Search code examples
c++multithreadingqtqthread

Affecting a QDialog From A QThread


I would like to affect a QDialog from a separate thread, I have to do two things:

dialog->show();
dialog->raise();
dialog->activateWindow();

As far as I understand, these are events and thus MUST be done in the main thread event loop. I think I achieve this with QApplication::postEvent within in the QThread::run(). Could anyone confirm?

Second, I would like to display an image which was processed in that separate thread. I think I need to subclass my dialog class and write a thread safe setImage() function, which is then called by paintEvent()... However, this seems like it's impossible. I can't block the paintEvent with a QMutex::unlock()? Could anyone offer some suggestions?


QApplication::postEvent(dialog, new QShowEvent()); did not work.

This is the solution for calling slots (as functions) from a seperate thread:

QMetaObject::invokeMethod(dialog, "show", Qt::QueuedConnection);
QMetaObject::invokeMethod(dialog, "raise", Qt::QueuedConnection);

... Still working on activateWindow() and QThread safe functions.

So for the QImage, it is a QPaintDevice. Supposedly it is thread safe. My approach would've been to have a class member QImage that is set within the thread. Then painted later.

Note, that the below approach is as good, if not better though.


Solution

  • I think this is a clearer way to do what you want:

    class Dialog : public QDialog
    {
        ...
    public slots:
        void showImage(QImage img);
        ...
    }
    
    void Dialog::showImage(QImage img);
    {
        setImage(img);
        show();
        raise();
        activateWindow();
    }
    
    class Thread : public QThread
    {
        ...
    signals:
        void imageReady(QImage);
    }
    
    void Thread::run()
    {
        QImage img;
        /// image processing stuff
    
        emit imageReady(img);
        ...
    }
    
    
    Thread *thread = new Thread;
    Dialog *dialog = new Dialog;
    connect(thread, SIGNAL(imageReady(QImage)), dialog, SLOT(showImage(QImage)));
    
    thread->start();