一个应用程序是可执行的进程,运行在一个或多个前台线程上,每个线程也可以启动后台线程来执行并行操作或不阻塞调用线程的操作。当所有前台线程结束后,应用程序将终止,因此您需要至少一个前台线程,在调用
app.exec_()
语句时创建。在 GUI 应用程序中,这是 UI 线程,在其中您应该创建和显示主窗口和任何其他 UI 小部件。Qt 将在所有小部件关闭后自动终止您的应用程序进程。
我的建议是尽可能遵循上述正常流程,工作流程如下:
启动应用程序 > 创建主窗口 > 为每个计算启动一个后台线程 > 将进度发送到 UI 线程 > 在每次计算完成后在窗口中显示结果 > 关闭所有窗口 > 结束应用程序
此外,您应该使用
ThreadPool
来确保您不会耗尽资源。
以下是一个完整的示例:
import sys
import time
import PyQt5
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import QRunnable, pyqtSignal, QObject
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QDialog
class CaptureDataTaskStatus(QObject):
progress = pyqtSignal(int, int)
captureDataFinished = pyqtSignal(dict)
class CaptureDataTask(QRunnable):
def __init__(self, num_measurements):
super().__init__()
self.num_measurements = num_measurements
self.status = CaptureDataTaskStatus()
def run(self):
for i in range(0, self.num_measurements):
self.status.progress.emit(i + 1, self.num_measurements)
time.sleep(0.1)
result = {'a': 1, 'b': 2, 'c': 3}
self.status.captureDataFinished.emit(result)
class ResultWindow(QWidget):
def __init__(self, result):
super().__init__()
self.result = result
print('a: {}'.format(result['a']))
print('b: {}'.format(result['b']))
print('c: {}'.format(result['c']))
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.result_windows = []
self.thread_pool = QtCore.QThreadPool().globalInstance()
self.thread_pool.setMaxThreadCount(1)
self.start_capturing_data()
def start_capturing_data(self):
for setting in range(0, 3):
capture_data_task = CaptureDataTask(300)
capture_data_task.status.progress.connect(self.capture_data_progress)
capture_data_task.status.captureDataFinished.connect(self.capture_data_finished)
self.thread_pool.globalInstance().start(capture_data_task)
def capture_data_progress(self, current, total):
print('Current: {}'.format(current))
print('Total: {}'.format(total))
def capture_data_finished(self, result):
result_window = ResultWindow(result)
self.result_windows.append(result_window)
result_window.show()
class App(QApplication):
"""Main application wrapper, loads and shows the main window"""
def __init__(self, sys_argv):
super().__init__(sys_argv)
self.main_window = MainWindow()
self.main_window.show()
if __name__ == '__main__':
app = App(sys.argv)
sys.exit(app.exec_())