Search code examples
pythonpyqt6

PyQt6 Tutorial - how to receiving signal parameters


I am a newbie to Python Qt programming. I have been going through a tutorial at the link - https://www.pythonguis.com/tutorials/pyqt6-signals-slots-events/

The part of the tutorial that I am unable to understand is under the section "Receiving data"

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")

        button = QPushButton("Press Me!")
        button.setCheckable(True)
        button.clicked.connect(self.the_button_was_clicked)
        button.clicked.connect(self.the_button_was_toggled)

        self.setCentralWidget(button)

    def the_button_was_clicked(self):
        print("Clicked!")

    def the_button_was_toggled(self, checked):
        print("Checked?", checked)

Questions

  1. how the author is able to pass the argument 'checked' to the function "the_button_was_toggled", since while connecting the signal 'clicked' we did not specify any arguments to the function. To me it appears more of a magic thing than something I can understand by going through relevant documentation that talks about receiving arguments from signal to slot
  2. Can someone provide any relevant link to PyQt6 documentation or tutorial to understand this better

Thank you for your time


Solution

  • The Qt documentation is a good place to look for descriptions of Qt features. There is a section about signals and slots that mentions this behavior:

    The signature of a signal must match the signature of the receiving slot. (In fact a slot may have a shorter signature than the signal it receives because it can ignore extra arguments.)

    This means you don't need to include all the parameters that are available from a signal in your function definition. Qt has logic to inspect the function you pass to connect() and determine the number of arguments the function needs. While Qt implements this in C++ you can do the same thing in your own Python programs. I found a SO thread that provides lots of options for doing this.

    Here is an example:

    from inspect import signature
    
    
    def pass_only_requested_args(function_ref):
        args = [1, 2, 3]
        sig = signature(function_ref)
        number_of_parameters = len(sig.parameters)
        function_ref(*args[:number_of_parameters])
        
    def function_1(p1):
        print(f"function 1 => {p1}")
        
    def function_2(p1, p2):
        print(f'{p1} {p2}')
        
    pass_only_requested_args(function_1)
    pass_only_requested_args(function_2)
    

    The output is:

    function 1 => 1
    1 2