PyQt 是基于事件的。它不断地运行一个循环等待事件,并在收到您关心的事件时调用您的回调(或向您的插槽发出信号)。所以,没有办法直接说“在我得到输入之前阻止”。
但是,在你到达那一点之前,如果你的模拟在主线程中连续运行一个循环,PyQt 也不能在主线程中连续运行一个循环。所以它不能响应来自操作系统的事件,比如“更新你的窗口”或“退出”。就您的用户而言,该应用程序只是冻结了;她只会看到广受欢迎的沙滩球(或其他平台等效)。
但是,无论您选择解决第一个问题,都将几乎免费解决第二个问题的大部分内容。
为什么您的 GUI 应用程序冻结尝试解释整个问题以及所有可能的解决方案,一般来说,使用 Tkinter 作为 GUI 库的示例。如果你想要更多特定于 Qt 的东西,我很确定 Qt 教程中有一个完整的部分,尽管我不确定在哪里,你可能需要在脑海中将一些 C++ 翻译成 Python。
但是有两个主要选项:回调或线程。
首先,您可以将循环分成小块,每个小块只需要几毫秒。不是运行整个循环,而是运行第一个片段,作为最后一行,它要求 PyQt 尽快安排下一个片段(例如,使用QTimer
超时为 0 的 a)。现在,Qt 将每隔几毫秒检查一次事件,如果它无事可做,它将立即开始您的下一步工作。
如果您的流控制已经围绕生成适当大小的块的迭代器(或推送协程)构建,那么这非常容易。如果不是,则可能意味着将外部循环中的流量控制由内向外翻转,这可能很难理解。
那么,完成这些之后,如何获得用户输入呢?简单的:
- 在你应该调用的地方
raw_input
,而不是安排下一段代码,而是做一些适当的 GUI 东西——创建一个弹出消息框,取消隐藏文本输入控件和按钮,等等。
- 将下一段代码连接为按钮单击或消息框接受或任何信号的处理程序。
或者,您可以在后台线程中运行您的工作。这不需要你重新组织任何东西,但它确实需要你小心不要在线程之间共享任何东西。不幸的是,这包括从后台线程调用 GUI 小部件上的方法,您认为这会导致无法执行任何有用的操作。幸运的是,PyQt 有很容易处理这个问题的机制:信号会根据需要在线程之间自动路由。
那么,在这种情况下如何要求用户输入呢?
- 将 之后的所有内容拆分
raw_input
为一个单独的函数,您可以将其连接为got_input
信号的处理程序。
- 在您曾经调用的原始函数中
raw_input
,您改为发出gimme_input
信号。
- 为该
gimme_input
信号编写一个处理程序以在主线程中运行,这将建立 GUI 小部件(与上面的单线程示例一样)。
got_input
为将信号发送回工作线程的 OK 按钮编写一个处理程序。