python - 需要建议以保持 GUI 响应
问题描述
基本上,我所拥有的是一个带有一些 QLineEdits、一个“搜索按钮”和一个表格的 GUI。您点击按钮,一个名为 DataGrabber 的类会在数据库中搜索数据,对其进行处理,然后返回一个列表,其中包含相应地填充表的字典。这些搜索可能需要一段时间,我需要保持我的 GUI 响应。另外,我希望状态栏消息在搜索进行时改变(类似于“正在搜索”->“正在搜索..”->“正在搜索...”,功能在这里并不重要,它只是关于了解我如何正确处理这个问题)。
我从对所有内容进行线程化开始,并在处理搜索的线程和处理状态栏的函数之间创建了一个队列,以了解搜索何时完成。但这似乎真的很愚蠢。特别是因为 Qt 提供了各种工具,例如 QThread 和 Signals。但我现在迷路了。当进行像数据库搜索这样耗时的操作时,处理响应性的最佳方法是什么?告诉主/子线程搜索完成的最佳方式是什么?
这是我现在拥有的简化版本:
class GUI(Ui_MainWindow, InitGlobals):
def __init__(dialog):
...
self.start_button_3.clicked.connect(\
lambda: self.start_search(self.result_tab_3))
...
def start_search():
...
search_paras = [3,
self.name_box_3.text(),
self.project_combo_3.currentText(),
self.voltage_box.text(),
self.volume_box.text()]
queue = Queue()
thr = Thread(target=self.search_thread, args=(queue, search_paras,))
thr.start()
data_lst = statusbar_load(queue, self.statusbar, option="loader")
thr.join()
self.statusbar.showMessage("Search completed...")
for dic in data_lst:
self.write_to_table(dic, tab)
def search_thread(self, queue, args):
grabber = DataGrabber(self.db_config)
...
if args[0] == 3:
queue.put(grabber.alpha_search(args[1], args[2],
args[3], args[4]))
queue.task_done()
def statusbar_load(queue, statusbar_obj, option="spinner"):
data = None
i = 0
while data is None:
try:
data = queue.get(timeout=0.1)
except Empty:
if option == "spinner":
status = ["-", "\\", "|", "/"]
statusbar_obj.showMessage("Searching [" + status[i%4] + "]")
....
i = i + 1
return data
解决方案
这可以用信号来处理。您可以使用信号将结果发送到 GUI 并更新进度的 GUI。
这是一个带有进度条和状态标签的快速实现示例。如果您愿意,这些可以包含在状态栏中:
class GUITest(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
layout = QtWidgets.QGridLayout()
self.button = QtWidgets.QPushButton('Run')
self.button.clicked.connect(self.run)
self.result_box = QtWidgets.QTextBrowser()
self.label = QtWidgets.QLabel()
self.progress_bar = QtWidgets.QProgressBar()
self.progress_bar.setVisible(False)
self.progress_bar.setMinimum(0)
self.progress_bar.setMaximum(100)
self.progress_bar.setValue(0)
layout.addWidget(self.button)
layout.addWidget(self.result_box)
layout.addWidget(self.label)
layout.addWidget(self.progress_bar)
self.setLayout(layout)
def run(self):
self.progress_bar.setVisible(True)
self.label.setText('Searching...')
self.thread = QtCore.QThread()
self.data_grabber = DataGrabber()
self.data_grabber.moveToThread(self.thread)
self.data_grabber.update_progress.connect(self.update_progress_bar)
self.data_grabber.results.connect(self.display_results)
self.data_grabber.finished.connect(self.complete)
self.data_grabber.finished.connect(self.thread.quit)
self.data_grabber.finished.connect(self.data_grabber.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
self.thread.started.connect(self.data_grabber.run)
self.thread.start()
def update_progress_bar(self):
self.progress_bar.setValue(self.progress_bar.value() + 1)
def complete(self):
self.label.setText('Complete')
self.progress_bar.setVisible(False)
def display_results(self, results):
for key, value in results.items():
self.result_box.append('%s: %s' % (key, value))
class DataGrabber(QtCore.QObject):
finished = QtCore.pyqtSignal()
update_progress = QtCore.pyqtSignal()
results = QtCore.pyqtSignal(dict) # set the type of object you are sending
def __init__(self):
super().__init__()
self.count = 0
def run(self):
# search database here and emit update_progress when appropriate
while self.count <= 100:
self.update_progress.emit()
self.count += 1
time.sleep(0.02)
self.send_results() # when done, send the results
self.finished.emit()
def send_results(self):
results = {'one': 'Result One', 'two': 'Result Two', 'three': 'Result Three'}
self.results.emit(results)
推荐阅读
- r - 用于拆分具有多个捕获组的单词列表的正则表达式
- python - 如何在正在运行的 docker 容器中执行 python 脚本?
- r - 如何在 R 中解析这种数据类型?
- c++ - 在 X64 Linux 中从用户级别使用 GS 寄存器
- javascript - 使用 append() 函数时重复的内容
- android - 什么是 gradlew 任务 assembleAndroidTest 以及 Android 中的测试应用程序是什么?
- java - 如何给 groovy 闭包参数一个类型
- reactjs - 使用 keyExtractor,仍然收到我的物品没有钥匙的警告
- java - 如何使用 Java 与 Eclipse 和 Maven 创建 Azure Web 作业?
- html - 在 NodeJS 中更改页面标题