我正在使用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文件应该从服务器实时接收信息。我受到聊天应用程序的启发,并使用了(而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_()命令后调用套接字连接,则QML文件将不再对参数更改命令作出反应。另一方面,如果我在执行QML之前编写套接字连接,则while循环将不允许执行后面的代码行。
答案 0 :(得分:1)
阻塞任务必须在另一个线程中执行,这样它们才不会冻结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.)
因此,我将创建一个QObject,在其中创建信号,该信号会将在次级线程上运行的套接字获取的信息发送到我在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())
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"
}
}