Отличное решение! Спасибо!
тоящее время я ищу способ создания настольных приложений с графическим интерфейсом на Python и HTML / CSS / JS с использованием PyQt5QWebEngineView.
В моем небольшом демонстрационном приложении я используюQWebChannel опубликовать PythonQObject на стороне JavaScript, так что данные могут быть переданы и передавать туда и обратно. Совместное использование и подключение слотов и сигналов пока работает нормально.
У меня трудности, хотя с синхронизацией простых (свойства) значений. Из того, что я прочитал, путь заключается в том, чтобы реализовать pyqtProperty в совместно используемом объекте QObject с помощью декорированных функций получения и установки с дополнительным сигналом, генерируемым в установщике, который используется для уведомления JavaScript при изменении значения. Код ниже показывает, что и до сих пор это работает нормально:
import sys
from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebChannel import QWebChannel
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
class HelloWorldHtmlApp(QWebEngineView):
html = '''
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script>
var backend;
new QWebChannel(qt.webChannelTransport, function (channel) {
backend = channel.objects.backend;
});
</script>
</head>
<body> <h2>HTML loaded.</h2> </body>
</html>
'''
def __init__(self):
super().__init__()
# setup a page with my html
my_page = QWebEnginePage(self)
my_page.setHtml(self.html)
self.setPage(my_page)
# setup channel
self.channel = QWebChannel()
self.backend = self.Backend(self)
self.channel.registerObject('backend', self.backend)
self.page().setWebChannel(self.channel)
class Backend(QObject):
""" Container for stuff visible to the JavaScript side. """
foo_changed = pyqtSignal(str)
def __init__(self, htmlapp):
super().__init__()
self.htmlapp = htmlapp
self._foo = "Hello World"
@pyqtSlot()
def debug(self):
self.foo = "I modified foo!"
@pyqtProperty(str, notify=foo_changed)
def foo(self):
return self._foo
@foo.setter
def foo(self, new_foo):
self._foo = new_foo
self.foo_changed.emit(new_foo)
if __name__ == "__main__":
app = QApplication.instance() or QApplication(sys.argv)
view = HelloWorldHtmlApp()
view.show()
app.exec_()
Начиная это с подключенным отладчиком, я могу вызватьbackend.debug()
слот в консоли JavaScript, что приводит к значениюbackend.foo
будучи "я изменил Foo!" впоследствии это означает, что код Python успешно изменил переменную JavaScript.
Это довольно утомительно, хотя. Для каждого значения, которым я хотел бы поделиться, я должен был бы
создать внутреннюю переменную (здесьself._foo
)создать функцию получениясоздать функцию установкисоздать сигнал вQObject
телоиспускать этот сигнал явно в функции установщикаЕсть ли более простой способ добиться этого? В идеале какое-то однострочное объявление? Может быть, с помощью класса или функции, чтобы упаковать все это? Как бы мне связать это сQObject
позже? Я думаю о чем-то вроде
# in __init__
self.foo = SyncedProperty(str)
Это возможно? Спасибо за ваши идеи!