如何在不同的QT线程中创建窗口?

19

我有一个程序,在该程序中,除了主线程外的每个线程都需要创建自己的窗口。我尝试创建一个线程,然后在run函数中调用this->exec()。然而,在我甚至没有到达该调用前就出现了错误:ASSERT failure in QWidget: "Widgets must be created in the GUI thread."

我想弹出一个消息窗口。问题是源代码有多个线程,每个线程都可能需要弹出自己的消息。


3
不要在后台/工作线程中尝试显示用户界面(UI)。相反,应该从主GUI线程中显示UI。安排你的后台/工作线程发信号给GUI线程以完成此操作。这个例子展示了如何实现:http://doc.qt.nokia.com/4.7-snapshot/thread-basics.html#example-3-clock。 - David Heffernan
4个回答

24

如果您需要在不同(非主)线程中创建QWidget(或其他GUI组件),可以按照以下方式实现:

  • 创建一个简单的包装器来保存GUI组件:

    // gui component holder which will be moved to main thread
    class gui_launcher : public QObject
    {
      QWidget *w;
      // other components
      //..
    public:
      virtual bool event( QEvent *ev )
      {   
        if( ev->type() == QEvent::User )
        {
          w = new QWidget;
          w->show();
          return true;
        }
        return false;
      }
    };
    
  • 在主线程中创建QApplication对象

  • 另一个线程的代码体:

  • ..
      // create holder
      gui_launcher gl;
      // move it to main thread
      gl.moveToThread( QApplication::instance()->thread() );
      // send it event which will be posted from main thread
      QCoreApplication::postEvent( &gl, new QEvent( QEvent::User ) );
    ..
    
  • 保持快乐, :)


2
你好,我只是为了好玩做了一些小改进。template<typename mygui> class gui_launcher : public QObject { mygui *w; // 其他组件public: void add2Gui() { this->moveToThread( QApplication::instance()->thread() ); QCoreApplication::postEvent( this, new QEvent( QEvent::User ) ); } virtual bool event( QEvent *ev ) {
if( ev->type() == QEvent::User ) { w = new mygui; w->show(); return true; } return false; } };
- jamk

7

Qt只允许在GUI线程中创建GUI元素 - 您需要从其他线程显示什么内容?请参考此答案,了解如何使用来自非GUI线程的数据更新进度条的示例。

更新:

如果您想要为每个窗口显示一条消息,您可以拥有这样的一个类:

class MyWorkerThread : public QThread
{
  Q_OBJECT
signals:
  void sendMessage(QString msg);
private:
  void run()
  {
    /* do stuff */
    emit sendMessage(QString("This thread is doing stuff!"));
    /* do more stuff */
  }
};

然后,通过信号槽机制将其连接到您的 GUI 上,例如:

connect(workerThread, SIGNAL(sendMessage(QString)),
        guiController, SLOT(showMessageBox(QString)));

showMessageBox函数可以实现您所需的功能。


抱歉让您等待了,我正在测试您的答案。 - chacham15
这是一个从QThread中调用QMessageBox的完整示例。它与您的示例非常相似。 https://dev59.com/smAg5IYBdhLWcg3wFHqF#23992291 - phyatt

1

我不相信这是可能的。其他非GUI组件可以在其他线程中运行,并通常通过信号/槽机制进行通信。


0
以上答案可以与QAction对象(或自定义类对象)结合使用,以传输任何操作到主GUI线程以执行,不仅仅是创建小部件或显示消息框。(例如通过发射sendAction(QAction*),或实现一个包含QAction*的自定义QEvent类。)

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