0

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

Manin
  • 29
  • 1
  • 3
  • `button.clicked.connect(lambda *args, x=button: print(x.text()))`. – ekhumoro Jun 16 '23 at 12:19
  • 1
    Does this answer your question? [Using lambda expression to connect slots in pyqt](https://stackoverflow.com/questions/35819538/using-lambda-expression-to-connect-slots-in-pyqt) – ekhumoro Jun 16 '23 at 12:19
  • No, unfortunately, the problem persists with your proposed lambda function. – Manin Jun 16 '23 at 13:12
  • 1
    If you're using PySide 6.5.1, it's a [known bug](https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-2346) that affects that specific version. Either downgrade or update to 6.5.2 at least. – musicamante Jun 16 '23 at 13:57
  • @Manin I was referring to the attribute-error, which is caused by a mistake in your example, and is not a bug in PySide. I wasn't aware of the issue with PySide-6.5.1, but I can now confirm the buggy behaviour. So in fact your initial example will work as expected in PySide2 (as will my lambda version), and also all other versions of PySide6. – ekhumoro Jun 16 '23 at 18:39
  • @musicamante Thanks, yes, indeed I'm using 6.5.1. While the mentioned post indicated the bug is fixed in 6.5.2, 6.6.0, and 6.5.1.1, after upgrading to 6.5.1.1 the bug persisted. So I'm waiting for a later version. – Manin Jun 17 '23 at 16:50
  • @ekhumoro, thank you – Manin Jun 17 '23 at 16:51

1 Answers1

-1

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']
Manin
  • 29
  • 1
  • 3
  • Using `exec` is a ***terrible*** workaround. It may work in your specific case, but should not be encouraged nor suggested. – musicamante Jun 17 '23 at 18:48