ljc*_* 09 7 python pyqt coroutine pyqt5 python-asyncio
是否可以让 UDP 服务器作为异步函数运行,接收数据,然后将其传递给也作为异步函数运行的 (PyQt5) 小部件?
这个想法是,当进入服务器的数据更新时,它也会更新小部件。
我已经有一个简单的 UDP 服务器和一个(PyQt5)小部件,它们独立工作正常,但我正在努力尝试将它们组合起来并保持它们异步运行并交换数据(服务器将数据传输到小部件)
[更新]
下面是我正在尝试的一个小部件
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow
import asyncio
class Speedometer(QMainWindow):
angleChanged = QtCore.pyqtSignal(float)
def __init__(self, parent = None):
QtWidgets.QWidget.__init__(self, parent)
self._angle = 0.0
self._margins = 20
self._pointText = {0: "40", 30: "50", 60: "60", 90: "70", 120: "80",
150:"" , 180: "", 210: "",
240: "0", 270: "10", 300: "20", 330: "30", 360: ""}
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.fillRect(event.rect(), self.palette().brush(QtGui.QPalette.Window))
self.drawMarkings(painter)
self.drawNeedle(painter)
painter.end()
def drawMarkings(self, painter):
painter.save()
painter.translate(self.width()/2, self.height()/2)
scale = min((self.width() - self._margins)/120.0,
(self.height() - self._margins)/60.0)
painter.scale(scale, scale)
font = QtGui.QFont(self.font())
font.setPixelSize(10)
metrics = QtGui.QFontMetricsF(font)
painter.setFont(font)
painter.setPen(self.palette().color(QtGui.QPalette.Shadow))
i = 0
while i < 360:
if i % 30 == 0 and (i <150 or i > 210):
painter.drawLine(0, -40, 0, -50)
painter.drawText(-metrics.width(self._pointText[i])/2.0, -52,
self._pointText[i])
elif i <135 or i > 225:
painter.drawLine(0, -45, 0, -50)
painter.rotate(15)
i += 15
painter.restore()
def drawNeedle(self, painter):
painter.save()
painter.translate(self.width()/2, self.height()/1.5)
painter.rotate(self._angle)
scale = min((self.width() - self._margins)/120.0,
(self.height() - self._margins)/120.0)
painter.scale(scale, scale)
painter.setPen(QtCore.Qt.NoPen)
painter.setBrush(self.palette().brush(QtGui.QPalette.Shadow))
painter.drawPolygon(
QtGui.QPolygon([QtCore.QPoint(-10, 0), QtCore.QPoint(0, -45), QtCore.QPoint(10, 0),
QtCore.QPoint(0, 5), QtCore.QPoint(-10, 0)])
)
painter.setBrush(self.palette().brush(QtGui.QPalette.Highlight))
painter.drawPolygon(
QtGui.QPolygon([QtCore.QPoint(-5, -25), QtCore.QPoint(0, -45), QtCore.QPoint(5, -25),
QtCore.QPoint(0, -30), QtCore.QPoint(-5, -25)])
)
painter.restore()
def sizeHint(self):
return QtCore.QSize(150, 150)
def angle(self):
return self._angle
# @pyqtSlot(float)
def setAngle(self, angle):
if angle != self._angle:
self._angle = angle
self.angleChanged.emit(angle)
self.update()
angle = QtCore.pyqtProperty(float, angle, setAngle)
@staticmethod
def mainLoopSpd():
while True:
app = QApplication(sys.argv)
window = QtWidgets.QWidget()
spd = Speedometer()
spinBox = QtWidgets.QSpinBox()
#spd.setAngle(100)
spinBox.setRange(0, 359)
spinBox.valueChanged.connect(spd.setAngle)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(spd)
layout.addWidget(spinBox)
window.setLayout(layout)
window.show()
app.exec_()
#await asyncio.sleep(1)
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)
下面是 UDP 套接字端的实现,它也在控制台中打印值
import socket
class UDPserver:
def __init__(self, parent= None):
self.localIP = "127.0.0.1"
self.localPort = 20002
self.bufferSize = 1024
self.UDPServerSocket = socket.socket(family= socket.AF_INET, type=socket.SOCK_DGRAM) # Create a socket object
self.UDPServerSocket.bind((self.localIP, self.localPort))
print("UDP server up and listening")
self.counter= 1
@staticmethod
def mainLoopUDPserver():
serv= UDPserver()
#while(True):
bytesAddressPair = serv.UDPServerSocket.recvfrom(serv.bufferSize) # Receive data from the socket
message = bytesAddressPair[0] # The output of the recvfrom() function is a 2-element array
# First element is the message
address = bytesAddressPair[1] # Second element is the address of the sender
newMsg= "{}".format(message)
serv.counter=serv.counter+1
NumMssgReceived = "#Num of Mssg Received:{}".format(serv.counter)
newMsg= newMsg.replace("'","")
newMsg= newMsg.replace("b","")
newMsg= newMsg.split("/")
eastCoord= float(newMsg[0])
northCoord= float(newMsg[1])
vehSpeed= float(newMsg[2])
agYaw= float(newMsg[3])
eastCoordStr="East Coordinate:{}".format(newMsg[0])
northCoordStr="North Coordinate:{}".format(newMsg[1])
vehSpeedStr= "Vehicle Speed:{}".format(newMsg[2])
agYawStr="Yaw Angle:{}".format(newMsg[3])
print(NumMssgReceived)
print(vehSpeedStr)
Run Code Online (Sandbox Code Playgroud)
下面是调用它们的主要函数
from speedometer import Speedometer
import asyncio
from pyServer import UDPserver
class mainApp:
#vel = 0
def __init__(self):
self.velo = 0
self.queue= asyncio.Queue(0)
async def server(self):
while True:
self.velo= UDPserver.mainLoopUDPserver()
print("THIS IS VELO{}",self.velo)
#await self.queue.put(self.velo)
#vel= await self.queue.get()
#return vel
#print("ASSDASDSADSD{}",vel)
await asyncio.sleep(0)
#print("HI, vel Received={}",self.veloc)
#return velo
async def widget(self):
while True:
#vel = await self.queue.get()
#print("Hola xDDDDDDD", vel)
print(">>>>>>>>>>>>>>>NextIteration>>>>>>>>>>>>>>")
await Speedometer.mainLoopSpd()
await asyncio.sleep(0)
loop= asyncio.get_event_loop()
mApp= mainApp()
loop.create_task(mApp.server())
loop.create_task(mApp.widget())
loop.run_forever()
Run Code Online (Sandbox Code Playgroud)
因此,当我运行它时,它会监听服务器,一旦我开始通过 UDP 发送数据,它就会收到第一条数据并打开运行良好的小部件,但它会使服务器停止,它不会收到任何数据数据不再了。
正如您在评论中看到的,我也一直在尝试使用 Asyncio 队列,但我还没有真正得到任何东西。
我的理想场景是服务器接收数据并将其传递给小部件,以便它随传入数据进行更新,但现在我只希望它们都独立工作。
谢谢
应该清楚的是,您的 UDP 服务器不是异步运行的。
asyncio 的逻辑是一切都使用 eventloop 作为基础,而默认情况下 Qt 不支持它,所以你必须使用qasync
( python -m pip install qasync
) 和asyncqt
( python -m pip install asyncqt
)等库
综合以上情况,解决方案是:
车速表.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Speedometer(QtWidgets.QWidget):
angleChanged = QtCore.pyqtSignal(float)
def __init__(self, parent=None):
super().__init__(parent)
self._angle = 0.0
self._margins = 20
self._pointText = {
0: "40",
30: "50",
60: "60",
90: "70",
120: "80",
150: "",
180: "",
210: "",
240: "0",
270: "10",
300: "20",
330: "30",
360: "",
}
def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.fillRect(event.rect(), self.palette().brush(QtGui.QPalette.Window))
self.drawMarkings(painter)
self.drawNeedle(painter)
def drawMarkings(self, painter):
painter.save()
painter.translate(self.width() / 2, self.height() / 2)
scale = min(
(self.width() - self._margins) / 120.0,
(self.height() - self._margins) / 60.0,
)
painter.scale(scale, scale)
font = QtGui.QFont(self.font())
font.setPixelSize(10)
metrics = QtGui.QFontMetricsF(font)
painter.setFont(font)
painter.setPen(self.palette().color(QtGui.QPalette.Shadow))
i = 0
while i < 360:
if i % 30 == 0 and (i < 150 or i > 210):
painter.drawLine(0, -40, 0, -50)
painter.drawText(
-metrics.width(self._pointText[i]) / 2.0, -52, self._pointText[i]
)
elif i < 135 or i > 225:
painter.drawLine(0, -45, 0, -50)
painter.rotate(15)
i += 15
painter.restore()
def drawNeedle(self, painter):
painter.save()
painter.translate(self.width() / 2, self.height() / 1.5)
painter.rotate(self._angle)
scale = min(
(self.width() - self._margins) / 120.0,
(self.height() - self._margins) / 120.0,
)
painter.scale(scale, scale)
painter.setPen(QtCore.Qt.NoPen)
painter.setBrush(self.palette().brush(QtGui.QPalette.Shadow))
painter.drawPolygon(
QtGui.QPolygon(
[
QtCore.QPoint(-10, 0),
QtCore.QPoint(0, -45),
QtCore.QPoint(10, 0),
QtCore.QPoint(0, 5),
QtCore.QPoint(-10, 0),
]
)
)
painter.setBrush(self.palette().brush(QtGui.QPalette.Highlight))
painter.drawPolygon(
QtGui.QPolygon(
[
QtCore.QPoint(-5, -25),
QtCore.QPoint(0, -45),
QtCore.QPoint(5, -25),
QtCore.QPoint(0, -30),
QtCore.QPoint(-5, -25),
]
)
)
painter.restore()
def sizeHint(self):
return QtCore.QSize(150, 150)
def angle(self):
return self._angle
@QtCore.pyqtSlot(float)
def setAngle(self, angle):
if angle != self._angle:
self._angle = angle
self.angleChanged.emit(angle)
self.update()
angle = QtCore.pyqtProperty(float, angle, setAngle)
if __name__ == "__main__":
import sys
import asyncio
from asyncqt import QEventLoop
app = QtWidgets.QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)
with loop:
w = Speedometer()
w.angle = 10
w.show()
loop.run_forever()
Run Code Online (Sandbox Code Playgroud)
服务器.py
import asyncio
from PyQt5 import QtCore
class UDPserver(QtCore.QObject):
dataChanged = QtCore.pyqtSignal(float, float, float, float)
def __init__(self, parent=None):
super().__init__(parent)
self._transport = None
self._counter_message = 0
@property
def transport(self):
return self._transport
def connection_made(self, transport):
self._transport = transport
def datagram_received(self, data, addr):
self._counter_message += 1
print("#Num of Mssg Received: {}".format(self._counter_message))
message = data.decode()
east_coord_str, north_coord_str, veh_speed_str, ag_yaw_str, *_ = message.split(
"/"
)
try:
east_coord = float(east_coord_str)
north_coord = float(north_coord_str)
veh_speed = float(veh_speed_str)
ag_yaw = float(ag_yaw_str)
self.dataChanged.emit(east_coord, north_coord, veh_speed, ag_yaw)
except ValueError as e:
print(e)
Run Code Online (Sandbox Code Playgroud)
主要.py
import sys
import asyncio
from PyQt5 import QtCore, QtWidgets
from asyncqt import QEventLoop
from speedometer import Speedometer
from server import UDPserver
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.spd = Speedometer()
self.spinBox = QtWidgets.QSpinBox()
self.spinBox.setRange(0, 359)
self.spinBox.valueChanged.connect(lambda value: self.spd.setAngle(value))
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.spd)
layout.addWidget(self.spinBox)
@QtCore.pyqtSlot(float, float, float, float)
def set_data(self, east_coord, north_coord, veh_speed, ag_yaw):
print(east_coord, north_coord, veh_speed, ag_yaw)
self.spd.setAngle(veh_speed)
async def create_server(loop):
return await loop.create_datagram_endpoint(
lambda: UDPserver(), local_addr=("127.0.0.1", 20002)
)
def main():
app = QtWidgets.QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)
w = Widget()
w.resize(640, 480)
w.show()
with loop:
_, protocol = loop.run_until_complete(create_server(loop))
protocol.dataChanged.connect(w.set_data)
loop.run_forever()
if __name__ == "__main__":
main()
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
14920 次 |
最近记录: |