Skip to main content
 首页 » 编程设计

python之在同一事件循环中运行 Qt 和 Websockets 服务器

2024年11月24日34jillzhang

我有一个在 python 中运行的 websockets 服务器,并且还想使用 PyQt5 显示一些 GUI。 websockets 和 PyQt5 都必须在同一个线程中永远运行,但我不确定我该怎么做。

下面是我用来创建和启动服务器的代码。

import websockets 
import asyncio 
 
 
async def server_extentions(websocket, path): 
    try: 
        while (True): 
            request = await websocket.recv() 
            response = "blabla" 
            await websocket.send(response) 
    except websockets.ConnectionClosed as exp: 
        print("connection closed.") 
 
evt_loop = asyncio.get_event_loop() 
start_server = websockets.serve(server_extentions, '127.0.0.1', 5588, loop=evt_loop) 
try: 
    evt_loop.run_until_complete(start_server) 
    evt_loop.run_forever() 
finally: 
    evt_loop.run_until_complete(evt_loop.shutdown_asyncgens()) 
    evt_loop.close() 
 

下面是我在我的应用程序中显示的一些图形用户界面

 
from PyQt5.QtWidgets import QProgressBar, QWidget, QLabel, QApplication 
from PyQt5 import QtCore 
 
 
class DownloadProgress(QWidget): 
 
    def __init__(self, parent=None): 
        super().__init__(parent) 
        self.init_ui() 
 
    def init_ui(self): 
        self.progress_bar = QProgressBar(self) 
        self.progress_bar.setGeometry(30, 40, 200, 25) 
        self.progress_bar.setValue(0) 
 
        self.label_status_msg = QLabel() 
        self.label_status_msg.setAlignment(QtCore.Qt.AlignCenter) 
        self.label_status_msg.setGeometry(30, 80, 200, 25) 
        self.label_status_msg.setText("starting") 
 
        self.setGeometry(300, 300, 280, 170) 
        self.setWindowTitle('Bla Bla') 
 
    def set_progress_value(self, value: int): 
        self.progress_bar.setValue(value) 
 
    def set_status_msg(self, msg: str): 
        self.label_status_msg.setText(msg) 
 
app = QApplication([]) 
 
 
dp = DownloadProgress() 
dp.set_status_msg("download in progress.") 
dp.set_progress_value(20) 
dp.show() 
 
app.exec() 
 
 

给我一​​些光照,在同一个事件循环中运行这两个任务。

注意:我绝对希望它们在同一个线程中。

提前致谢。

请您参考如下方法:

app.exec() 运行 QT 的事件循环,您不能这样做,因为您必须使用 run_forever() 运行 asyncio 的事件循环。

幸运的是Qt提供了processEvents您可以定期调用它与 asyncio 的事件循环一起使 Qt 工作:

You can call this function occasionally when your program is busy performing a long operation (e.g. copying a file).


删除 app.exec() 并按照以下方式更改代码:

app = QApplication([]) 
 
async def qt_loop():     
    while True: 
        app.processEvents()     # allow Qt loop to work a bit 
        await asyncio.sleep(0)  # allow asyncio loop to work a bit 
 
qt_loop_task = asyncio.ensure_future(qt_loop())  # task will work alongside with the server 
 
 
evt_loop = asyncio.get_event_loop()     
start_server = websockets.serve(server_extentions, '127.0.0.1', 5588, loop=evt_loop) 
try: 
    evt_loop.run_until_complete(start_server) 
    evt_loop.run_forever() 
finally: 
    # I'll leave to you job to kill qt_loop_task  
    # see: https://stackoverflow.com/a/37345564/1113207 
    evt_loop.run_until_complete(evt_loop.shutdown_asyncgens()) 
    evt_loop.close() 

我没有检查它,但我认为它应该可以工作。

好主意是启用debug mode同时进行测试以确保一切正常。