PyQt:app.exec_()会阻止所有后续代码的执行

14

我有一段看起来像这样的代码:

app = QApplication(sys.argv)
self.interface = Interface()

# The figure
self.fig = self.interface.fig
self.ax = self.fig.add_subplot(111)

self.interface.show()
app.exec_()

print 'this is not printed'
问题在于一旦执行了app.exec_(),除非我关闭弹出的窗口,否则不会有任何反应。
如何继续运行代码?
如何保持代码继续运行?
4个回答

16

这是有意的。您需要做的是使用信号/槽、在您的Qt类中编写代码,或在调用app.exec()之前启动线程。

信号和槽是与Qt交互的默认方法。基本上,一个信号是任何“事件”或自定义“事件”,而槽可以被看作是“事件处理程序”。例如,当GUI上的按钮被按下时,它将创建一个信号,寻找连接到它的任何处理程序。您可以连接零个、一个或多个槽到每个信号(您甚至可以多次连接同一个槽)!这里是一个很好的Python参考

在Qt类中编写代码通常意味着创建为您执行有用工作的槽。请记住,你不想让事件循环卡住太久,因此如果这样做,请生成新线程。

您可以使用第三个选项来启动其他线程。小心使用线程与Qt进行交互,如果这样做,您必须使用信号和槽。请按照此SO建议实现线程。


非常抱歉,我对此还比较新,所以您能否请详细解释一下我应该做什么,或者至少指出一些在线示例?不幸的是,PyQt 的示例相当稀少... - cgf
1
如果你遇到更多问题,请告诉我。基本上,app.exec() 应该会锁定一切,你需要绕过它来解决问题。 - Jack
所以,归根结底,没有机会在app.exec_()之后运行代码?是否可能只是打开一个窗口,做一些事情,然后关闭它,然后再运行代码? - cgf
我从未这样做过,但所有的迹象都指向肯定,只要确保你使用的任何东西都调用了正确的Qt信号来关闭它。否则,Qt会关闭得非常混乱,而你可能无法使该函数返回。 - Jack

9

app.exec_()不会锁定任何内容,它运行一个GUI事件循环,等待用户操作(事件),并将它们分派到正确的小部件进行处理。在没有顶级窗口保持打开状态时,它会一直执行此操作;如果您至少保留了一个应用程序的顶级窗口,则exec()永远不会返回,它无法返回(在系统关闭期间将终止您的应用程序)。当没有更多的顶级窗口时,应用程序会清理并从exec()返回。此时,GUI不再处于事件循环中。

无论您想在exec()之后做什么,您很可能会将其放在QThread或信号处理程序中(例如,您会将“Go!”按钮连接到处理程序,将“Cancel”按钮连接到关闭应用程序窗口的处理程序)。

您可以在exec()之后放置代码,但这可能相当不寻常:如果出现任何问题,由于GUI不再可见,因此用户很难看到问题,GUI应用程序通常不会打开控制台终端,因此通常不会有控制台(即,您将通过pythonw.exe而不是python.exe运行应用程序),或者您必须打开一个新窗口并再次执行exec()以显示错误消息并等待用户单击确定,在ok处理程序中销毁消息窗口,以便app.exec()再次返回。


1
GUI启动后是否会触发信号? - Hanan Shteingart
QApplication会发出十几个信号,其中一个可能会奏效(http://doc.qt.io/qt-5/qapplication.html)。 QMainWindow可能有一些事件方法(大多数在QWidget中定义),您可以通过重写方法来捕获它们。如需更多详细信息,请在SO上发布具体问题。 - Oliver

5
除了之前的答案,不是每次当所有窗口都关闭时GUI事件循环(由app.exec_()运行)都会停止。如果您想手动终止它,可以在任何事件处理程序中使用app.quit()。它将停止GUI事件循环并在app.exec_()后启动您的代码。
第一个答案是一堆空话。

1

一种消除阻塞的卑劣手段是滥用mathplot lib:

import matplotlib
import matplotlib as mpl

import matplotlib.cbook as cbook
import matplotlib.collections as mcol
import matplotlib.patches as mpatches
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
import matplotlib.cm as cm       # colors 
from   mpl_toolkits.mplot3d import Axes3D   # imports options for 3-D plotting
from   matplotlib.backends.backend_pdf import PdfPages

from PyQt5 import QtWidgets, uic
# ============================================================== 
if not QtWidgets.QApplication.instance():
    app = QtWidgets.QApplication(sys.argv)
else:
    app = QtWidgets.QApplication.instance() 
#endelse

MainWindow =  QtWidgets.QMainWindow()
MainWindow=uic.loadUi('E:\Python\Python_lib\MyGui.ui',MainWindow)
MainWindow.show()

# There are two ways to start the gui, and i.e. it looping 
# The correct way if to use app.exec_(), which 
# blocks the command line :


#d=app.exec_()

# However, this will block the command line making 
# We can misuse mathplot lib creating a Figure instead
# which seems to start the Gui loop without blocking the command line: 

ImageFig = Figure((3,4))
ImagePanel = FigureCanvas(ImageFig)
ImagePanel.draw()

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