xmlprc внутри цикла событий Qt (PyQt)? - PullRequest
1 голос
/ 27 марта 2019

Я хочу использовать сервер xmlprc вместе с приложением Qt, в этом случае веб-движок Qt, чтобы клиент xmlrpc мог отправлять ему команды. Я должен сделать с существующим клиентом.

У нас здесь два цикла событий. Запуск exec_() Qt блокирует, запуск serve_forever() xmlrpc блокирует.

Сначала мне стало интересно, знаете ли вы о библиотеке xmlrpc для Python, которая прекрасно интегрируется с циклом событий Qt. Так что все будет работать из коробки.


Я не нашел ни одного, поэтому я попытался немного запустить rpc-сервер внутри потока. В основном это работает, но не может взаимодействовать с виджетом Qt. Как мы можем это сделать?

ниже с pyqt5 == 5.12 и PyQtWebEngine.

from PyQt5.QtCore import QUrl from PyQt5.QtCore import QThread
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QWidget

from xmlrpc.server import SimpleXMLRPCServer

# Qt
URL_START = "http://ddg.gg"

app = QApplication([])
window = QWidget()
layout = QVBoxLayout()

webview = QWebEngineView()
webview.setUrl(QUrl(URL_START))

minibuffer = QWebEngineView()
mb_prompt = """
<html>
<div> hello minibuffer </div>
</html>
"""
minibuffer.setHtml(mb_prompt)

layout.addWidget(webview)
layout.addWidget(minibuffer)

window.setWindowTitle("My browser")
window.setLayout(layout)
window.show()

# xmlrpc
def hello(name):
    return "hello " + name

def set_minibuffer(name):
    return minibuffer.setHtml(mb_prompt.replace("minibuffer", name))


class RPCThread(QThread):
    def run(self):
        # sleep a little bit to make sure QApplication is running.
        self.sleep(1)
        print("--- starting server…")
        self.rpcserver = SimpleXMLRPCServer(("localhost", 8282))
        self.rpcserver.register_function(hello)
        self.rpcserver.register_function(set_minibuffer)

        self.rpcserver.serve_forever()

class RPCWidget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.thread = RPCThread(self)
        self.thread.start()

rpcwidget = RPCWidget()
rpcwidget.show()

# Qt main loop.
print("--- Qt loop")
app.exec_()

От клиента:

from xmlrpc.client import ServerProxy
client = ServerProxy("http://localhost:8282"
print(client.hello("me"))  # OK
# Trying to set the web engine's html content:
print(client.set_minibuffer("me")  # fails

это не с

--- starting server…
127.0.0.1 - - [27/Mar/2019 16:52:01] "POST /RPC2 HTTP/1.1" 200 -
Received signal 11 SEGV_MAPERR 000000000000
#0 0x7f9b5bf3e8bf <unknown>
#1 0x7f9b5bf3ecbb <unknown>
#2 0x7f9b5bf3f33e <unknown>
#3 0x7f9b6667ef20 <unknown>
#4 0x7f9b5b9f3515 <unknown>
#5 0x7f9b5b9f37eb <unknown>
#6 0x7f9b5b9f3b79 <unknown>
#7 0x7f9b5a4731c0 QtWebEngineCore::WebContentsAdapter::setContent()
#8 0x7f9b610c7bf5 QWebEnginePage::setHtml()
#9 0x7f9b612fb824 meth_QWebEngineView_setHtml
#10 0x0000005030d5 <unknown>
#11 0x000000506859 _PyEval_EvalFrameDefault
#12 0x000000504c28 <unknown>
#13 0x00000058644b <unknown>
#14 0x00000059ebbe PyObject_Call
#15 0x000000507c17 _PyEval_EvalFrameDefault
[…]

1 Ответ

1 голос
/ 27 марта 2019

У вас есть 2 ошибки:

Учитывая вышеизложенное,решение:

from functools import partial

# ...

from PyQt5.QtCore import QTimer

# ...

def set_minibuffer(name):
    html = mb_prompt.replace("minibuffer", name)
    wrapper = partial(minibuffer.setHtml, html)
    QTimer.singleShot(0, wrapper)
    return html


class RPCThread(QThread):
    def run(self):
        # sleep a little bit to make sure QApplication is running.
        self.sleep(1)
        print("--- starting server…")
        self.rpcserver = SimpleXMLRPCServer(("localhost", 8282), allow_none=True)
        self.rpcserver.register_function(hello)
        self.rpcserver.register_function(set_minibuffer)

        self.rpcserver.serve_forever()

# ...
...