有没有一种方法可以在没有QApplication :: exec()的情况下使用Qt?

5
有没有一种安全的方法可以在不调用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毫秒的QTimer会在GUI有机会运行时运行,并且可以用于收集其他线程的信号以在GUI线程上运行代码并避免任何线程问题。因此,您的线程对象(QThread)可以继续执行其业务并在需要输入时发出信号,然后停止自身。 GUI线程捕获该信号,提示用户,提供线程结果。然后线程可以继续进行。或者我误解了? - Thadeux
我们的应用程序在Qt部分和其余部分之间有明确的分界线。我们大部分的源文件(包括上面的主函数)不会通过moc工具运行,也无法发出或接收Qt信号。 - Ted Middleton
虽然可以通过挂在QApplication的空闲时间上来执行此函数,但这意味着该函数必须重新进入并且会变成一个丑陋的状态机。我希望有一个单一的函数可以从头到尾运行 - 这将使程序流程非常明确。 - Ted Middleton
我正在尝试寻找一种替代方法,避免将netobject传递给所有GUI窗口和对话框,并让它们启动处理(在我看来,这样会掩盖整个连接/处理流程)。 - Ted Middleton
信号和槽基本上就是函数指针。你应该可以用一个线程来完成同样的事情。我不确定如果你从未调用QApp::exec,Qt会怎么做,我猜它可能不会在意,但你最好检查一下源代码以确保。 - Thadeux
1个回答

5
你需要的是一个与应用程序主事件循环不同的事件循环。可以使用 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而不是建立连接即可。本质上这两种方法是相同的。 - leemes
我将把这个标记为“答案”。我喜欢它完全避免了processEvents(),这似乎有点不可靠,并且似乎有一些危险的异常,我不理解(比如DeferredDelete事件?)。 - Ted Middleton
你不知道这对我有多大帮助! - Luca
@leemes 这会不会对主事件循环造成任何问题,或者两者是否并行运行而没有交集?如果有问题,是否有方法可以防止这些可能的问题发生? - user3085931
当我尝试这个时,我得到的是:- QEventLoop:没有 QApplication 不能使用。 - Waslap

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接