Python 如何创建qml对象';"香港地产";“可动态更新”;通过插座连接?

Python 如何创建qml对象';"香港地产";“可动态更新”;通过插座连接?,python,sockets,pyqt,qml,real-time,Python,Sockets,Pyqt,Qml,Real Time,我正在使用PyQt5和Qml创建客户机应用程序。这是我的Qml文件的简化示例: import QtQuick 2.11 import QtQuick.Window 2.2 import QtQuick.Controls 2.2 ApplicationWindow { visible: true width: Screen.width/2 height: Screen.height/2 Rectangle { id: rectangle

我正在使用PyQt5和Qml创建客户机应用程序。这是我的Qml文件的简化示例:

import QtQuick 2.11
import QtQuick.Window 2.2
import QtQuick.Controls 2.2

ApplicationWindow {    
    visible: true
    width: Screen.width/2
    height: Screen.height/2
    Rectangle {
        id: rectangle
        x: 187
        y: 92
        width: 200
        height: 200
        color: "blue"
    }
}
客户端应用程序必须从服务器接收上述矩形的属性。为此,我在“.py”文件中实现了一个套接字连接。client.py文件应该从服务器实时接收信息。我的灵感来自聊天应用程序,我使用(while True:{})循环来实现这一点:

from PyQt5.QtQml import QQmlApplicationEngine, QQmlProperty
from PyQt5.QtQuick import QQuickWindow, QQuickView
from PyQt5.QtCore import QObject, QUrl
from PyQt5.QtWidgets import QApplication
import sys, socket

    def run():
    myApp = QApplication(sys.argv)
    myEngine = QQmlApplicationEngine()

    myEngine.load('mainViewofHoomanApp.qml')
    Win = myEngine.rootObjects()[0]
    rect = Win.findChild(QObject, "rectangle")
    rect.setProperty("height", 10)  # Here I am accessing the properties of the rectangle
    if not myEngine.rootObjects():
        return -1
    return myApp.exec_()


if __name__ == "__main__":
    sys.exit(run())
它是套接字连接的格式:

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Server_IPAddress = '192.168.1.163'
Port = 5000
client_socket.connect((Server_IPAddress,Port))
while True:
    message = client_socket.recv(1024)

    # Then the code extracts the parameters from the message
    # and converts it to integer, and saves it in realT_width variable:

    rect.setProperty("height", realT_width variable)

我对如何将这两个代码合并在一起感到困惑。如果我在写入myApp.exec_389;()命令后调用套接字连接,那么QML文件将不再对参数更改命令作出反应。另一方面,如果我在QML执行之前写入套接字连接,那么while循环将不允许执行后面的代码行。

阻塞任务必须在另一个线程中执行,以便它们不会冻结GUI,在这种情况下,我将假定下一个是服务器,因此您必须首先启动它

server.py

import socket
import time
import random

HOST = '127.0.0.1'
PORT = 65432

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    conn, addr = s.accept()
    with conn:
        print('Connected by', addr)
        while True:
            v = random.randint(10, 100)
            conn.sendall(str(v).encode())
            time.sleep(1.)
import os
import sys
import threading
import socket
from PyQt5 import QtCore, QtGui, QtQml
from functools import partial

class SocketWorker(QtCore.QObject):
    heightChanged = QtCore.pyqtSignal(float)

    @QtCore.pyqtSlot()
    def process(self):
        HOST = '127.0.0.1'  # The server's hostname or IP address
        PORT = 65432        # The port used by the server
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.connect((HOST, PORT))
            while True:
                data = s.recv(1024)
                print('Received', repr(data))
                try:
                    height = float(data)
                    self.heightChanged.emit(height)
                except ValueError:
                    print("error")

class RectangleManager(QtCore.QObject):
    widthChanged = QtCore.pyqtSignal(float)
    heightChanged = QtCore.pyqtSignal(float)

    def __init__(self, parent=None):
        super(RectangleManager, self).__init__(parent)
        self._width = 100
        self._height = 100

    def getWidth(self):
        return self._width

    def setWidth(self, w):
        if self._width != w:
            self._width = w
            self.widthChanged.emit(w)

    def getHeight(self):
        return self._height

    def setHeight(self, h):
        if self._height != h:
            self._height = h
            self.heightChanged.emit(h)

    width = QtCore.pyqtProperty(float, fget=getWidth, fset=setWidth, notify=widthChanged)
    height = QtCore.pyqtProperty(float, fget=getHeight, fset=setHeight, notify=heightChanged)

def run():
    myApp = QtGui.QGuiApplication(sys.argv)
    myEngine = QtQml.QQmlApplicationEngine()
    manager = RectangleManager()
    myEngine.rootContext().setContextProperty("r_manager", manager)
    directory = os.path.dirname(os.path.abspath(__file__))
    myEngine.load(QtCore.QUrl.fromLocalFile(os.path.join(directory, 'main.qml')))

    if not myEngine.rootObjects():
        return -1

    worker = SocketWorker()
    threading.Thread(target=worker.process, daemon=True).start()
    worker.heightChanged.connect(manager.setHeight)
    return myApp.exec_()

if __name__ == "__main__":
    sys.exit(run())
因此,我将创建一个QObject,在这里我可以创建信号,将在辅助线程上运行的套接字获得的信息发送给我发布的处理程序

client.py

import socket
import time
import random

HOST = '127.0.0.1'
PORT = 65432

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    conn, addr = s.accept()
    with conn:
        print('Connected by', addr)
        while True:
            v = random.randint(10, 100)
            conn.sendall(str(v).encode())
            time.sleep(1.)
import os
import sys
import threading
import socket
from PyQt5 import QtCore, QtGui, QtQml
from functools import partial

class SocketWorker(QtCore.QObject):
    heightChanged = QtCore.pyqtSignal(float)

    @QtCore.pyqtSlot()
    def process(self):
        HOST = '127.0.0.1'  # The server's hostname or IP address
        PORT = 65432        # The port used by the server
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.connect((HOST, PORT))
            while True:
                data = s.recv(1024)
                print('Received', repr(data))
                try:
                    height = float(data)
                    self.heightChanged.emit(height)
                except ValueError:
                    print("error")

class RectangleManager(QtCore.QObject):
    widthChanged = QtCore.pyqtSignal(float)
    heightChanged = QtCore.pyqtSignal(float)

    def __init__(self, parent=None):
        super(RectangleManager, self).__init__(parent)
        self._width = 100
        self._height = 100

    def getWidth(self):
        return self._width

    def setWidth(self, w):
        if self._width != w:
            self._width = w
            self.widthChanged.emit(w)

    def getHeight(self):
        return self._height

    def setHeight(self, h):
        if self._height != h:
            self._height = h
            self.heightChanged.emit(h)

    width = QtCore.pyqtProperty(float, fget=getWidth, fset=setWidth, notify=widthChanged)
    height = QtCore.pyqtProperty(float, fget=getHeight, fset=setHeight, notify=heightChanged)

def run():
    myApp = QtGui.QGuiApplication(sys.argv)
    myEngine = QtQml.QQmlApplicationEngine()
    manager = RectangleManager()
    myEngine.rootContext().setContextProperty("r_manager", manager)
    directory = os.path.dirname(os.path.abspath(__file__))
    myEngine.load(QtCore.QUrl.fromLocalFile(os.path.join(directory, 'main.qml')))

    if not myEngine.rootObjects():
        return -1

    worker = SocketWorker()
    threading.Thread(target=worker.process, daemon=True).start()
    worker.heightChanged.connect(manager.setHeight)
    return myApp.exec_()

if __name__ == "__main__":
    sys.exit(run())

main.qml

import QtQuick 2.11
import QtQuick.Window 2.2
import QtQuick.Controls 2.2

ApplicationWindow {    
    visible: true
    width: Screen.width/2
    height: Screen.height/2
    Rectangle {
        id: rectangle
        x: 187
        y: 92
        width: r_manager.width
        height: r_manager.height
        color: "blue"
    }
}

显示您的服务器代码服务器代码是用Csharp编写的,很遗憾,我没有访问权限。但它会发送一个包含所需参数值的字符串。好的,我将发布一个简单的服务器代码来测试我的代码。谢谢你@Eylansec。它们运行时没有任何错误,客户端控制台打印字符串。但是,我想知道为什么它不显示图形窗口。可能它对myApp.exec_389;()命令没有反应?从服务器发送的随机数唯一的修改是我将主机变量更改为:HOST=socket.gethostname()Aha。对不起,我失礼了。我没有修改qml代码。