Search code examples
pythonmayapyside2

PySide Qt self.function not working in clicked.connect()


I am just trying to run a class function when my button is clicked. It works when you write it like this (outside of a class):

from PySide2 import QtWidgets
window =  QtWidgets.QWidget()

def click_me(self):
    print('clicked me!')

button1 = QtWidgets.QPushButton("Click me")
button1.clicked.connect(click_me)

layout = QtWidgets.QVBoxLayout()
layout.addWidget(button1)

window.setLayout(layout)
window.show()

But for some reason the same thing doesn't work when inside a class:

from PySide2 import QtWidgets
window =  QtWidgets.QWidget()

class Tester():
    def click_me(self):
        print('clicked me!')

    def run(self):
        button1 = QtWidgets.QPushButton("Click me")
        button1.clicked.connect(self.click_me)

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(button1)

        window.setLayout(layout)
        window.show()

Tester().run()

Could someone please help me understand why this is the case and how I can fix it. I need the class approach, so I can't just get rid of the class like in my first example.

Note: I am running this in Autodesk Maya, so in my case I don't need to start up a QApplication in my code. I executed the above code by simply pasting it in the Maya terminal and running it.


Solution

  • The reason is pretty simple: the instance has no persistent reference, even in the local scope, so it gets deleted as soon as it's created and its run method returns.

    The solution is also pretty simple, as you only need to change the last line:

    tester = Tester()
    tester.run()
    

    This ensures that the instance has a persistence (setting it to a variable creates a reference), so it will not garbage collected (aka: deleted). In your case, the instance were actually deleted after that line, so the click_me function (which is an instance attribute) gets deleted as well, and so the signal gets automatically disconnected as the object doesn't exist any more.

    I believe that you were confused by the fact that many tutorials just call a main function or directly create the instance in a one-liner as you tried.

    The difference is that those tutorials create windows that use the maya main window as a parent (which means that it has a reference), and in that case Python does not delete them.

    In your first example the problem didn't happen because the click_me function was anonymous and got referenced in the local scope of the environment.