QApplication в неосновной теме

Мне нужно выполнить exec() QApplication в потоке, который не является основным (мои GUI должны быть плагинами, которые могут динамически загружаться и выгружаться во время выполнения, поэтому у меня нет доступа к основному потоку). Кто-нибудь знает (относительно) безболезненный способ взломать ограничение Qt против запуска QApplication вне main?

Я разрабатываю в Linux с Qt4 в C++, используя gcc4.3.4.

5 ответов

Решение

Если вы используете QThread, то у вас уже есть обычный цикл обработки событий Qt, и вы можете просто запустить exec() внутри функции QThread::run(). Хотя вы не можете работать с объектами графического интерфейса вне основного потока, вы все равно можете взаимодействовать с ними посредством подключенных к очереди соединений сигнал / слот. Возможно, вы можете попытаться сохранить указатель на объект QThread основного потока и вызвать QObject::moveToThread(), чтобы переместить объекты GUI в основной поток вместо перемещения QApplication в другой поток.

Я думаю, что не очень хорошая идея пытаться идти против инструментария с различными видами хаков и клугов.

Вы можете запустить QApplication в PThread, как показано ниже

//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);
}

Патч Qt, я полагаю, удалите проверку основного потока и проверьте, работает ли она для вас. Согласно http://bugreports.qt-project.org/browse/QTBUG-7393, это не будет работать на OS X/Cocoa, поскольку Cocoa предполагает, что первый поток порожден как основной поток / поток пользовательского интерфейса.

Добавляя мои 2 цента с причудливой лямбда-нитью и потоками C++:

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

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

Вот Mainwindow может быть вашим QMainWindow,

Хорошо, у меня есть кое-что, что работает! Это не красиво, но это определенно делает работу.

  1. Создайте производную QMainWindow со всем вашим действительным кодом GUI и перегрузите функцию event() этого класса, чтобы вызвать this->show()

  2. Создайте класс (назовем его Runner), который будет содержать указатель на вашу производную QMainWindow, и предоставит ему функцию run.

  3. В Runner::Runner() запустите поток, который будет вызывать Runner::run()

  4. В Runner::run() (которая теперь выполняется в своем собственном потоке) создайте QApplication и создайте экземпляр вашего производного QMainWindow. Вызовите функцию exec() приложения QApplication.

  5. Теперь, когда вы захотите запустить свой графический интерфейс, просто опубликуйте любое событие в производной от QMainWindow, и оно покажет себя!

Похоже, что это решение очень хорошо работает в Linux, хотя на самом деле оно использует некоторую лазейку в Qt и может не работать на других платформах. Определенно проще, чем патчить Qt.

Хорошее решение можно найти в: git@github.com:midjji/ удобный_multithreaded_qt_gui.git

тогда это просто например

run_in_gui_thread(new RunEventImpl([](){
        QMainWindow* window=new QMainWindow();
        window->show();
    }));

или любой другой код, который вы хотите запустить в потоке графического интерфейса.

вызывается из любого потока, в любое время, при этом заботясь о настройке для вас в bg.

Другие вопросы по тегам