Python qt: signals/slots

From wikinotes

Sigals and Slots are Qt's way of communicating between widgets.

In order to run a GUI (or make use of nearly of any of Qt's classes) you must have a QCoreApplication (or subclass) running. This starts an eventloop, which enables communication between signals and slots.

Documentation

signals/slots implementation https://woboq.com/blog/how-qt-signals-slots-work.html

Signals

Basics

from Qt import QtWidgets

def printhi():
    print('hi')

btn = QtWidgets.QPushButton('Press Me')
btn.clicked.connect(printhi)                # signal 'clicked' will call function 'printhi'

Now whenever the button is clicked, the function printhi will be called. Consult the api to see a list of all of the signals an object has. You can also built custom signals.

Repeating Signals

Signals can be connected to other signals. The connected signal gets emitted when it's source-signal gets called.

btnA = QtWidgets.QPushButton('press me')
btnB = QtWidgets.QPushButton('or press me instead')

btnA.clicked.connect(btnB.clicked)

Custom Signals

class MyWorker(QtCore.QObject):
    started = QtCore.Signal()
    finished = QtCore.Signal()

    def start(self):
        self.started.emit()
        time.sleep(5)
        self.finished.emit()

def printhi():
    print('hi')

worker = MyWorker()
worker.finished.connect(printhi)

In the above example, finished is emitted when the job is done. prinhi is called when it is signaled. You can only call signals on objects that are QObject subclasses.

wrapping connections

Sometimes you want to connect a signal to a method that needs parameters that your signal does not pass. You can use python's functools.partial or lambda: functions to wrap a signal's output. This is called currying.

def print_message(message):
    print(message)

btn.clicked.connect(
    functools.partial(
        print_message, 'hi'
    )
)




slots

Slots are simply functions that are allowed to be connected to Signals. PySide/PyQt are both very relaxed about this, allowing even lambda functions to be called. C++ is much more strict. See the Official C++ documentation for more details.

In python, you can define a slot using a decorator. So far this has not been necessary, but emulating C++ as closely as possible is likely a good practice in case future bindings abandon the flexible approach being used.

class MyWidget(QtWidgets.QWidget):
    @QtCore.Slot()
    def myslot(self):
        pass