如何抑制警告 QPixmap: 在GUI线程外使用pixmaps不安全

3 投票
3 回答
7344 浏览
提问于 2025-04-18 10:14

我在终端上看到一堆错误信息,这让我根本没法调试。有没有办法让这个警告不再出现?这个错误只有在我在TableWidget里加了scrollToBottom()的时候才会出现。

3 个回答

0

如果你能提供一些实际的代码,那就更好了。

你看到这个问题的原因是因为你使用的线程类型和 QThreads 不一样。一般来说,这样做是不太推荐的,但也不是违法的。你需要注意三件事情:

  1. 所有的调用都应该在 QThreads 对象内部执行。
  2. 通过信号和槽机制传递的数据,确保没有指向非 QThread 所拥有对象的引用或指针。
  3. 在接收来自非 QThreads 调用的对象之间建立连接,发出信号时使用 Qt::QueuedConnectionQt::BlockingQueuedConnection 这两种连接类型。
0

你应该更好地设计你的代码,避免出现这个提示信息。如果你在一个线程中创建了图像,然后在GUI线程中使用它,这种做法可能现在有效,明天有效,或者永远有效……也可能根本不行。不要这样做。

你不能不改变Qt的源代码或安装消息处理程序就抑制这个警告的输出。

9

不想忽略这个警告,因为这不是警告,而是错误。Qt在这里太客气了。它应该是一个强制性检查,因为这个错误的出现说明你写的代码可能会破坏图形界面对象的数据,继续执行下去简直是自找麻烦。

不要直接从其他线程调用图形界面的方法,除非这些方法明确说明是线程安全的。

如果你需要跨线程调用,应该使用间接的、线程安全的方式:比如用QMetaObject::invokeMethod来调用QObject的槽函数和可调用的方法,或者使用一个代理QObject。如果你是从另一个线程更新图像,使用信号-槽机制或元调用机制在线程之间传递QImage实例是完全可以的。

有一个很简单的标准可以测试:如果一个QObject派生类的方法没有被记录为线程安全的,你就可以安全地认为这个对象是在当前线程中的:

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

并不重要这个方法看起来有多“无害”。比如TableWidget.scrollToBottom()会造成这么大的麻烦吗?会,也可能不会。即使在某个特定情况下它没有问题,你仍然是在依赖Qt的实现细节保持不变。你真的想去审查Qt的代码,确认这样做是否安全吗?不想。你的代码有bug,修复它就行了。这就是全部。

撰写回答