有没有办法在没有 QApplication::exec() 的情况下使用 Qt?

Posted

技术标签:

【中文标题】有没有办法在没有 QApplication::exec() 的情况下使用 Qt?【英文标题】:Is there a way to use Qt without QApplication::exec()? 【发布时间】:2012-10-03 23:27:33 【问题描述】:

有没有不调用 QApplication::exec() 来使用 Qt 的安全方法?

我有许多不同的对象在多个资源上执行长期进程(其中至少一个正在与 Web 应用程序服务器通信)。我正在制作一个 GUI 应用程序,提示用户在正确的时间输入这些不同的进程。我想将我的“流程”逻辑——决定下一步做什么的逻辑——放在一个地方,而不是像对话框类这样的 GUI 对象中。我在想我可以做这样的事情:

...

wait_dialog dlg;
dlg.setModal( false );
dlg.show(); // Should return...

netobject.start_long_lived_process_that_happens_on_other_thread( &completion_callback );
while ( !completion_callback_called() )

    qApp->processEvents();
    netobject.pump_callbacks();
    magically_avoid_busywait_while_still_servicing_qt_somehow();


dlg.hide();

...

从 Qt 的角度来看,这安全吗?有没有实现magically_avoid_busywait_while_still_servicing_qt_somehow() 的“好”方法?

我在这里想要完成的是尽可能以最明确的方式编写我们的处理流程。我想要一个这样做的函数:

 show_a_non_modal_wait_dialog()

 start_some_processing_1()

 wait_for_processing_1_to_finish()

 dismiss_non_modal_wait_dialog()

 show_modal_input_dialog()

 if ( cancelled ) return

 show_a_non_modal_wait_dialog()

 start_some_processing_2()

 wait_for_processing_2_to_finish()

 dismiss_non_modal_wait_dialog()

 show_modal_input_dialog()

 if ( cancelled ) return

 ...

我真正想要避免的是开始并等待 Qt 小部件和窗口内的处理。此外,处理对象本身完全独立于 Qt。我想我想要做的是在单个函数中创建一个控制器,其中包含一些辅助回调和状态变量。

【问题讨论】:

我想我不确定您为什么需要为此停止事件处理。我相信设置为 0 ms 的 QTimer 将在 gui 有机会的任何时候运行,并且可用于从其他线程收集信号以在 gui 线程上运行代码并避免任何线程地狱。因此,您的线程对象(QThread)可以执行它的业务并在需要输入时发出信号,然后自行停止。 gui 线程捕获该信号,提示用户,给线程结果。然后线程可以继续。还是我误会了? 我们的应用程序在 Qt 位和应用程序的其余部分之间有一条清晰的分界线。我们的大部分源文件(包括上面的 main 函数)都没有通过 moc 工具运行,并且无法发出或接收 Qt 信号。 虽然可以在 QApplication 的空闲时间之外执行此功能,但这意味着该功能必须重新进入,并且会变成一个丑陋的状态机。我希望的是一个可以从头到尾运行的单个函数——这将使程序流程非常明确。 我正在尝试寻找一种替代方法,以将netobject 传递给我们所有的 GUI 窗口和对话框并让它们启动处理(恕我直言,这隐藏了整个连接/处理流程)。跨度> 信号和槽几乎是函数指针。您应该能够使用其中一个线程完成相同的事情。如果您从不调用 QApp::exec,我不完全确定 Qt 会做什么,我的猜测是它不会在意,但您可能需要检查源代码才能确定。 【参考方案1】:

您想要的是应用程序的主事件循环以外的事件循环。这可以使用QEventLoop

wait_dialog dlg;
dlg.setModal( false );
dlg.show(); // Should return...

QEventLoop loop;
connect(&netobject, SIGNAL(done()), &loop, SLOT(quit()));
netobject.start_long_lived_process_that_happens_on_other_thread();

loop.exec(); // BLOCKING (non-busy) until quit() is called via the signal done()

虽然(在我看来)这是干净的代码,但这需要您的 netobject 类是 QObject 并实现信号 done()(这也比提供回调更干净)。

现在您可以将整个代码封装在一个函数中,该函数本身就是一个阻塞调用,因此如果您愿意,它可以从您的对话框中返回一些结果。

【讨论】:

啊,既然你扩展了关于对象与 Qt 无关的信息的问题,我想补充一点,你也可以创建一个回调方法,只是退出特定的 QEventLoop 而不是这样做联系。这基本上是一样的。 我将把它标记为“答案”。我喜欢它完全避免了 processEvents() 这似乎有点狡猾,并且似乎有一些我不理解的危险异常(比如 DeferredDelete 事件?)。 你不知道这对我有多大帮助! @leemes 这是否会导致主事件循环出现任何问题,或者两者都在没有交叉点的情况下并行运行?如果没有,有没有办法防止这些可能的问题发生?

以上是关于有没有办法在没有 QApplication::exec() 的情况下使用 Qt?的主要内容,如果未能解决你的问题,请参考以下文章

[JavaScript]有没有办法在没有终端的情况下使用 Cloudinary

有没有办法在 REST API Jersey 中检测预检请求?

sbt 中的 ScalaTest:有没有办法在没有标签的情况下运行单个测试?

Falcor - 有没有办法迭代地图

有没有办法在没有活动的情况下使用 Viewpager 实现 TabLayout?

有没有办法在没有 CASE 表达式的情况下做到这一点?