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

时间:2019-06-13 16:19:05

标签: python websocket pyqt python-asyncio

我有一个运行在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()

下面是我在应用程序中显示的一些gui


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


告诉我一些提示,以在同一事件循环中运行两个任务。

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

谢谢。

1 个答案:

答案 0 :(得分:1)

app.exec()运行QT的事件循环,因为您必须使用run_forever()运行asyncio的事件循环,所以您无法执行此操作。

幸运的是,Qt提供了processEvents,您可以在asyncio的事件循环中定期调用debug mode,以使Qt正常工作:

  

您可以在程序繁忙时偶尔调用此函数   执行较长的操作(例如,复制文件)。


按照以下方式删除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()

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

好主意是在测试过程中启用Fiddle,以确保一切正常。