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
,
Хорошо, у меня есть кое-что, что работает! Это не красиво, но это определенно делает работу.
Создайте производную QMainWindow со всем вашим действительным кодом GUI и перегрузите функцию event() этого класса, чтобы вызвать this->show()
Создайте класс (назовем его Runner), который будет содержать указатель на вашу производную QMainWindow, и предоставит ему функцию run.
В Runner::Runner() запустите поток, который будет вызывать Runner::run()
В Runner::run() (которая теперь выполняется в своем собственном потоке) создайте QApplication и создайте экземпляр вашего производного QMainWindow. Вызовите функцию exec() приложения QApplication.
Теперь, когда вы захотите запустить свой графический интерфейс, просто опубликуйте любое событие в производной от 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.