Search code examples
python-3.xuser-interfacepyside2

How can I share data with a pyside2 slot function?


I have a PySide2 GUI application with a QPushButton button with a @Slot function connected to it. How can I share data with the function?

from PySide2.QtCore import Slot
from PySide2.QtWidgets import QApplication, QMainWindow, QWidget, QPushButton, QVBoxLayout

@Slot()
def button_XYZ_callback():
    # Function which is executed when the button XYZ is clicked.
    # I'd like to access the __main__s context data "parent_data" here.
    pass

if __name__ == '__main__':
    # parent context data what I want to access (read only)
    parent_data = "blub"

    application = QApplication(sys.argv)
    window = QMainWindow()
    central_widget = QWidget()
    xyz_button = QPushButton("XYZ", central_widget)
    xyz_button.clicked.connect(button_xyz_callback)
    layout = QVBoxLayout(central_widget)
    layout.addWidget(xyz_button)
    window.show()
    sys.exit(application.exec_())

Solution

  • Per Python's LEGB rule, the global variable parent_data is accessible from within the button_XYZ_callback function.

    If, however, you wish to reduce the function's dependence on global variables, the standard technique is to define a class, and use class or instance attributes to store what was before global values:

    # based on code from https://wiki.qt.io/Qt_for_Python_Tutorial_ClickableButton
    import sys
    from PySide2 import QtCore, QtWidgets, QtGui
    
    
    class MyWidget(QtWidgets.QWidget):
        def __init__(self, data):
    
            QtWidgets.QWidget.__init__(self)
            self.data = data
            self.button = QtWidgets.QPushButton("Click me!")
            self.text = QtWidgets.QLabel("Hello World")
            self.text.setAlignment(QtCore.Qt.AlignCenter)
            self.layout = QtWidgets.QVBoxLayout()
            self.layout.addWidget(self.text)
            self.layout.addWidget(self.button)
            self.setLayout(self.layout)
            self.button.clicked.connect(self.button_XYZ_callback)
    
        @QtCore.Slot()
        def button_XYZ_callback(self):
            print(self.data)
    
    if __name__ == "__main__":
        parent_data = "blub"
        app = QtWidgets.QApplication(sys.argv)
        widget = MyWidget(data=parent_data)
        widget.show()
        sys.exit(app.exec_())
    

    Alternatively, if the data is known before the callback is to be defined, you could use a function factory to place the data in the enclosing scope of the callback:

    import sys
    from PySide2.QtCore import Slot
    from PySide2.QtWidgets import QApplication, QPushButton
    
    
    def make_callback(data):
        @Slot()
        def button_XYZ_callback():
            print(data)
        return button_XYZ_callback
    
    if __name__ == "__main__":
        parent_data = "blub"
        # https://wiki.qt.io/Qt_for_Python_Tutorial_ClickableButton
        app = QApplication(sys.argv)
        button = QPushButton("Click me")
        button.clicked.connect(make_callback(parent_data))
        button.show()
        app.exec_()