Manin
Manin

Reputation: 29

Event handler argument freezes in a loop

I'm working on a PySide6 application that uses a loop to create a number of pushbuttons and assign each a click event handler which is obtained by calling a static function in the loop and passing to it the pushbutton generated in that loop iteration. That static function prints the text of the pushbutton passed to it. Therefore clicking on each button is supposed to print its text. But it always prints the same string, the text of the button created in the first iteration of the loop ('Button 0'). This is a sample code that produces the mentioned effect.

import sys
from PySide6.QtCore import QSize
from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QDialog


def get_button_click(x):
    def click():
        print(x.text())
    return click


class MainWindow(QDialog):
    def __init__(self):
        super().__init__()
        verticalLayout = QVBoxLayout(self)
        for i in range(5):
            button = QPushButton('Button {}'.format(i))
            button.clicked.connect(get_button_click(button))
            verticalLayout.addWidget(button)
        self.setFixedSize(QSize(400, 300))


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

I tried static and object functions, but the results were the same. Defining a default parameter as

def get_button_click(x):
    def click(x=x):
        print(x.text())
    return click

results in AttributeError: 'bool' object has no attribute 'text' I searched the web extensively and found nothing similar. This post illustrate the concept of defining functions in a loop. This is the same with PySide2. I wonder if this is a bug or designed? And if there is any workaround?

Much appreciated

Upvotes: 0

Views: 52

Answers (1)

Manin
Manin

Reputation: 29

Till the availability of a fixed version a dirty fix is to wrap the inner function in an exec statement and return the locals with the key of that function

def get_button_click(x):
    exec(f'def click(): print({x})')
    return locals()['click']

Upvotes: -1

Related Questions