需要建议以保持 GUI 响应 [英] Need advice to keep GUI responsive

查看:45
本文介绍了需要建议以保持 GUI 响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上,我拥有的是一个带有一些 QLineEdits 的 GUI、一个搜索按钮"和一个表格.你点击按钮,一个名为 DataGrabber 的类在数据库中搜索数据,处理它们,相应地返回一个包含字典的列表,其中填充了表格.这些搜索可能需要一段时间,我需要保持我的 GUI 响应.此外,我希望状态栏消息在搜索进行时发生变化(类似于正在搜索."->正在搜索..."->正在搜索...",功能在这里并不重要,它只是关于了解我如何正确处理这个问题).

Basically, what I have is a GUI with some QLineEdits, a "search button" and a table. You hit the button and a class called DataGrabber searches a database for data, processes them, returns a list with dictionaries with which the table is filled, accordingly. These searches can take a while and I need to keep my GUI responsive. Also, I want the statusbar message to change as long as the search is going on (something like "Searching." -> "Searching.." -> "Searching...", the functionality is not rly important here, it's just about understanding how I can handle this properly).

我从线程化开始,并在处理搜索的线程和处理状态栏的函数之间创建了一个队列,以了解搜索何时完成.但这似乎真的很愚蠢.特别是因为 Qt 提供了各种工具,例如 QThread 和 Signals.但我现在很迷茫.当执行像数据库搜索这样耗时的操作时,处理响应的最佳方法是什么?告诉主/子线程搜索已完成的最佳方法是什么?

I started with threading everything and created a queue between the thread that handles the search and the function that handles the statusbar, to know when the search is done. But that seems really goofy. Especially since Qt provides all kind of tools, like QThread and Signals. But I'm rly lost right now. What would be the best way to handle the responsiveness when having such a time-consuming action like a database search? And what would be the best way to tell the main/child thread that the search is finished?

这是我现在所拥有的缩小版:

Here is a reduced version of what I have right now:

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.

This can be handled with signals. You can use signals to send the results to the GUI and to update the GUI of the progress.

这是一个带有进度条和状态标签的快速实现示例.如果您愿意,可以将它们包含在状态栏中:

Here is a quick example of the implementation with a progress bar and status label. These can be included in a status bar if you would like:

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)

这篇关于需要建议以保持 GUI 响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆