19

I have an application in which each thread (except the main thread) needs to create its own window. I tried creating a thread and then calling this->exec() in the run function. However, I get an error before I even get to that call: ASSERT failure in QWidget: "Widgets must be created in the GUI thread."

I want to popup a message window. The problem is that the source has multiple threads each of which may need to popup its own message.

chacham15
  • 13,719
  • 26
  • 104
  • 207
  • 3
    Don't attempt to show UI from the background/worker threads. Instead show that UI from the main GUI thread. Arrange for your background/worker to signal the GUI thread in order to get this done. This example shows how to do it: http://doc.qt.nokia.com/4.7-snapshot/thread-basics.html#example-3-clock. – David Heffernan Mar 19 '12 at 21:48

4 Answers4

24

If you need to create QWidget(or some other gui component(s)) in different(non-main) thread(s) you can implement it in such way:

  • Create simple wrapper which holds gui component:

    // 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;
      }
    };
    
  • create QApplication object in main thread

  • another thread body:

    ..
      // 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 ) );
    ..
    
  • be happy, :)

mortalis
  • 2,060
  • 24
  • 34
aleksey_m_t
  • 256
  • 2
  • 2
  • 2
    Hello I made some small improvement just for fun template class gui_launcher : public QObject { mygui *w; // other components 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 Dec 11 '12 at 12:44
7

Qt will only let you create GUI elements in the GUI thread - what is it that you need to display from the other threads? See something like This answer for an example of updating a progress bar with data from a non-GUI thread.

Update:

If you want to show a message for each window, you can have a class like this:

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 */
  }
};

Then connect it up to your GUI via the signal-slot mechanism with something like:

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

Where the showMessageBox function does what you need it to do.

Community
  • 1
  • 1
spbots
  • 1,513
  • 1
  • 15
  • 22
1

I don't believe this is possible. Other non-GUI components can run in other threads and will usually communicate via the signal/slot mechanisms.

Tom Kerr
  • 10,444
  • 2
  • 30
  • 46
0

The above answers can be combined with a QAction object (or custom class objects) to transfer any action to the main GUI thread to be executed, not just creating widgets or displaying a message box. (e.g. by emitting sendAction(QAction*), or implementing a custom QEvent class embodying a QAction*.)

Masood Khaari
  • 2,911
  • 2
  • 23
  • 40