Question

Let's say that you've created a new thread that then calls a static function after it has been started. Within that static function you need to create and display a custom qdialog. How can you create it so that it has no parent and is located in the proper thread?

The constructor sets the parent to 0 but it still reports an error about being unable to create children for a parent in a different thread. Since it's a static function I can't use the "this" object and without "this" I can't retrieve the current thread or thread id. I thought I might be able to call myCustomDialog->moveToThread() but I have no idea how to determine the correct thread from a static function.

If I use one of the QMessageBox static functions everything works fine. For example, calling QMessageBox::information(0, tr("Title"), tr("Message")) doesn't report any errors. How can I code my custom qdialog to function similar to the qmessagebox static function?

Is there any way to retrieve a list of all running threads from the qApp object? Any other suggestions?

static int myFunction();

int myObject::myFunction()
{
    myCustomDialog *mcd = new myCustomDialog();
    // as soon as I call exec() it reports an error and crashes
    mcd->exec();
    // QObject: Cannot create children for a parent that is in a different thread.

    // can't call mcd->moveToThread() without knowing the current thread
    // how can I determine the current thread from this static function?
    // if parent = 0 then why is this error occurring?
    return 0;
}

myCustomDialog(QWidget *parent = 0);

myCustomDialog::myCustomDialog(QWidget *parent) : QDialog(parent)
{
    // create widgets and layout here
}
Was it helpful?

Solution 2

Sample... You may adapt it to make calls from static functions, but I don't think that it is necesary. It is good practice to work with threads in next way: You should create your dialog in GUI thread and connect it's exec() slot to your signal with Qt::BlockingQueuedConnection

Worker.h

#include <QObject>

class Worker
    : public QObject
{
    Q_OBJECT

signals:
    void showDialog();

public:
    Worker( QObject *parent = NULL );
    ~Worker();

public slots:
    void doLongWork();

private:
};

Worker.cpp

#include <QThread>
#include <QMessageBox>
#include <QDebug>
#include <QCoreApplication>

#include <Windows.h>


Worker::Worker( QObject *parent )
    : QObject( parent )
{
}

Worker::~Worker()
{
}

void Worker::doLongWork() // You may override QThread::run with same effect, but it is bad practice
{
    qDebug() << "Worker thread id = " << QThread::currentThreadId();
    ::MessageBoxA( NULL, "Click to show dialog in 3 seconds", NULL, 0 );
    ::Sleep( 3000 );
    emit showDialog();  // "Showing" dialog from non-GUI thread. And wait for close
    ::MessageBoxA( NULL, "Dialog closed!", NULL, 0 );
    qApp->quit();
}

main.cpp

#include <QApplication>
#include <QDialog>
#include <QThread>
#include <QDebug>

#include "Worker.h"


int main(int argc, char *argv[])
{
    QApplication a( argc, argv );
    a.setQuitOnLastWindowClosed( false );

    QDialog dlg;
    QThread workerThread;
    Worker worker;

    qDebug() << "Main thread id = " << QThread::currentThreadId();

    QObject::connect( &workerThread, SIGNAL( started() ), &worker, SLOT( doLongWork() ) );
    QObject::connect( &worker, SIGNAL( showDialog() ), &dlg, SLOT( exec() ), Qt::BlockingQueuedConnection ); // !!!See connection type!!!

    worker.moveToThread( &workerThread );
    workerThread.start();

    return a.exec();
}

Note: WinAPI MessageBoxes are used only to visualize that thread is really waiting for close of dialog.

OTHER TIPS

Don't. Creating QWidget objects from another thread is a bad idea. The Documentation states:

In GUI applications, the main thread is also called the GUI thread because it's the only thread that is allowed to perform GUI-related operations.

The way I normally get around this is to emit a signal from my object in the non-GUI thread that's connected to an object living in the main thread (often MainWindow for me). The receiving object then creates the dialog on the main thread.

As mentioned in the other answer, this connection can block your worker thread if needed by establishing the connection type as Qt::BlockingQueuedConnection.

For more information on invoking functions from other threads, see this post.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top