无法为另一个帖子中的对象发送已发布的事件 - Qt

时间:2016-06-15 15:50:47

标签: c++ qt qwidget qthread

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

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

我已经读过QThreads不能使用QWidgets的其他主题(UI小部件必须在主线程中),但我的应用程序中的输出似乎是正确的。

有人可以向我解释为什么会出现此消息吗?如果我按原样使用代码会发生什么?

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

提前致谢

1 个答案:

答案 0 :(得分:5)

  

我已经阅读过另一个QThreads不能与QWidgets一起使用的主题[...]   但是我的应用程序中的输出似乎是正确的。

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

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

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强制执行。