如何使 qml 对象的属性“可动态更新"通过套接字连接? [英] How to make a qml object's property "dynamically updatable" through socket connection?

查看:35
本文介绍了如何使 qml 对象的属性“可动态更新"通过套接字连接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using PyQt5 and Qml to create a client application. This is a simplified sample of my Qml file:

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:{}) 循环来做到这一点:

The client app must receive the properties of the above rectangle from the server. In order to do that, I implemented a socket connection in the ".py" file. the client.py file ought to receive information in real-time from the server. I was inspired by chat application programs and I used a (while True:{}) loop to do this:

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())

这是socket连接的格式:

And it is the format of socket connection:

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_() 命令后调用套接字连接,那么 QML 文件将不再对参数更改命令做出反应.另一方面,如果我在 QML 执行之前编写套接字连接,那么 while 循环将不允许执行后面的代码行.

I am confused about how to merge these two codes together. If I call the socket connection after write the myApp.exec_() command, then the QML file will no longer react to the parameter change commands. On the other hand, if I write the socket connection before the QML execution, then the while loop will not allow the latter code lines to be executed.

推荐答案

阻塞任务必须在另一个线程中执行,这样它们才不会冻结 GUI,在这种情况下,我将假设下一个是服务器,所以你必须先启动它.

The blocking tasks must be executed in another thread so that they do not freeze the GUI, in this case I will assume that the next one is the server so you must launch it first.

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.)

因此,我将创建一个 QObject,我可以在其中创建信号,这些信号会将在辅助线程上运行的套接字获取的信息发送到我在 我的另一个答案.

So I will create a QObject where I can create the signals that will send the information obtained by the socket that runs on a secondary thread to the handler that I publish in my other answer.

client.py

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())

<小时>

ma​​in.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"
    }
}

这篇关于如何使 qml 对象的属性“可动态更新"通过套接字连接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆