Нужен совет, чтобы сохранить отзывчивость GUI - PullRequest
0 голосов
/ 05 июня 2018

По сути, у меня есть графический интерфейс с некоторыми QLineEdits, «кнопкой поиска» и таблицей.Вы нажимаете кнопку, и класс DataGrabber ищет в базе данных данные, обрабатывает их, возвращает список со словарями, которыми заполнена таблица, соответственно.Эти поиски могут занять некоторое время, и мне нужно, чтобы мой графический интерфейс реагировал.Кроме того, я хочу, чтобы сообщение в строке состояния менялось до тех пор, пока идет поиск (что-то вроде «Поиск» -> «Поиск ..» -> «Поиск ...», функциональность здесь не очень важна, простоо понимании того, как я могу справиться с этим должным образом).

Я начал с создания потока всего и создал очередь между потоком, который обрабатывает поиск, и функцией, которая обрабатывает строку состояния, чтобы узнать, когда поиск будет завершен.Но это кажется действительно глупым.Тем более, что 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 голосов
/ 05 июня 2018

Это может быть обработано с помощью сигналов.Вы можете использовать сигналы для отправки результатов в 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)
...