Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QApplication In Non-Main Thread

I need to exec() a QApplication in a thread that is not main (my GUIs must be plugins that can be dynamically loaded and unloaded at runtime, so I have no access to the main thread). Does anyone know of a (relatively) painless way to hack around Qt's restriction against starting QApplication outside of main?

I'm developing in Linux with Qt4 in C++ using gcc4.3.4.

like image 787
rcv Avatar asked May 09 '10 19:05

rcv


4 Answers

Adding my 2 cents with a fancy lambda and C++ threads:

#include "mainwindow.h"
#include <QApplication>
#include <thread>

int main(int argc, char *argv[])
{
    std::thread t1
    (
        [&]
        {
            QApplication a(argc, argv);
            MainWindow w;
            w.show();
            return a.exec();
        }
    );
    t1.join();
}

Here Mainwindow can be your QMainWindow.

like image 111
PRIME Avatar answered Oct 07 '22 07:10

PRIME


You can start a QApplication in a PThread as below

//main.cpp

#include <iostream>
#include "appthread.h"
int main(int argc, char *argv[]) {
  InputArgs args = {argc, argv};
  StartAppThread(args);
  sleep(10);
  return 0;
}

//appthread.h

struct InputArgs{
  int argc;
  char **argv;
};
void StartAppThread(InputArgs &);

//appthread.cpp

#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include "appthread.h"
#include <pthread.h>

void *StartQAppThread(void *threadArg) {
  InputArgs *args = (struct InputArgs*) threadArg;
  QApplication app(args->argc, args->argv);
  QMainWindow w;
  w.show();
  w.setCentralWidget(new QPushButton("NewButton"));
  app.exec();
  pthread_exit(NULL);
}

void StartAppThread(InputArgs &args) {
  pthread_t thread1;  
  int rc = pthread_create(&thread1, NULL, StartQAppThread, (void*)&args);
}
like image 36
Chenna V Avatar answered Nov 11 '22 09:11

Chenna V


If you are using QThread then you already have normal Qt event loop and can just run exec() inside QThread::run() function. While you can't work with GUI objects outside of the main thread you still can interact with them through queued signal/slot connections. Maybe you can try to store pointer to the main thread QThread object and call QObject::moveToThread() to move your GUI objects to the main thread instead of moving QApplication into another thread.

I think it's not really good idea to try to go against toolkit with different kind of hacks and kluges.

like image 40
VestniK Avatar answered Nov 11 '22 09:11

VestniK


Ok, I got something that works! It's not pretty, but it definitely does the job.

  1. Create a QMainWindow derivative with all of your actual GUI code in it and overload the event() function of this class to call this->show()

  2. Create a class (let's call it Runner) which will hold a pointer to your QMainWindow derivative, and give it a run function.

  3. In the Runner::Runner(), start up a thread which will call Runner::run()

  4. In Runner::run() (which is now running in it's own thread) construct a QApplication, and an instantiation of your QMainWindow derivative. Call the exec() function of the QApplication.

  5. Now, when you want to start up your GUI, just post any event to your QMainWindow derivative, and it will show itself!

This solution seems to work very well in Linux, although it really seems to be exploiting some loophole in Qt and may not work on other platforms. Definitely easier than patching Qt though.

like image 2
rcv Avatar answered Nov 11 '22 08:11

rcv