2010-05-09 2 views
10

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

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

ответ

4

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

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

+0

Я думаю, что вы можете быть правы, VestniK. Хотя мой графический интерфейс действительно работает, на самом деле он не вызывает вызовы update(), если я не заставляю ОС перерисовывать графический интерфейс, перетаскивая другое окно поверх него. – rcv

+0

Я нашел этот ответ полезным для решения другой проблемы, но, перемещая объект QMainWindow из другого потока в основной, я получил 'QObject :: moveToThread: виджеты не могут быть перенесены в новый поток' – ASten

1

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

1

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

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

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

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

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

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

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

+0

Эй, Бодзарт, я пытаюсь добиться того же. Когда вы говорите «Runner :: Runner(), запустите поток, который вызывается Runner :: run()», что вы имеете в виду.Начните еще один QThread, который запустит поток Runner? Но как вы могли бы начать другой поток без создания QApplication? – blueskin

8

Вы можете начать 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); 
}