4

我正在尝试在 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 线程中的运行函数看起来像这样:

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 不会失败,因此参数不是问题,而是通过单独的工作线程调用该方法。

4

3 回答 3

4

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

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

于 2011-02-26T17:52:20.283 回答
3

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

请注意,使用QMetaObject::invokeMethod()(with Qt::BlockedConnection),您可以跨线程安全地调用函数并获取返回值,而无需过多编码。

于 2011-02-26T17:55:28.303 回答
2

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

Qt 文档中的示例:

myObject->moveToThread(QApplication::instance()->thread());
于 2012-06-30T19:26:53.763 回答