我有一个PyQt GUI,用于在Python中启动长时间运行的计算。这是一个最小的例子:
import sys
import time
from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QDialog,
QVBoxLayout, QPushButton, QDialogButtonBox)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
button = QPushButton("Start", self)
button.clicked.connect(self.long_task)
self.setGeometry(300, 300, 300, 200)
self.show()
def long_task(self):
dialog = QDialog(self)
vbox = QVBoxLayout(dialog)
label = QLabel("Running...")
button = QDialogButtonBox(QDialogButtonBox.Cancel)
vbox.addWidget(label)
vbox.addWidget(button)
dialog.open()
time.sleep(10) # long task, external function
dialog.close()
app = QApplication(sys.argv)
main = MainWindow()
app.exec_()
在主窗口中,我可以通过单击按钮启动任务。然后弹出模态对话框并开始任务。如果GUI被阻止是可以的(我知道我可以通过将任务放在一个单独的工作线程中来防止冻结GUI线程,但这不是重点)。关键的是,我希望能够击中"取消"按钮来终止任务。或者,由于长时间运行的任务总是Python命令,我也可以使用Ctrl + C来终止任务。
我无法改变长时间运行的Python命令:即,我无法将其分解成小块,并将状态变量与线程结合使用,有时会提示。替代方法(按Ctrl + C)也不起作用,因为PyQt似乎没有注册它(即使Python解释器应该在它运行任务时)。
答案 0 :(得分:1)
最简单的方法是使用multiprocessing。这将允许您同时运行任务(或任务组)并随时终止处理。但是,请务必阅读programming guidelines以了解如何有效使用该模块。特别是,尽管terminate方法适用于自包含任务,但它不应该与使用共享资源的多个任务一起使用。
以下是基于您的示例的简单演示:
import sys
import time
from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QDialog,
QVBoxLayout, QPushButton, QDialogButtonBox)
from multiprocessing import Pool
def long_task():
for x in range(10):
print('long task:', x)
time.sleep(1)
return 'finished'
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
button = QPushButton("Start", self)
button.clicked.connect(self.long_task)
self.setGeometry(300, 300, 300, 200)
self.show()
def long_task(self):
dialog = QDialog(self)
vbox = QVBoxLayout(dialog)
label = QLabel("Running...")
button = QDialogButtonBox(QDialogButtonBox.Cancel)
button.rejected.connect(dialog.close)
vbox.addWidget(label)
vbox.addWidget(button)
def callback(msg):
print(msg)
dialog.accept()
pool.apply_async(long_task, callback=callback)
if dialog.exec_() == QDialog.Rejected:
pool.terminate()
print('terminated')
app = QApplication(sys.argv)
main = MainWindow()
app.exec_()