如何抑制警告QPixmap:在GUI线程之外使用像素图不安全

3

我遇到一个问题,终端窗口一直输出这个错误信息,导致我无法进行调试。请问有没有方法可以消除这个警告?我只在 TableWidget 上使用 scrollToBottom() 方法时才会出现这个错误。

3个回答

9

请不要忽略那个警告,因为它并不仅是一个警告,而是一个错误。Qt在这里过于礼貌了。应该使用硬断言(hard assertion),因为其存在表明您编写的代码很可能会破坏GUI对象的数据,并且在此之后继续执行是愚蠢之举。

除非明确说明这些方法是线程安全的,否则永远不要直接从其他线程调用GUI方法。

如果需要进行跨线程调用,请使用间接的、线程安全的方式:QObject上的QMetaObject::invokeMethod用于信号槽或调用方法,或使用代理QObject。如果需要在另一个线程更新图像,则使用信号槽或元调用机制传递QImage实例。

有一个非常简单的标准可以测试:如果QObject派生类的方法没有被记录为线程安全,那么可以安全地断言该对象在当前线程中存在:

Q_ASSERT(widget->thread() == QThread::currentThread());
widget->scrollToBottom();

无论看起来多么“无害”,方法是什么并不重要。 TableWidget.scrollToBottom() 是否会造成很大的麻烦? 是的。或者也可能不会。即使在特定情况下它没有问题,您仍然需要依赖于Qt的实现细节保持不变。您真的想审核Qt代码以确定它是安全的还是不安全的吗? 不。您的代码有一个错误。修复它。就这样。


明白。TableWidget.scrollToBottom() 会引起这么多麻烦吗?我知道要将其从当前位置移除,只是想确保我和其他像我一样(新手使用 Qt)的人完全理解正在发生的事情。 - sudobangbang
在大多数情况下,如果一个Qt类可以安全地在不同的线程中使用,在文档中会说明此类中的所有函数都是可重入的或类似的内容。例如,在QImage文档中已经说明了,因此可以在不同的线程中使用该类。您应该阅读有关Qt中的线程基础知识可重入性和线程安全性的内容。 - thuga
补充一下thuga所说的,即使一个类是可重入的,也不意味着该类的实例(对象)是可重入的。可重入类可以用于在多个线程中创建对象,但这些对象不一定在线程之间共享。 - three_pineapples
@three_pineapples 是的,当处理共享数据时,可以从多个线程安全访问的函数被标记为“线程安全”。例如,QMutex的所有函数。这在文档中有很好的解释。 - thuga

0

你最好设计好你的代码,避免显示这个消息。如果你在另一个线程中创建了pixmap并在GUI线程中“使用”,那么它可能现在、明天或永远可以工作...或者不行。别这样做。

你无法在不更改Qt源代码或安装消息处理程序的情况下抑制此警告的输出。


我找出了导致错误的原因,但现在我有点进退两难。为了确保我的TableWidget可以动态处理数据(实时更新),它必须不断检查新数据。所以,我别无选择,只能将其链接到一个线程。我将尝试一些不同的scrollToBottom()放置方式,并报告结果。 - sudobangbang

0

如果您提供了一些实际的代码,那将会更好。

您看到这个问题的原因是您正在使用与 QThreads 不同类型的线程。一般来说,这并不可取,但也不是非法的。有三件事情需要注意:

  1. 所有调用都应该从 QThreads 对象内部的调用中结束执行
  2. 通过信号槽机制传递的所有数据都应该被设置为没有引用/指向非 QThread 拥有的对象的指针。
  3. 建立连接,使得从非 QThreads 接收调用的对象发出信号,并使用 Qt::QueuedConnectionQt::BlockingQueuedConnection 连接类型接收信号。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接