需要建议以保持GUI响应

时间:2018-06-05 17:11:21

标签: python pyqt pyqt5 qthread

基本上,我所拥有的是带有一些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

1 个答案:

答案 0 :(得分:0)

这可以通过信号处理。您可以使用信号将结果发送到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)