PyQt6 Tutorial – how to receiving signal parameters

Question:

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

Asked By: Yana Dior

||

Answers:

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
Answered By: FractalLotus

To answer this case specifically, the signal which is being connected to the method is the QPushButton.clicked signal.

Slightly confusingly, if you go to Qt’s QPushButton documentation you won’t find any mention of this signal as it’s inherited from QAbstractButton. If you look at the top of that documentation page, you see "Inherits: QAbstractButton" with a link to the QAbstractButton documentation.

On that page you can find the .clicked signal definition.

void QAbstractButton::clicked(bool checked = false)
This signal is emitted when the button is activated (i.e., pressed down then > released while the mouse cursor is inside the button), when the shortcut key > is typed, or when click() or animateClick() is called.

You can see in that definition that the clicked signal passes the checked parameter when it is emitted. That value comes from the button itself to notify the connected slots of the check state of the button.

That state only changes if the button is checkable (so normally it will always be false).

Answered By: mfitzp
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.