PyQt5 Как обновить GUI, если использоватьубытJavaScript, если Python все еще работает - PullRequest
1 голос
/ 18 октября 2019

Я хотел бы динамически изменить мой графический интерфейс с помощью командыvaluJavaScript

Я заметил, что графический интерфейс обновляется только после завершения работы python. Я создал этот пример кода:

Базовый GUI:

webView = QWebView()
myObj = ExampleClass(webView)
webView.page().mainFrame().addToJavaScriptWindowObject("pyObj", myObj)
webView.setHtml('''
<html>
    <body>
        <div id="content"></div>
        <button onClick="pyObj.example()">start</button>
    </body>
</html>
''')

Python-код для обновления Html GUI:

class ExampleClass(QtCore.QObject):
    def __init__(self, webView):
        super(ExampleClass, self).__init__(webView)
        self.webView = webView

    @QtCore.pyqtSlot()
    def example(self):
        print("start")
        for i in range(0,5):
            print(i)
            self.webView.page().mainFrame().evaluateJavaScript('document.getElementById("content").innerHTML = "'+str(i)+'";')
            time.sleep(1)
            #simulation of a heavy code
            for a in range(0,999):
                for b in range(0,9999):
                    c = a * b;

Цель: после нажатия кнопки «Пуск» Iхотел бы видеть цифры 0 1 2 3 4 последовательно появляются в моем графическом интерфейсе. Текущий результат: после нажатия кнопки «Пуск» в течение N секунд ничего не происходит, а затем появляется число 4

Ответы [ 2 ]

1 голос
/ 18 октября 2019

Как указывает @ gelonida , решение в целом состоит в том, чтобы использовать потоки и уведомлять GUI через сигналы, поэтому мой ответ обеспечивает возможную реализацию.

Для реализации в потокахЦикл for необходимо переставить в последовательных задачах, например, с использованием итераторов, а затем вызвать следующий, когда задача будет выполнена с помощью сигнала. Для трудоемкой задачи в этом случае я создал работника, который живет в другом потоке, и должен быть вызван метод «задача».

import sys
from PyQt5 import QtCore, QtWidgets, QtWebKitWidgets


class Worker(QtCore.QObject):
    finished = QtCore.pyqtSignal()

    @QtCore.pyqtSlot()
    def task(self):
        # simulation of a heavy code
        for a in range(999):
            for b in range(9999):
                c = a * b
        self.finished.emit()


class ExampleClass(QtCore.QObject):
    def __init__(self, webView):
        super(ExampleClass, self).__init__(webView)
        self.webView = webView

        thread = QtCore.QThread(self)
        thread.start()

        self.m_worker = Worker()
        self.m_worker.moveToThread(thread)
        self.m_worker.finished.connect(self.execute)

        self.m_numbers = None

    @QtCore.pyqtSlot()
    def example(self):
        print("example")
        self.m_numbers = iter(range(5))
        self.execute()

    @QtCore.pyqtSlot()
    def execute(self):
        if self.m_numbers is None:
            return
        try:
            i = next(self.m_numbers)
        except StopIteration:
            return
        else:
            self.webView.page().mainFrame().evaluateJavaScript(
                'document.getElementById("content").innerHTML = "{}";'.format(i)
            )
            QtCore.QTimer.singleShot(1000, self.m_worker.task)


if __name__ == "__main__":
    html = """<html>
    <body>
        <div id="content"></div>
        <button onClick="pyObj.example()">start</button>
    </body>
</html>"""

    app = QtWidgets.QApplication(sys.argv)

    view = QtWebKitWidgets.QWebView()
    obj = ExampleClass(view)
    view.page().mainFrame().addToJavaScriptWindowObject("pyObj", obj)
    view.setHtml(html)
    view.resize(640, 480)
    view.show()
    sys.exit(app.exec_())
0 голосов
/ 18 октября 2019

Как правило, в структурах GUI не должно быть кода блокировки, который блокирует запуск цикла обработки событий.

Если вам это действительно нужно, вы должны использовать поток / Qthread и отправлять сигналы для обновления GUI

...