Qt部分解决技巧

记录和分享

部分小技巧

Qt  Creator自动补全快捷键

在Qt官方默认设置中,自动补全快捷键(complete)为Ctrl + 空格。而在各大主流UI系统中,Ctrl + 空格均被设置为切换输入法的存在, 因此会形成冲突。可以根据以下设置:

  • Qt Creator Version <= 6.0.0:
    上方菜单栏 - 工具 - 外部 - 配置 - 环境 - 键盘 - 过滤器输入complete
  • Qt Creator Version > 6.0.0:
    上方菜单栏 - 选项 - 环境 - 键盘 - 过滤器输入complete
    我个人习惯使用Ctrl + Alt + 空格

定时器

在Qt中定时器是个好东西,在很多情况下,使用定时器异步调用函数,就可以完成意想不到的操作。

  • singleShot
    singleShot是QTimer类方法中的一个静态函数,在你需要一次单一的启用定时器的时候,你就需要这个函数了。对比定时器来说,它不需要开辟一个QTimer。因为本身是一个异步操作,所以也不会阻塞主线程。
    1
    2
    3
    4
    5
    6
    7
    8
    
    //延时10毫秒执行update函数
    QTimer::singleShot(10, this, SLOT(update()));
    
    //定时器lambda表达式方式
    QTimer::singleShot(10, [&]() 
    {
      load();
    });
    
  • invokeMethod
    invokeMethod是QMetaObject类中的一个静态函数,它可以让你需要跨线程执行方法或在不直接访问对象方法的情况下非常有用。需要注意的是,调用的对象必须是被Q_OBJECT宏修饰过的类,也就是父类必须继承于QObject且使用Q_OBJECT修饰
    1
    2
    
    //异步执行load函数
    QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
    
    从以上代码来看,最值得解释的是第三个参数。
    • 如果是Qt::DirectConnection,则会立即调用该成员函数。
    • 如果是Qt::QueuedConnection,则会发送一个QEvent,并在应用程序进入主事件循环后立即调用该成员函数。
    • 如果是Qt::BlockingQueuedConnection,则将以与Qt::QueuedConnection相同的方式调用该方法,除了当前线程将阻塞直到事件被传递。使用此连接类型在同一线程中的对象之间进行通信将导致死锁。
    • 如果是Qt::AutoConnection,则如果obj与调用者位于同一个线程中,则会同步调用该成员; 否则它将异步调用该成员。

processEvents

processEvents函数是QCoreApplication类中的一个静态函数,它允许Qt的事件循环在代码的当前执行点暂时接管控制权,处理所有等待中的事件。这在长时间运行的任务或等待操作中特别有用,因为它可以防止应用程序界面冻结,使用户界面保持响应。

官方对他的解释为:(Qt 6.7.2官方文档)
Calling this function processes events only for the calling thread, and returns after all available events have been processed. Available events are events queued before the function call. This means that events that are posted while the function runs will be queued until a later round of event processing.
调用此函数仅处理调用线程的事件,并在处理完所有可用事件后返回。可用事件是在函数调用之前排队的事件。这意味着在函数运行时发布的事件将排队,直到下一轮事件处理。

注意: 调用此函数时,线程切换去处理事件时,之前正在做的操作就被阻塞了,直到待处理事件完成。 我们可以根据以下代码查看processEvents完整函数:

processEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents);

  • flags 参数是一个位掩码,用于指定哪些类型的事件应该被处理。默认情况下,QEventLoop::AllEvents 会处理所有类型的事件。但是,你可以指定其他标志来限制处理的事件类型,比如只处理定时器事件(QEventLoop::DeferredDeletion 和 QEventLoop::TimerEvent)或只处理用户输入事件(如鼠标和键盘事件)。

processEvents(QEventLoop::ProcessEventsFlags flags, int ms)

对比上一个函数,这个重载函数多一个毫秒级参数。这个参数来自官方的说法为:
Processes pending events for the calling thread for ms milliseconds or until there are no more events to process, whichever is shorter.
处理调用线程的挂起_事件毫秒_或直到没有更多事件要处理,以较短者为准。

This is equivalent to calling: processEvents(flags, QDeadlineTimer(ms));
这相当于调用:processEvents(flags, QDeadlineTimer(ms));

processEvents(QEventLoop::ProcessEventsFlags flags, QDeadlineTimer deadline);

TODO

QTableWidget

  • QTableWidget刷新残留(此特性于高版本已经修复,个人遇到版本为Qt <= 5.6.3)
    当删除QTableWidget更新最后一行的时候,会造成行数异常残留。目测是因为使用样式表设置行高又使用horizontalHeader()->setDefaultSectionSize()设置行高导致的问题。
    解决办法也很简单,使用resizeRowsToContents()让Qt自动调整行高。这个函数的原理也是按照字所占的像素进行计算,故这个是很占后续代码执行的效率。推荐使用以下方式:
    1
    2
    3
    4
    
    //异步执行resizeRowsToContents函数
    QMetaObject::invokeMethod(this, "resizeRowsToContents",Qt::QueuedConnection);
    //延时10毫秒执行resizeRowsToContents函数
    QTimer::singleShot(10, this, SLOT(resizeRowsToContents()));
    
Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计