在主线程之外创建QDialog的方法

时间:2011-02-26 17:33:58

标签: qt qthread

我正在尝试在QT中创建一个客户端应用程序,它需要处理线程和可变数量的窗口实例。但我正在努力弄清楚如何在其中一个处理线程中创建一个新窗口。我知道所有ui元素必须在与QApplication类相同的线程中创建,但我需要能够实例化,或者至少在另一个线程中引用QDialog。
线程和QDialog之间的通信可以使用信号完成,我并不担心这一点,但实际上创建窗口是另一回事。我可以使用信号告诉主线程为窗口创建一个实例,然后以某种方式检索指向它的指针,但对我来说似乎有点复杂和丑陋。有没有更好的方法来完成这样的任务?要在主线程外创建QDialog,QApplication类是否存在?

编辑:我尝试过Q_INVOKABLE方法,但它不能跨线程工作。我创建了一个视图工厂类,它可以创建我指定的类型的QDialog并返回指向它的指针。此类已在主GUI线程中实例化,并且对此类的引用将发送到任何工作线程。问题是,当一个线程使用Qt :: BlockingQueuedConnection从工厂调用create方法时,invoke方法失败。如果我将其更改为Qt :: DirectConnection,则invoke方法将调用正确的create方法,但在当前线程中调用工作线程。

我的主要功能如下:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ViewFactory vFactory;

    vFactory.registerCreator(Util::W_CONNECT, new ConnectWindow::ConnectCreator());

    ClientApp app;

    if(!app.Initialize(&vFactory))
        return 0;

    app.start();
    a.exec();
    .............................

}

我在ClientApp线程中的run函数看起来像这样:

void ClientApp::run()
{
    QDialog * tmp = NULL;
    QMetaObject::invokeMethod(this->_vFactory, "create", Qt::BlockingQueuedConnection,
                        Q_RETURN_ARG(QDialog*, tmp), Q_ARG(int, 0));
}

就像我说的,如果我将连接类型更改为Qt :: DirectConnection,invokeMothod将不会失败,因此params不是问题,而是在单独的工作线程中调用该方法。

3 个答案:

答案 0 :(得分:3)

你只能在gui线程中做Gui的东西。显而易见的解决方案是工作线程以Qt术语向gui thread = a信号发送消息。

如果一个工作线程需要提问,它应该向gui线程发送一条消息然后阻塞,直到它收到回信号。

答案 1 :(得分:3)

AFAIK,信号(或只是一个动态可调用的方法,使用Q_INVOKABLE)或事件是可行的方法。

请注意,使用QMetaObject::invokeMethod()(带Qt::BlockedConnection),您可以跨线程安全地调用函数,并在没有太多编码的情况下获取返回值。

答案 2 :(得分:2)

好像QObject::moveToThread可以解决这个问题。此函数将事件处理循环移动到另一个线程。

Qt文档示例:

myObject->moveToThread(QApplication::instance()->thread());