我正在尝试在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不是问题,而是在单独的工作线程中调用该方法。
答案 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());