有没有办法在没有 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:有没有办法在没有标签的情况下运行单个测试?