无法在另一个线程中发送对象的发布事件 - Qt

Posted

技术标签:

【中文标题】无法在另一个线程中发送对象的发布事件 - Qt【英文标题】:Cannot send posted events for objects in another thread - Qt 【发布时间】:2016-06-15 15:50:46 【问题描述】:

我创建了一个 QThread 类来运行另一个类中的函数,但是这个另一个类有一个指向 QWidget (QwtPlot) 的指针,我是在应用程序输出中收到此消息:

QCoreApplication::sendPostedEvents: Cannot send posted events for objects in another thread

我已经在另一个主题中读到 QThreads 不适用于 QWidgets(UI 小部件必须在主线程中),但我的应用程序中的输出似乎是正确的。

谁能向我解释为什么会出现此消息?如果我让代码保持原样会发生什么?

注意:抱歉,我无法发布代码。

提前致谢

【问题讨论】:

你试过用Qt::QueuedConnection连接信号和槽吗?此外,您不应该使用指向 QWidget 的指针。使用插槽和信号在线程之间通信小部件(同样,没有指针)。见mandelbrot example 【参考方案1】:

我已经在另一个主题中读到 QThreads 不适用于 QWidgets [...] 但我的应用程序中的输出似乎是正确的。

不正确,否则你不会问,对吧?

QWidget 必须在主线程中。很可能是这样。但是您正在从另一个线程调用它的方法,并且您调用的方法不是线程安全的。不要那样做。还有其他方法可以跨线程安全地调用方法。改用它们。例如,假设你想调用QWidget::resize,你可以使用postToThread from this answer:

QWidget* widget;
QSize size;
Q_ASSERT_X(widget->thread() == qApp->thread(), "widget",
           "The widget must live in the main thread.");
postToThread([=] widget->resize(size); , widget);

如果您想要更详细,或者必须维护 Qt 4 代码库,您可以这样做:

class TSWidgetAdapter : public QObject 
  Q_OBJECT
  QWidget * widget() const  return qobject_cast<QWidget*>(parent()); 
  Q_SLOT void resize_d(const QSize & size)  widget()->resize(size); 
public:
  explicit TSWidgetAdapter(QWidget * parent) : QObject(parent) 
    Q_ASSERT_X(parent->thread() == qApp->thread(), "TSWidgetAdapter()",
              "The widget must live in the main thread.");
    connect(this, SIGNAL(resize(QSize)), this, SLOT(resize_d(QSize)));
  
  Q_SIGNAL void resize(const QSize & size);
;

QWidget* widget;
QSize size;
TSWidgetAdapter widget_ts(widget);
widget_ts.resize(size);

_d 插槽在小部件的线程中被调用。这就是自动连接的美妙之处:你可以在任何线程中调用信号,而槽只会在目标对象的线程中被调用。由于适配器是小部件的子级,它位于小部件的线程中 - 这是由 Qt 强制执行的。

【讨论】:

以上是关于无法在另一个线程中发送对象的发布事件 - Qt的主要内容,如果未能解决你的问题,请参考以下文章

Qt - 由 qt 对象发送的信号调用由接收器对象覆盖的事件函数

Qt:在另一个线程中预加载 qpixmap?

Qt:将事件发布到 QThread 的正确方法?

BOOST 如何在一个线程中发送信号并在另一个线程中执行相应的插槽?

如何在另一个 Qt 线程上运行它?

将异步任务发送到在其他线程中运行的循环