[PyQt] PyQt signals priority

Maurizio Berti maurizio.berti at gmail.com
Mon Apr 1 02:58:00 BST 2019


As far as I know, slots are called in the same sequence they're connected
to.
But I'm afraid that's not the issue here. As pointed out by Phil and the
good and omnipresent eyllanesc on stackoverflow, you're misunderstanding
how signal/slot work: once a signal is fired, the "control" is returned
only as soon as the slot returns it.

If you've a long/heavy process in the slot, the UI won't react until that
process has finished. The only alternative is to use threads (both via
Python or QThreads).

In similar scenarios I usually create a subclassed QObject with a Python
Queue, create a QThread in the parent object, use
object.moveToThread(createdThread), then connect the started() signal of
the thread to the "worker" method of the QObject and finally push
"messages" to the Queue to let the QObject relate with them.

Let's see a very simple example:

from time import sleep
from Queue import Queue
from PyQt5 import QtCore, QtWidgets

class Worker(QtCore.QObject):
    working = QtCore.Signal(bool)

    def __init__(self):
        QtCore.QObject.__init__(self)
        self.queue = Queue()

    def run(self):
        while True:
            res = self.queue.get(True)
            if res is None:
                break
            self.process(*res)
        print('quitting thread')

    def doCommand(self, cmd, *args):
        self.queue.put((cmd, args))

    def process(self, cmd, *args):
        getattr(self, cmd)(*args)

    def myCommand(self, *args):
        print('doing some long process with {}'.format(*args))
        self.working.emit(True)
        sleep(2)
        print('processing complete')
        self.working.emit(False)

    def quit(self):
        self.queue.put(None)


class Test(QtWidgets.QWidget):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        l = QtWidgets.QGridLayout()
        self.setLayout(l)
        b = QtWidgets.QPushButton('cmd')
        l.addWidget(b)

        q = QtWidgets.QPushButton('quit')
        l.addWidget(q)

        self.worker = Worker()
        b.clicked.connect(lambda: self.worker.doCommand('myCommand',
'Argument 1', 'Argument 2'))
        q.clicked.connect(self.quit)
        self.worker.working.connect(b.setDisabled)
        self.workerThread = QtCore.QThread()
        self.worker.moveToThread(self.workerThread)
        self.workerThread.started.connect(self.worker.run)
        self.workerThread.start()

    def quit(self):
        self.worker.quit()
        QtWidgets.QApplication.quit()


This will show a simple window with two buttons. The latter will just quit
the program and the thread with it, which is suggested in most cases
(expecially when using external modules, and if that's the case add a
custom signal and connect it to the quit() slot of the QThread).
The former button will call some virtually long process (taking 2 seconds
in this case) but will not block the user interface; instead, it will send
a "working" signal itself, disabling the button to avoid further processing
(since the process is in the same thread, further clicking will "queue" the
processing) until the process is actually finished.

Some special care is required with the signal connection: signals have to
be connected *before* starting the thread, otherwise they won't be received
by the QObject (since its thread is already running and waiting for the
queue to be filled, thus blocking any other interaction - including signal
connection).
If, for any reason, you need to connect signals afterwards, just use the
timeout argument of the Queue.get() method to a reasonable amount and
customize the "quit" message to put into the queue, leaving the "None"
result to continue the while cycle.

Regards,
Maurizio


Il giorno dom 31 mar 2019 alle ore 18:28 <kristof.mulier at telenet.be> ha
scritto:

> Hi,
> Is there a way to set a priority on programmatically fired pyqt signals?
> I've posted a StackOverflow question about the matter:
>
> https://stackoverflow.com/questions/55442777/pyqt5-how-to-set-a-priority-to-a-pyqtsignal
> Please leave your reply on the StackOverflow page (or send it over mail).
>
> Thank you very much :-)
> Kind greetings,
>
> Kristof Mulier
>
> _______________________________________________
> PyQt mailing list    PyQt at riverbankcomputing.com
> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
>


-- 
È difficile avere una convinzione precisa quando si parla delle ragioni del
cuore. - "Sostiene Pereira", Antonio Tabucchi
http://www.jidesk.net
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20190401/70c9506f/attachment.html>


More information about the PyQt mailing list