SoFunction
Updated on 2024-11-17

An article explains PyQt5 signal (Signal) and slot (Slot)

Introduction to Signals and Slots

Signal (Signal) and Slot (Slot) is the core mechanism in Qt, but also in the PyQt programming between the object communication mechanism.PyQt's window control class has a lot of built-in signals, developers can also add custom signals. Signals and slots have the following characteristics:

  • One signal can be connected to multiple slots.
  • One signal can be connected to another.
  • The signal argument can make any Python type.
  • One slot can be connected to multiple signals.
  • Signals can be connected to slots either synchronously or asynchronously.
  • Signal to slot connections may cross threads.
  • The signal can be disconnected.

Use of built-in signals and slots

The use of the built-in clicked signal connection slot function is demonstrated here

import sys
from  import QPushButton, QApplication, QWidget, QMessageBox

app = QApplication()
widget = QWidget()

def showMsg():
    (widget, "Information Alert Box", "Ok, pop-up test message.")

btn = QPushButton("Test Click Button", widget)
(showMsg)

()
(app.exec_())

Use of custom signals and slots

import sys
from  import QObject, pyqtSignal


# Signal Objects
class QTypeSignal(QObject):
    # Define a signal
    sendmsg = pyqtSignal(object)

    def __init__(self):
        super(QTypeSignal, self).__init__()
    
    def run(self):
        # Transmit signals
        ('Hello PyQt5')

# Slot objects
class QTypeSlot(QObject):
    def __init__(self):
        super(QTypeSlot, self).__init__()

    # Slot functions in slot objects
    def get(self, msg):
        print("QSlot get msg => " + msg)

if __name__ == "__main__":
    send = QTypeSignal()
    slot = QTypeSlot()

    # 1
    print("--- Bind signals to slot functions ---")
    ()
    ()

    # 2 
    print('--- Disconnect the signal from the slot function ---')
    ()
    ()

Custom signals and built-in slot functions

import sys
from  import *
from  import *
from  import Qt

class WinForm (QWidget):
    # Custom signals without parameters
    button_clicked_signal = pyqtSignal()

    def __init__(self, parent=None):
        super(WinForm, self).__init__(parent)
        ("Examples of custom signals and built-in slot functions")
        (330, 50)
        btn = QPushButton("Close.", self)

        # Connecting signals to slot functions
        (self.btn_clicked)
        
        # Receive signal, connect to slot function
        self.button_clicked_signal.connect()

    def btn_clicked(self):
        # Send customized signal, no parameters
        self.button_clicked_signal.emit()

if __name__ == "__main__":
    app = QApplication()
    win = WinForm()
    ()
    (app.exec_())

Custom signals and custom slot functions

import sys
from  import *
from  import *

class WinForm(QWidget):
    # Custom signals, no parameters
    button_clicked_signal = pyqtSignal()
    def __init__(self, parent= None):
        super(WinForm, self).__init__(parent)
        ("Customized Signal and Slot Function Examples")
        (350, 50)

        btn = QPushButton("Close.", self)
        (self.btn_clicked)
        self.button_clicked_signal.connect(self.btn_close)
    
    def btn_clicked(self):
        self.button_clicked_signal.emit()

    def btn_close(self):
        ()

if __name__ == "__main__":
    app = QApplication()
    win = WinForm()
    ()
    (app.exec_())    

Custom parametric signals

import sys
from  import pyqtSignal, QObject

class CustSignal(QObject):
    # Declare signals without parameters
    signal1 = pyqtSignal()

    # Declare a signal with a parameter of type int
    signal2 = pyqtSignal(int)

    # Declare signals with one int and one str type parameter
    signal3 = pyqtSignal(int, str)

    # Declare a signal with a list type parameter
    signal4 = pyqtSignal(list)

    # Declare a signal with a dictionary type parameter
    signal5 = pyqtSignal(dict)

    # Declare a multi-overloaded version of the signal, including signals with int and str type parameters and signals with str type parameters
    signal6 = pyqtSignal([int,str], [str])

    def __init__(self, parent=None):
        super(CustSignal, self).__init__(parent)
        
        # Connect the signal to the specified slot function
        self.(self.signalCall1)
        self.(self.signalCall2)
        self.(self.signalCall4)
        self.(self.signalCall4)
        self.(self.signalCall5)
        self.signal6[int, str].connect(self.signalCall6)
        self.signal6[str].connect(self.signalCall6OverLoad)

        # Transmit signals
        self.()
        self.(100)
        self.(200, 'hello')
        self.([1,2,3,4,5,6])
        self.({"name":"xiaowang", "age":"25"})
        self.signal6[int, str].emit(300, 'hello world')
        self.signal6[str].emit('hello pyqt')

    def signalCall1(self):
        print('signal1 emit')
    
    def signalCall2(self, val):
        print('signal3 emit, value:', val)
    
    def signalCall3(self, val, text):
        print('signal3 emit, value:', val, text)

    def signalCall4(self, val):
        print('signal4 emit, value:', val)
    
    def signalCall5(self, val):
        print('signal5 emit, value:', val)

    def signalCall6(self, val, text):
        print('signal6 emit, value:', val, text)

    def signalCall6OverLoad(self, val):
        print('signal6 overload emit, value:', val)

if __name__ == "__main__":
    custSignal = CustSignal()
  

Using Custom Signal Parameters

For the clicked signal he is no parameters, if connected to the slot function hopefully can receive parameters, if directly connected to the slot function with parameters will be an error, because the number of parameters issued by the signal must be greater than the number of parameters received by the slot function. Here are two solutions:

1. Use lambda

2. Use the partial function in the functools module.

import sys
from  import *
from  import *
from functools import partial, partialmethod

class WinForm(QMainWindow):
    def __init__(self, parent=None):
        super(WinForm, self).__init__(parent)
        ("Solution for a parametric slot function to receive an unparameterized signal.")

        button1 = QPushButton("Button 1")
        button2 = QPushButton("Button 2")

        # For the clicked signal he has no parameters, if the connected slot function wants to receive parameters, if the direct connection has parameters
        #'s slot function will error out because the number of arguments signaled must be greater than the number of arguments received by the slot function. There are two solutions here:
        # 1. Using lambda
        # 2. Using the partial function in the functools module
        
        # Use lambda
        (lambda: (1))

        # Use the partial function in the functools module
        (partial(, 2))

        layout = QHBoxLayout()
        (button1)
        (button2)
        mainwidget = QWidget()
        (layout)
        (mainwidget)


    def onButtonClick(self, n):
        print("Button {0} It's pressed.".format(n))
        (self, "Information Alert Box", 'Button {0} clicked'.format(n))

if __name__ == "__main__":
    app = QApplication()
    win = WinForm()
    ()
    (app.exec_())

Decorator signals and slots

@(parameter)

def on_sender_object_name_transmit_signal_name (self, arguments):

pass

This line of code must have been executed first: (self)

from PyQt5 import QtCore
from  import QApplication, QWidget, QHBoxLayout, QPushButton, QMessageBox
import sys

# Decorator signals and slots
# @(parameter)
# def on_sender_object_name_transmit_signal_name (self, arguments):
#   pass
# 
# This line of code must be executed first: (self)

class CustWidget(QWidget):
    def __init__(self, parent=None):
        super(CustWidget, self).__init__(parent)
        ("Decorator Signal and Slot Demo.")
        (350, 50)

         = QPushButton("OK", self)

        # Set the object name using setObjectName
        ("okButton")
        layout = QHBoxLayout()
        ()
        (layout)

        (self)


    @()
    def on_okButton_clicked(self):
        print("The OK button was clicked.")
        (self, "Information Alert Box", "The OK button was clicked.")

if __name__ == "__main__":
    app = QApplication()
    win = CustWidget()
    ()
    (app.exec_())

Disconnecting and connecting signals to slots

import sys
from  import *
from  import *


# Signal disconnected from slot

class SignalClass(QObject):
    # Declare signals without parameters
    signal1 = pyqtSignal()

    # Declare a signal with a parameter of type int
    signal2 = pyqtSignal(int)

    def __init__(self, parent=None):
        super(SignalClass, self).__init__(parent)

        # Connect the signal signal1 to the two slot functions sig1Call and sig2Call
        self.(self.sig1Call)
        self.(self.sig2Call)

        # Connect signal2 to signal1
        self.(self.signal1)

        # Transmit signals
        self.()
        self.(1)

        # Disconnect signal1,signal2 signals from each slot function
        self.(self.sig1Call)
        self.(self.sig2Call)
        self.(self.signal1)
        
        # Connect signals signal1 and signal2 to the same slot function sig1Call
        self.(self.sig1Call)
        self.(self.sig1Call)

        # Re-transmit the signal
        self.()
        self.(2)

    def sig1Call(self):
        print('signal-1 emit')
    
    def sig2Call(self):
        print('signal-2 emit')

if __name__ == "__main__":
    signal = SignalClass()

The use of signals and slots in multithreading

import sys
from  import QApplication, QWidget
from  import QThread, pyqtSignal

class Main(QWidget):
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)

        # Create a thread instance and set the name, variables, signals and slots
         = MyThread()
        ("thread1")
        ()
        (6)
        
    def outText(self, text):
        print(text)

class MyThread(QThread):
    
    sinOut = pyqtSignal(str)

    def __init__(self, parent=None):
        super(MyThread, self).__init__(parent)
         = None

    def setIdentity(self, text):
         = text
    
    def setVal(self, val):
         = int(val)
        # Execute the thread run method
        ()

    def run(self):
        while  > 0 and :
            # Transmit signals
            ( + "==>" + str())
             -= 1

if __name__ == '__main__':
    app = QApplication()
    main = Main()
    ()
    (app.exec_())

The above is a detailed explanation of PyQt5 signal (Signal) and slot (Slot) of the details, more about PyQt5 signal Slot information please pay attention to my other related articles!