Qt:从非GUI线程设置覆盖光标

时间:2011-07-18 17:40:57

标签: qt cursor

前段时间我写了一个小的RAII类来包装setOverrideCursor()上的restoreOverrideCursor()QApplication方法。构造此类将设置游标,析构函数将恢复它。由于覆盖光标是一个堆栈,因此非常有效,如:

{
   CursorSentry sentry;
   // code that takes some time to process
}

后来,我发现在某些情况下,处理代码有时会花费一段时间来处理(例如超过半秒),而其他时候它会接近瞬间(因为缓存)。之前很难确定哪种情况会发生,因此它仍然总是通过创建CursorSentry对象来设置等待光标。但这可能会导致一个令人不快的“闪烁”,光标会从等待光标快速转向正常光标。

所以我认为我很聪明,我添加了一个单独的线程来管理光标覆盖。现在,当创建CursorSentry时,它向光标线程发出请求以进入等待状态。当它被销毁时,它告诉线程返回正常状态。如果CursorSentry的寿命超过一定的时间(50毫秒),则处理光标更改并设置覆盖光标。否则,将丢弃更改请求。

问题是,游标线程在技术上无法更改游标,因为它不是GUI线程。在大多数情况下,它确实发生了工作,但有时候,如果我真的不走运,当GUI线程与其他一些X11调用混合在一起时,会发生更改光标的调用,并且整个应用程序都会死锁。这通常只有在GUI线程几乎在光标线程决定设置覆盖光标的确切时刻完成处理时才会发生。

那么,有没有人知道从非GUI线程设置覆盖光标的安全方法。请记住,大多数情况下,GUI线程将忙于处理内容(这就是为什么需要等待光标),所以我不能只将一个事件放入GUI线程队列,因为它赢了“要处理,直到为时已晚。另外,将我正在谈论的处理移动到一个单独的线程是不切实际的,因为这是在绘制事件期间发生的,并且它需要在完成时进行GUI工作(找出要绘制的内容)。

添加延迟来设置覆盖光标的任何其他想法都会很好。

1 个答案:

答案 0 :(得分:0)

我认为除了信号插槽连接进入GUI线程后跟qApp->processEvents()调用之外还有其他任何方式,但就像你说的那样,当GUI线程是这样时,这可能不会很好。捆绑。

QCoreApplication::processEvents的文档也有一些推荐的长事件处理用法:

  

此函数重载processEvents()。处理待处理事件   调用线程的maxtime毫秒或直到没有更多   要处理的事件,以较短者为准。

     

您可以调用此功能   偶尔当你编程忙于长时间操作时(例如   复制文件)。

     

调用此函数仅处理事件   调用线程。

如果可能的话,在paint事件中分解长调用,并定期检查它已经花了多长时间。在任何这些检查中,让它在GUI线程中设置覆盖光标。

QProgressBar通常可以很长时间地向用户传达相同的信息。

另一个可能有用的选项是将GUI线程外部渲染到QImage缓冲区,然后在完成后将其发布到GUI。