D
D
dibanshee2021-01-05 23:25:45
PyQt
dibanshee, 2021-01-05 23:25:45

How to do in python and PyQt5 in such a way that when working with zmq or sockets there would be no "blocking" of the window?

I'm just starting to learn PyQT and really like it. I'm trying to write a program, just for the sake of self-development, listening to sockets. Those. the given host and port are entered in the window, then the start server button is pressed, which immediately becomes inactive, and the stop server becomes active. Everything would be fine until I start listening to the socket through while True, the window is immediately blocked. Can anyone suggest how this is done?

I apologize if it's too scattered over the files, it's somehow more convenient for me this way.

main.py

import sys
import argparse
import logging
from PyQt5.QtWidgets import QApplication

from ui import App
from db import Database
from ZMQ_server import ZServer

LOGGER = logging.getLogger(__name__)

db_name = 'proba.db'
app_args = []


def parse_arg(args):
    parser = argparse.ArgumentParser()
    parser.add_argument('-v', '--verbose',
                        action='count',
                        default=1,
                        help='Verbose level')
    return parser.parse_args(args)


def init_logger(level):
    logger = logging.getLogger()
    logger.addHandler(logging.StreamHandler())
    if level == 1:
        logger.setLevel(logging.INFO)
    elif level == 2:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.WARNING)


def main():
    try:
        options = parse_arg(sys.argv[1:])
        init_logger(options.verbose)
        LOGGER.info('Starting...')

        try:
            # Database
            database = Database(db_name)
            database.db_connect()
            database.db_tables_creation()
            LOGGER.info('DB connected')

            # Server
            server = ZServer()

            # Window
            app = QApplication(app_args)
            window = App(database, server)
            window.initUI()
            sys.exit(app.exec_())

        except Exception as err:
            LOGGER.warning('Error at init %s', err)

    except KeyboardInterrupt:
        sys.exit(0)

    except Exception as err:  # pylint: disable=broad-except
        LOGGER.exception(err)
        sys.exit(1)

    finally:
        try:
            database.db_disconnect()
            LOGGER.info('DB connection closed')
            server.stop()
            LOGGER.info('Server is stopped')
        except UnboundLocalError:
            pass
        LOGGER.info('Stopped correctly')

if __name__ == '__main__':
    main()


I won’t throw db.py, it’s just creating databases and tables

ZMQ_server.py
import asyncio
import zmq
import zmq.asyncio
import logging

ctx = zmq.asyncio.Context()
LOGGER = logging.getLogger(__name__)


class ZServer(object):

    def __init__(self):
        self.socket = None

    def start(self, protocol, host, port):
        address = protocol + '://' + host + ':' + port
        try:
            self.socket = ctx.socket(zmq.REP)
            self.socket.bind(address)
            if self.socket.closed is not True:
                LOGGER.info('Server ready at address %s', address)
                # loop = asyncio.get_event_loop() # скрыл это пока что чтоб не ждать ответа
                # loop.run_until_complete(self.run())
        except Exception as err:
            LOGGER.warning('Unable create server due to %s', err)

    def run(self):
        # while True:  # Так же пока скрыл
        #     msg = yield from self.socket.recv()
        #     if msg:
        #         LOGGER.info('MSG %s', msg.decode('ascii'))
        pass

    def stop(self):
        try:
            self.socket.close()
            if self.socket.closed is True:
                LOGGER.info('Server closed')
        except Exception as err:
            LOGGER.warning('Unable disconnect server due to %s', err)


Well, PyQT ui.py itself, main_window is just a set of widgets, etc. from the designer
from PyQt5.QtWidgets import QWidget, QMainWindow
from main_window import Ui_MainWindow


class App(object):

    def __init__(self, database, server):
        self.window = QMainWindow()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self.window)
        self.database = database
        self.server = server
        self.ui.serverStopButton.setDisabled(True)
        self.ui.serverStartButton.clicked.connect(self.start_server)
        self.ui.serverStopButton.clicked.connect(self.stop_server)

    def initUI(self):
        self.window.setWindowTitle('Nova FX advisor')
        self.window.show()

    def start_server(self):
        host_input = self.ui.serverHostInput.text()
        port_input = self.ui.serverPortInput.text()
        host = host_input if host_input else '127.0.0.1'
        port = port_input if port_input else '5599'
        self.server.start('tcp', host, port)
        self.ui.serverStartButton.setDisabled(True)
        self.ui.serverStopButton.setDisabled(False)

    def stop_server(self):
        self.server.stop()
        self.ui.serverStartButton.setDisabled(False)
        self.ui.serverStopButton.setDisabled(True)

Answer the question

In order to leave comments, you need to log in

1 answer(s)
B
bbkmzzzz, 2021-01-06
@dibanshee

The Qt event loop must also work somehow)
1 - move the server to a separate QThread
2 - Use Qt

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question