Запустите сервер Qt и Websockets в одном цикле событий - PullRequest
2 голосов
/ 13 июня 2019

У меня есть сервер websockets, работающий на python, и я также хотел показать некоторый графический интерфейс с использованием PyQt5. И 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()


подайте мне немного света, чтобы выполнить обе задачи в одном цикле событий.

примечание: я определенно хочу их в одной теме.

Заранее спасибо.

1 Ответ

1 голос
/ 15 июня 2019

app.exec() запускает цикл событий QT, чего вы не можете сделать, так как вам нужно запустить цикл событий asyncio с run_forever().

К счастью, Qt предоставляет processEvents , которые вы можете периодически вызывать вместе с циклом событий asyncio, чтобы заставить 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()

Я не проверял, но я полагаю, что это должно работать.

Хорошая идея - включить режим отладки во время тестирования, чтобы убедиться, что все в порядке.

...