Multithreading Qt: Cannot access a Qt object after app.exec()
-
So I have a class called QtWindowInit, that initializes some QWidgets in a seperate thread. It instantiates the QApplicaton object in this seperate thread. In the example below it initializes a LED that I created.
class QtWindowInit { public: inline void Init() { _qtThread = boost::thread(&QtWindowInit::StartThread, this); } inline void StartThread() { char *argv[] = {"program name", "arg1", "arg2", NULL}; int argc = sizeof(argv) / sizeof(char*) - 1; QApplication app(argc, argv); // Some code to initialize the window _led = new QGraphicsEllipseItem(50, 50, 50, 50); _led->setBrush(Qt::gray); // Some code to add it to the window and then call show() app.exec(); }
Then I have a main:
int main(int argc, char *argv[]) { QtWindowInit LED(); LED.StartThread(); LED._led->setBrush(Qt::red); // This line of code causes the gui to show nothing }
With the above line of code where I set the brush color, the gui does not even show up. It doesn't crash and I don't get any errors. Without that line, the gui works and the led shows up but it is gray. Could it be because I am trying to set the color after app.exec()? Is there a work around?
-
Hi and welcome to devnet,
keep in mind that
QApplication::exec()
never returns.In your code everything is executed in the main thread; Qt suggest to create the application object and the GUI in the main thread.
-
@justiliang said:
LED._led->setBrush(Qt::red); // This line of code causes the gui to show nothing
As I said in http://forum.qt.io/topic/53905/ , the methods of GUI-related objects can only be called in the thread that created QApplication.
-
@JKSH Do you know of a work around for my case? I need somehow be able to change the color outside of the thread.
-
@justiliang said:
@JKSH Do you know of a work around for my case? I need somehow be able to change the color outside of the thread.
Yes, there are 2 ways to do handle this use-case:
- Emit a signal from your secondary thread.
- Call QMetaObject::invokeMethod() in your secondary thread.
For both ways listed above, use a Qt::QueuedConnection to connect your request to a QObject that lives in the GUI thread. When that QObject receives your request, it should call
setBrush()
for you. This way,setBrush()
is executed in the correct thread.See also the section about QObject thread affinity.