PySide : How to get the clicked QPushButton object in the QPushButton clicked slot?
Asked Answered
U

4

13

I am new to PySide. I want to get the QPushButton obj (such as use it to get its text) in its clicked slot.

button = QtGui.QPushButton("start go")
button.clicked.connect(self.buttonClick)

def buttonClick(self):
    ... # How can I get the button  object?
    # print button.text()  how to get the text : 'start go' ?

Thanks!

Undo answered 2/12, 2013 at 3:18 Comment(0)
P
20

Here is what I did to solve the problem:

button = QtGui.QPushButton("start go")
button.clicked.connect(lambda: self.buttonClick(button))

def buttonClick(self, button):
    print button.text()
Piedadpiedmont answered 2/12, 2013 at 17:20 Comment(5)
+1. This is probably the best way to avoid using sender(). Can be tricky to use lambda like this when connecting lots of buttons in a loop, though.Polemics
what the lambda does?Skillern
In Python, lambda creates an anonymous function, more info here secnetix.de/olli/Python/lambda_functions.hawkPiedadpiedmont
@Piedadpiedmont Can we write the same in a separate .py file, as the main window file changes once we change in QT designer and convert from .ui to .py fileTruong
@pjrockzzz, just saw your comment, writing this for future reference: when you have a .py file generated from a .ui file you normally don't edit that .py file directly to connect signals and slots but inherit a subclass from the class in the .py file. You'd put that subclass in the separate .py file and make the connections in there.Piedadpiedmont
E
21

You can just use self.sender() to determine the object that initiated the signal.

In your code something along the lines of this should work.

button = QtGui.QPushButton("start go")
button.clicked.connect(self.buttonClick)

def buttonClick(self):
    print self.sender().text()
Egon answered 2/12, 2013 at 3:33 Comment(3)
I just test it, But it issues an error.Undo
@tao4yu. The example code should be: print self.sender().text()Polemics
Thanks @Polemics bad copy/pasting on my part.Egon
P
20

Here is what I did to solve the problem:

button = QtGui.QPushButton("start go")
button.clicked.connect(lambda: self.buttonClick(button))

def buttonClick(self, button):
    print button.text()
Piedadpiedmont answered 2/12, 2013 at 17:20 Comment(5)
+1. This is probably the best way to avoid using sender(). Can be tricky to use lambda like this when connecting lots of buttons in a loop, though.Polemics
what the lambda does?Skillern
In Python, lambda creates an anonymous function, more info here secnetix.de/olli/Python/lambda_functions.hawkPiedadpiedmont
@Piedadpiedmont Can we write the same in a separate .py file, as the main window file changes once we change in QT designer and convert from .ui to .py fileTruong
@pjrockzzz, just saw your comment, writing this for future reference: when you have a .py file generated from a .ui file you normally don't edit that .py file directly to connect signals and slots but inherit a subclass from the class in the .py file. You'd put that subclass in the separate .py file and make the connections in there.Piedadpiedmont
L
2

I actually wanted to comment on a comment in answer #1 but don't have enough reputation to do so yet :). The comment is "Can be tricky to use lambda like this when connecting lots of buttons in a loop, though." And that's exactly what I needed to do when I found this page.

Doing this in a loop doesn't work:

for button in button_list :
    button.clicked().connect( lambda: self.buttonClick( button )

Your callback will always get called with the last button in button_list (for why see information on this page I also just found - https://blog.mister-muffin.de/2011/08/14/python-for-loop-scope-and-nested-functions)

Do this instead, it works:

for button in button_list :
    button.clicked().connect( lambda b=button: self.buttonClick( b ))
Lining answered 5/3, 2018 at 16:51 Comment(1)
There may be a catch here, however... Being a local variable, the widget's c++ object may have gotten deleted by the time the callback is called. Running into this now.Lining
P
1

Usually, most widgets will be created in the setup code for the main window. It is a good idea to always add these widget as attributes of the main window so that they can be accessed easily later on:

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None)
        super(MainWindow, self).__init__(parent)
        ...
        self.button = QtGui.QPushButton("start go")
        self.button.clicked.connect(self.buttonClick)
        ...

    def buttonClick(self):
        print(self.button.text())

If you have lots of buttons that all use the same handler, you could add the buttons to a QButtonGroup, and connect the handler to its buttonClicked signal. This signal can send either the clicked button, or an identifier that you specify yourself.

There is also the possibility of using self.sender() to get a reference to the object that sent the signal. However, this is sometimes considered to be bad practice, because it undermines the main reason for using signals in the first place (see the warnings in the docs for sender for more on this).

Polemics answered 2/12, 2013 at 4:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.