0

I'm trying to create a simple GUI app in python that runs a webserver, but I don't know how to start the server without blocking the UI. I was trying to start it on a new thread, but it still blocks the UI.

Here is a sample of my code:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QPushButton
from PyQt5.QtCore import pyqtSlot
from aiohttp import web
import json
from threading import Thread


class App(QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'Window Application'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        # Create a button
        self.btn_startServer = QPushButton('Start Server', self)
        self.btn_startServer.setToolTip('This is an example button')
        self.btn_startServer.move(500, 50)
        self.btn_startServer.clicked.connect(self.on_click_startWebServer)

        # Create a button
        self.btn_stopServer = QPushButton('Stop Server', self)
        self.btn_stopServer.setToolTip('This is an example button')
        self.btn_stopServer.move(500, 80)
        self.btn_stopServer.clicked.connect(self.on_click_stopWebServer)

        # Create textbox
        self.textbox = QLineEdit(self)
        self.textbox.move(20, 20)
        self.textbox.resize(120, 20)

        self.show()

    async def handle(request):
        response_obj = {'status': 'success'}
        return web.Response(text=json.dumps(response_obj))

    @pyqtSlot()
    def on_click_startWebServer(self):
        app = web.Application()
        app.router.add_get('/', self.handle)

        self.thread = Thread(target=web.run_app(app))
        self.thread.start()
        print("Webserver started")

    @pyqtSlot()
    def on_click_stopWebServer(self):
        # Close the server
        self.thread.join()
        print("Webserver stopped")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

What am I doing wrong? Is there any solution to this problem?

Razero
  • 321
  • 1
  • 4
  • 16
  • 1
    change `Thread(target=web.run_app(app))` to `Thread(target=web.run_app, args=(app,))` – eyllanesc May 21 '19 at 16:44
  • 1
    threading.Thread() expects a callable, and if this needs arguments you must pass it through args and kwargs, but instead you are invoking the callable in the main thread – eyllanesc May 21 '19 at 16:50

1 Answers1

1

Replace default asyncio loop with qualmash.

Qualmash is a library that provides asyncio-compatible loop but operates on top of Qt facilities.

Installation is pretty easy. Instead of

app = QApplication(sys.argv)
app.exec_()

do

app = QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)  # NEW must set the event loop
loop.run_until_complete(main())
Andrew Svetlov
  • 16,730
  • 8
  • 66
  • 69