如何在 Python 函数中创建简单的 PyQt 弹出窗口并在结束时关闭?
How to create simple PyQt popup in Python function and close at the end of it?
我是 运行 一个函数,我想在其中打开一个 PyQt 弹出窗口,上面写着类似 "Waiting..." 的内容,它会持续到函数完成所需的时间。之后我想将文本更改为 "Complete",休眠一两秒钟,然后关闭弹出窗口。我已经尝试了很多方法来做到这一点,但到目前为止都没有成功。看起来任何时候我调用 app.exec_()
函数都会停止函数,直到我关闭弹出窗口。我想在 PyQt 的主事件循环的上下文之外执行此操作(我异步尝试 运行 此事件循环无济于事)。如果我不调用 exec_()
,我根本看不到弹出窗口。基本上我想要这样的东西:
# this is the function that is being run
def run():
create_popup() # show popup
wait_for_some_messages() # do some stuff
close_popup() # close popup
def create_popup():
app = QApplication([])
popup = Popup()
popup.show()
class Popup(QDialog):
super().__init__()
self.label = QLabel(self)
非常感谢任何帮助。谢谢!
我认为你要执行的任务很重,所以你可以阻止 GUI 循环,所以建议实现一个 QRunnable
并用 QThreadPool
启动它,在 运行方法会调用heavy函数,最后这个task会通过QMetaObject::invokeMethod
更新数据,然后我们用一个QEventLoop
等待2秒后调用方法close.
class Runnable(QRunnable):
def __init__(self, popup, func):
QRunnable.__init__(self)
self.popUp = popup
self.func = func
def run(self):
# execute hard function
self.func()
# Update the text shown in the popup
QMetaObject.invokeMethod(self.popUp, "setText",
Qt.QueuedConnection,
Q_ARG(str, "Complete"))
# wait 2 seconds
loop = QEventLoop()
QTimer.singleShot(2000, loop.quit)
loop.exec_()
# call the close method of the popup
QMetaObject.invokeMethod(self.popUp, "close",
Qt.QueuedConnection)
class PopUp(QDialog):
def __init__(self, *args, **kwargs):
QDialog.__init__(self, *args, **kwargs)
self.setLayout(QVBoxLayout())
self.label = QLabel(self)
self.layout().addWidget(self.label)
@pyqtSlot(str)
def setText(self, text):
self.label.setText(text)
# emulate the heavy task
def func():
for i in range(10000):
print(i)
QThread.msleep(1)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = PopUp()
w.show()
w.setText("Waiting...")
runnable = Runnable(w, func)
QThreadPool.globalInstance().start(runnable)
w.exec_()
加上:
如果你想调用另一个函数只需更改:
runnable = Runnable(w, func)
至:
runnable = Runnable(w, name_of_your_function)
我是 运行 一个函数,我想在其中打开一个 PyQt 弹出窗口,上面写着类似 "Waiting..." 的内容,它会持续到函数完成所需的时间。之后我想将文本更改为 "Complete",休眠一两秒钟,然后关闭弹出窗口。我已经尝试了很多方法来做到这一点,但到目前为止都没有成功。看起来任何时候我调用 app.exec_()
函数都会停止函数,直到我关闭弹出窗口。我想在 PyQt 的主事件循环的上下文之外执行此操作(我异步尝试 运行 此事件循环无济于事)。如果我不调用 exec_()
,我根本看不到弹出窗口。基本上我想要这样的东西:
# this is the function that is being run
def run():
create_popup() # show popup
wait_for_some_messages() # do some stuff
close_popup() # close popup
def create_popup():
app = QApplication([])
popup = Popup()
popup.show()
class Popup(QDialog):
super().__init__()
self.label = QLabel(self)
非常感谢任何帮助。谢谢!
我认为你要执行的任务很重,所以你可以阻止 GUI 循环,所以建议实现一个 QRunnable
并用 QThreadPool
启动它,在 运行方法会调用heavy函数,最后这个task会通过QMetaObject::invokeMethod
更新数据,然后我们用一个QEventLoop
等待2秒后调用方法close.
class Runnable(QRunnable):
def __init__(self, popup, func):
QRunnable.__init__(self)
self.popUp = popup
self.func = func
def run(self):
# execute hard function
self.func()
# Update the text shown in the popup
QMetaObject.invokeMethod(self.popUp, "setText",
Qt.QueuedConnection,
Q_ARG(str, "Complete"))
# wait 2 seconds
loop = QEventLoop()
QTimer.singleShot(2000, loop.quit)
loop.exec_()
# call the close method of the popup
QMetaObject.invokeMethod(self.popUp, "close",
Qt.QueuedConnection)
class PopUp(QDialog):
def __init__(self, *args, **kwargs):
QDialog.__init__(self, *args, **kwargs)
self.setLayout(QVBoxLayout())
self.label = QLabel(self)
self.layout().addWidget(self.label)
@pyqtSlot(str)
def setText(self, text):
self.label.setText(text)
# emulate the heavy task
def func():
for i in range(10000):
print(i)
QThread.msleep(1)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = PopUp()
w.show()
w.setText("Waiting...")
runnable = Runnable(w, func)
QThreadPool.globalInstance().start(runnable)
w.exec_()
加上:
如果你想调用另一个函数只需更改:
runnable = Runnable(w, func)
至:
runnable = Runnable(w, name_of_your_function)