Qt connect two signals together using QueuedConnection - qt

Qt documentation states that it is possible to connect two signals together:
It is even possible to connect a signal directly to another signal.
I tried:
connect(x, SIGNAL(S()), y, SIGNAL(func()));
and it works as mentioned, but Qt documentation continues:
(This will emit the second signal immediately whenever the first is emitted.)
Does this mean that QueuedConnection will not work correctly? Can I connect two signals across threads?
The reason I am asking this is because I solved a class of crashes on an application by avoiding this, but I am not sure if this was related to connecting signals together.

It shouldn't be a great deal different from a signal/slot connection. Let's take a look at underlying mechanism of signals/slots. There is an event queue in each thread which maintains signals (events) that have been emitted but not processed yet. So whenever the execution returns to the event loop the queue is processed. Event loop itself doesn't handle the events. Rather it delivers them to the objects so they can handle it. In this special case, I suppose that the object would emit another signal which would be inserted in the queue. When the execution returns to event loop the new signal is handled by the object again. Here is a test which proves the above argument.
If you run the codes attached, the output would be:
before signal()
after signal()
slot() called
which means defining a signal-signal connection type as queued between threads have the expected queued behaviour, that rejects the argument which it is always immediate. If you define it as direct, the output would be:
before signal()
slot() called
after signal()
as expected. it doesn't generate any errors or warnings, and program doesn't crash as well.Yet this simple example doesn't prove it works for a large and complex one as well.
main.cpp:
#include <QtGui/QApplication>
#include "dialog.h"
#include "testssconnection.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TestSignalSignalConnection * t = new TestSignalSignalConnection();
t->start();
return a.exec();
}
testssconnection.h:
#ifndef TESTSSCONNECTION_H
#define TESTSSCONNECTION_H
#include <QObject>
#include <QThread>
class TestSignalSignalConnection : public QThread
{
Q_OBJECT
public:
explicit TestSignalSignalConnection(QObject *parent = 0);
void run();
signals:
void signal1();
void signal2();
public slots:
void slot();
};
#endif // TESTSSCONNECTION_H
testssconnection.cpp:
#include "testssconnection.h"
#include <QtCore>
TestSignalSignalConnection::TestSignalSignalConnection(QObject *parent) :
QThread(parent)
{
}
void TestSignalSignalConnection::run()
{
TestSignalSignalConnection *t = new TestSignalSignalConnection();
this->connect(this,SIGNAL(signal1()),t,SIGNAL(signal2()), Qt::QueuedConnection);
t->connect(t,SIGNAL(signal2()), t,SLOT(slot()), Qt::DirectConnection);
qDebug() << "before signal()";
emit signal1();
qDebug() << "after signal()";
exec();
}
void TestSignalSignalConnection::slot()
{
qDebug() << "slot() called";
}

Take a look at qt-project, its a great wiki page about Threads and signals.
Threads, Events and QObjects::Signals and slots across threads

Related

Qt: using QWidgets in non GUI threads

I'm trying to understand what is and isn't allowed when it comes to QWidget and Qt concurrency. I've created a Widget which has a slow_function and I'm considering three cases:
Run the slow_function on the GUI thread. This results in the expected behaviour; the GUI becomes unresponsive while waiting for the function to return.
Use QtConcurrent::run(this, &Widget::slow_function). I was surprised to see that this didn't block the GUI. I've confirmed that the thread affinity of my instance is still the GUI thread, nevertheless, the function seems to be executing on a separate thread. Is such an approach allowed and is this the expected behaviour (documentation link would be really helpful)? Is such an approach safe if I can guarantee that slow_function is thread-safe?
Create a subclass of QThread which holds a pointer to my widget. Override the run method to call slow_function. The behaviour is the same as Case 2. This is also surprising as the thread affinity is still the GUI thread (besides, we are not even allowed to use moveToThread on a QWidget). Why is this running on a separate thread? Is moveToThread meant to be useful only when we are interested in calling slots via signals sent from another thread?
Thank you for reading. Here is the relevant code starting with my the header file:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QDebug>
#include <QPushButton>
#include <QLayout>
#include <windows.h>
#include <QtConcurrent/QtConcurrent>
#include <QThread>
#include <QApplication>
class Widget;
class Thread: public QThread
{
public:
Thread(Widget* widget)
: m_widget(widget){}
protected:
void run() override;
private:
Widget* m_widget;
};
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget* parent = nullptr)
: QWidget(parent)
, m_thread(this){
auto layout = new QVBoxLayout(this);
auto button = new QPushButton("Case 1: Run on gui thread");
auto button2 = new QPushButton("Case 2: Run with qtconcurrent");
auto button3 = new QPushButton("Case 3: Run with qthread");
connect(button, &QPushButton::clicked, this, &Widget::slow_function);
connect(button2, &QPushButton::clicked, this, &Widget::use_concurrent);
connect(button3, &QPushButton::clicked, this, &Widget::use_qthread);
layout->addWidget(button);
layout->addWidget(button2);
layout->addWidget(button3);
}
~Widget()
{
m_thread.quit();
m_thread.wait();
}
public slots:
void slow_function()
{
qDebug() << "Starting";
auto gui_thread = QApplication::instance()->thread();
auto this_thread = thread();
qDebug() << "Thread affinity is" << (gui_thread == this_thread ? "gui_thread" : "non_gui_thread");
Sleep(5000);
qDebug() << "Finished";
}
void use_concurrent()
{
QtConcurrent::run(this, &Widget::slow_function);
}
void use_qthread()
{
m_thread.start();
}
private:
Thread m_thread;
};
#endif // WIDGET_H
and the main.cpp file:
#include "widget.h"
#include <QApplication>
void Thread::run()
{
m_widget->slow_function();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
You should not do any UI things in nonmain threads. The UI means
widget interaction
model
Run the slow_function on the GUI thread
That's not allowed, nothing should block the GUI thread.
Is such an approach safe if I can guarantee that slow_function is thread-safe?
It's okay to run slow function in a different thread. But...
what happens when the user closes the application, but the function still executes?
I have done this, but I prefer to encapsulate it in a separate class.
Create a subclass of QThread which holds a pointer to my widget.
You should only subclass QThread if the subclass is a thread. Like, subclassing an animal class will give you an animal, not a chair with four legs.
Is moveToThread meant to be useful only when we are interested in calling slots via signals sent from another thread?
moveToThread changes the affinity of the object. So, slots are always executed in the correct thread, when you call invokeMethod, the method is executed in the correct thread. When an event is delivered, the event handler is always called in the appropriate thread.
The whole purpose of QtConcurrent::run() is to make running heavy workloads in a thread easier. If your use-case allows for it, great!
Pair it with a QFutureWatcher to retrieve the result after your slow_function is finished.
Using QThread is another option, but it makes more sense when you have a long-lived object. Instead of subclassing, I find it easier to use the worker model: create a worker class with signals/slots, call moveToThread on it with a vanilla QThread object, connect/subscribe, start the thread
QWidget is a way to create GUI functionality in Qt. While it may be possible to use such objects in non-gui threads, it's best you separate your compute workloads from GUI (don't put your slow_function into widget classes).

When is it mandatory to call qRegisterMetaType()?

I have studied the qt documentation of qRegisterMetaType() where it says that this function must be called before the corresponding type can be used in signal/slot mechanism. However I couldn't find any code example where this has to be done by hand.
This page states, that the registration is done automatically by the moc if it can determine that the type may be registered as meta-type. It looks like this is right, because I tested QSignalSpy, QObject::connect() (direct and queued connection) and QVariant - with just using Q_DECLARE_METATYPE(type) and none of them needed a explicit call to qRegisterMetaType to work.
So my question is: when do I have to call qRegisterMetaType(), because otherwise the code won't work?
The Qt docs say that Q_DECLARE_METATYPE is necessary in case one has a connect being a queued connection.
Adding a Q_DECLARE_METATYPE() makes the type known to all template
based functions, including QVariant. Note that if you intend to use
the type in queued signal and slot connections or in QObject's
property system, you also have to call qRegisterMetaType() since the
names are resolved at runtime.
For this I build a small testing app, that exemplifies the behavior.
Just try to remove the Q_DECLARE_METATYPE(Message) and watch the warnings and output change. In case of the normal connect the macro seems to be unnecessary.
main.cpp
#include <QApplication>
#include <QThread>
#include "MyHeaderView.h"
Q_DECLARE_METATYPE(Message);
int main(int argc, char **args)
{
QApplication app(argc, args);
{
TestObject sender;
TestObject receiver;
QObject::connect(&sender, &TestObject::sendMessage, &receiver, &TestObject::onMessage);
sender.emitMessage(1, 2);
}
// This requires Q_DECLARE_METATYPE(Message);
QThread workerThread;
TestObject sender2;
TestObject receiver2;
receiver2.moveToThread(&workerThread);
workerThread.start();
QObject::connect(&sender2, &TestObject::sendMessage, &receiver2, &TestObject::onMessage, Qt::ConnectionType::QueuedConnection);
sender2.emitMessage(3, 4);
app.exec();
}
TestObject.h
#pragma once
#include <QObject>
#include <QDebug>
struct Message
{
int x;
int y;
};
class TestObject : public QObject
{
Q_OBJECT
public:
void emitMessage(int x, int y) { emit sendMessage(Message{ x,y }); }
signals:
void sendMessage(const Message&);
public slots:
void onMessage(const Message& m) { qDebug() << m.x << m.y; }
};

In a Qt console application, why is a QTimer required for the code to exit properly?

I've wrote this code looking at examples online of how I'm supposed to run a console program that doesn't just run and quit and one that does. Based on a Qt console application. This one here, I wanted it to quit. I've understood pretty much everthing excepth the QTimer::singleShot line. If the line is commented out, the application will run but will not quit. If it is left, the application will run and quit as expected. Can anyone explain to me why?
dostuff.h
#ifndef DOSTUFF_H
#define DOSTUFF_H
#include <QObject>
#include <iostream>
class DoStuff: public QObject
{
Q_OBJECT
public :
DoStuff(QObject *parent = 0);
public slots:
void run();
signals:
void finished();
};
#endif // DOSTUFF_H
And the implementation dostuff.cpp
#include "dostuff.h"
DoStuff::DoStuff(QObject *parent):QObject(parent)
{
}
void DoStuff::run(){
for (int i = 0; i < 10000; i++){
std::cout << "Processing " << i << std::endl;
}
emit(finished());
}
My main.cpp
#include <QCoreApplication>
#include <QTimer>
#include "dostuff.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
DoStuff *dostuff = new DoStuff(&a);
QObject::connect(dostuff,SIGNAL(finished()),&a,SLOT(quit()));
dostuff->run();
// WHY THIS??
QTimer::singleShot(10,dostuff,SLOT(run()));
return a.exec();
}
QTimer is not required to exit properly; You just need to provide a way to get your application to break the event loop at some point. In GUI application, Qt does that automatically when the last window is closed.
In Console applications, you can:
Either run your application without an event loop (if you have a straight-forward simple control flow in your application).
Or (if you require an event loop to handle some events or cross thread signal/slots) you need to have some event that makes your application break the event loop and quit. This event should only be triggered when the application has finished its job.
The code sample you have in your question is really simple, and does not require an event loop to run properly. The only effect the QTimer has in your code is that it delays execution for 10 ms. Here is the same code sample without running an event loop:
#include <QtCore>
class DoStuff: public QObject
{
Q_OBJECT
public :
DoStuff(QObject *parent = 0) : QObject(parent) {}
public slots:
void run() {
for (int i = 0; i < 10000; i++){
qInfo() << "Processing " << i;
}
emit finished();
}
signals:
void finished();
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
DoStuff dostuff;
QObject::connect(&dostuff, &DoStuff::finished,
&a, &QCoreApplication::quit);
dostuff.run();
return 0; //no event loop required
}
#include "main.moc"
If you start an event loop, you may notice that the quit slot does not work when not using QTimer::singleShot. The reason for this is that quit is called before the event loop is even started (and the call has no effect at all). That's why according to the docs, it is recommended to connect to quit using a queued connection:
It's good practice to always connect signals to this slot using a QueuedConnection. If a signal connected (non-queued) to this slot is emitted before control enters the main event loop (such as before "int main" calls exec()), the slot has no effect and the application never exits. Using a queued connection ensures that the slot will not be invoked until after control enters the main event loop.
So, if you want to have an event loop in your code above, you just need to connect using a Qt::QueuedConnection:
#include <QtCore>
class DoStuff: public QObject
{
Q_OBJECT
public :
DoStuff(QObject *parent = 0) : QObject(parent) {}
public slots:
void run() {
for (int i = 0; i < 10000; i++){
qInfo() << "Processing " << i;
}
emit finished();
}
signals:
void finished();
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
DoStuff dostuff;
QObject::connect(&dostuff, &DoStuff::finished,
&a, &QCoreApplication::quit,
Qt::QueuedConnection);
// ^^^^^^^^^^^^^^^^
// use a queued connection
dostuff.run();
return a.exec(); //start an event loop
}
#include "main.moc"
Timer is needed to postpone execution. Since you want to have a running event loop, a.exec() has to be called, then the timer executes your code. When your code finishes running, it triggers finished signal, that is tied to QCoreApplication::quit - that's the needed exit for event loop running inside a.exec().
Btw, you have to remove: dostuff->run(); from your code.

Using POSIX threads in Qt Widget App

I'm relatively new to both Qt and pthreads, but I'm trying to use a pthread to work in the background of basic test app I'm making. I'm aware of the Qt Frameworks own threading framework - but there's a lot of complaint surrounding it so I'd like to use pthread if possible. The code is as below
#include "drawwindow.h"
#include "ui_drawwindow.h"
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include "QThread"
pthread_t th1;
DrawWindow::DrawWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::DrawWindow)
{
ui->setupUi(this);
}
DrawWindow::~DrawWindow()
{
delete ui;
}
void DrawWindow::on_pushButton_clicked()
{
pthread_create(&th1, NULL, &DrawWindow::alter_text, NULL);
}
void DrawWindow::alter_text()
{
while(1)
{
ui->pushButton->setText("1");
QThread::sleep(1);
ui->pushButton->setText("one");
QThread::sleep(1);
}
}
With the header
#ifndef DRAWWINDOW_H
#define DRAWWINDOW_H
#include <QMainWindow>
namespace Ui {
class DrawWindow;
}
class DrawWindow : public QMainWindow
{
Q_OBJECT
public:
explicit DrawWindow(QWidget *parent = 0);
~DrawWindow();
void alter_text();
private slots:
void on_pushButton_clicked();
private:
Ui::DrawWindow *ui;
};
#endif // DRAWWINDOW_H
And I'm getting the error
error: cannot convert 'void (DrawWindow::*)()' to 'void* (*)(void*)' for argument '3' to 'int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)'
pthread_create(&th1, NULL, &DrawWindow::alter_text, NULL);
^
Does anyone know what is wrong?
TL;DR: The way you're using pthreads is precisely the discouraged way of using QThread. Just because you use a different api doesn't mean that what you're doing is OK.
There's absolutely no problem with either QThread or std::thread. Forget about pthreads: they are not portable, their API is C and thus abhorrent from a C++ programmer's perspective, and you'll be making your life miserable for no reason by sticking to pthreads.
Your real issue is that you've not understood the concerns with QThread. There are two:
Neither QThread nor std::thread are destructible at all times. Good C++ design mandates that classes are destructible at any time.
You cannot destruct a running QThread nor std::thread. You must first ensure that it's stopped, by calling, respectively QThread::wait() or std::thread::join(). It wouldn't have been a big stretch to have their destructors do that, and also stop the event loop in case of QThread.
Way too often, people use QThread by reimplementing the run method, or they use std::thread by running a functor on it. This is, of course, precisely how you use pthreads: you run some function in a dedicated thread. The way you're using pthreads is just as bad as the discouraged way of using QThread!
There are many ways of doing multithreading in Qt, and you should understand the pros and cons of each of them.
Thus, how do you do threading in C++/Qt?
First, keep in mind that threads are expensive resources, and you should ideally have no more threads in your application than the number of available CPU cores. There are some situations when you're forced to have more threads, but we'll discuss when it's the case.
Use a QThread without subclassing it. The default implementation of run() simply spins an event loop that allows the objects to run their timers and receive events and queued slot calls. Start the thread, then move some QObject instances to it. The instances will run in that thread, and can do whatever work they need done, away from the main thread. Of course, everything that the objects do should be short, run-to-completion code that doesn't block the thread.
The downside of this method is that you're unlikely to exploit all the cores in the system, as the number of threads is fixed. For any given system, you might have exactly as many as needed, but more likely you'll have too few or too many. You also have no control over how busy the threads are. Ideally, they should all be "equally" busy.
Use QtConcurrent::run. This is similar to Apple's GCD. There is a global QThreadPool. When you run a functor, one thread from the pool will be woken up and will execute the functor. The number of threads in the pool is limited to the number of cores available on the system. Using more threads than that will decrease performance.
The functors you pass to run will do self-contained tasks that would otherwise block the GUI leading to usability problems. For example, use it to load or save an image, perform a chunk of computations, etc.
Suppose you wish to have a responsible GUI that loads a multitude of images. A Loader class could do the job without blocking the GUI.
class Loader : public QObject {
Q_OBJECT
public:
Q_SIGNAL void hasImage(const QImage &, const QString & path);
explicit Loader(const QStringList & imagePaths, QObject * parent = 0) :
QObject(parent) {
QtConcurrent::map(imagePaths, [this](const QString & path){
QImage image;
image.load(path);
emit hasImage(image, path);
});
}
};
If you wish to run a short-lived QObject in a thread from the thread pool, the functor can spin the event loop as follows:
auto foo = QSharedPointer<Object>(new Object); // Object inherits QObject
foo->moveToThread(0); // prepares the object to be moved to any thread
QtConcurrent::run([foo]{
foo->moveToThread(QThread::currentThread());
QEventLoop loop;
QObject::connect(foo, &Object::finished, &loop, &QEventLoop::quit);
loop.exec();
});
This should only be done when the object is not expected to take long to finish what it's doing. It should not use timers, for example, since as long as the object is not done, it occupies an entire thread from the pool.
Use a dedicated thread to run a functor or a method. The difference between QThread and std::thread is mostly in that std::thread lets you use functors, whereas QThread requires subclassing. The pthread API is similar to std::thread, except of course that it is C and is awfully unsafe compared to the C++ APIs.
// QThread
int main() {
class MyThread : public QThread {
void run() { qDebug() << "Hello from other thread"; }
} thread;
thread.start();
thread.wait();
return 0;
}
// std::thread
int main() {
// C++98
class Functor {
void operator()() { qDebug() << "Hello from another thread"; }
} functor;
std::thread thread98(functor);
thread98.join();
// C++11
std::thread thread11([]{ qDebug() << "Hello from another thread"; });
thread11.join();
return 0;
}
// pthread
extern "C" void* functor(void*) { qDebug() << "Hello from another thread"; }
int main()
{
pthread_t thread;
pthread_create(&thread, NULL, &functor, NULL);
void * result;
pthread_join(thread, &result);
return 0;
}
So, what is this good for? Sometimes, you have no choice but to use a blocking API. Most database drivers, for example, have blocking-only APIs. They expose no way for your code to get notified when a query has been finished. The only way to use them is to run a blocking query function/method that doesn't return until the query is done. Suppose now that you're using a database in a GUI application that you wish to remain responsive. If you're running the queries from the main thread, the GUI will block each time the database query run. Given long-running queries, a congested network, a dev server with a flaky cable that makes the TCP perform on par with sneakernet... you're facing huge usability issues.
Thus, you can't but have to run the database connection on, and execute the database queries on a dedicated thread that can get blocked as much as necessary.
Even then, it might still be helpful to use some QObject on the thread, and spin an event loop, since this will allow you to easily queue the database requests without having to write your own thread-safe queue. Qt's event loop already implements a nice, thread-safe event queue so you might as well use it. For example, with a note that Qt's SQL module can be used from one thread only - thus you can't prepare QSQLQuery in the main thread :(
Note that this example is very simplistic, you'd likely want to provide thread-safe way of iterating the query results, instead of pushing the entire query's worth of data at once.
class DBWorker : public QObject {
Q_OBJECT
QScopedPointer<QSqlDatabase> m_db;
QScopedPointer<QSqlQuery> m_qBooks, m_query2;
Q_SLOT void init() {
m_db.reset(new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE")));
m_db->setDatabaseName(":memory:");
if (!m_db->open()) { emit openFailed(); return; }
m_qBooks.reset(new QSqlQuery(*m_db));
m_qBooks->prepare("SELECT * FROM Books");
m_qCars.reset(new QSqlQuery(*m_db));
m_qCars->prepare("SELECT * FROM Cars");
}
QList<QVariantList> read(QSqlQuery * query) {
QList<QVariantList> result;
result.reserve(query->size());
while (query->next()) {
QVariantList row;
auto record = query->record();
row.reserve(record.count());
for (int i = 0; i < recourd.count(); ++i)
row << query->value(i);
result << row;
}
return result;
}
public:
typedef QList<QVariantList> Books, Cars;
DBWorker(QObject * parent = 0) : QObject(parent) {
QObject src;
connect(&src, &QObject::destroyed, this, &DBWorker::init, Qt::QueuedConnection);
m_db.moveToThread(0
}
Q_SIGNAL void openFailed();
Q_SIGNAL void gotBooks(const DBWorker::Books &);
Q_SIGNAL void gotCars(const DBWorker::Cars &);
Q_SLOT void getBooks() {
Q_ASSERT(QThread::currentThread() == thread());
m_qBooks->exec();
emit gotBooks(read(m_qBooks));
}
Q_SLOT void getCars() {
Q_ASSERT(QThread::currentThread() == thread());
m_qCars->exec();
emit gotCars(read(m_qCars));
}
};
Q_REGISTER_METATYPE(DBWorker::Books);
Q_REGISTER_METATYPE(DBWorker::Cars);
// True C++ RAII thread.
Thread : public QThread { using QThread::run; public: ~Thread() { quit(); wait(); } };
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
Thread thread;
DBWorker worker;
worker.moveToThread(&thread);
QObject::connect(&worker, &DBWorker::gotCars, [](const DBWorker::Cars & cars){
qDebug() << "got cars:" << cars;
qApp->quit();
});
thread.start();
...
QMetaObject::invokeMethod(&worker, "getBooks"); // safely invoke `getBooks`
return app.exec();
}
Change void DrawWindow::alter_text() to void* DrawWindow::alter_text(void*) and return pthread_exit(NULL);.

qt5: how to create and display custom qdialog from static function within a qthread

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
}
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.
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.

Resources