Python Forum

Full Version: Connecting pushbuttons signals throug a lambda fonction in a loop
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi

Using PyQt5, I try to create pushbuttons from a list in a loop. As an example, I extracted the following script (I'm fond of ancient greek)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# 

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QWidget, QLabel,  QLineEdit,  QPushButton, QApplication
from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QMessageBox

class Κοινή(QtWidgets.QWidget):
	def __init__(ἁυτόν):
		super(Κοινή,ἁυτόν).__init__()
	def init(ἁυτόν):
		zc=QHBoxLayout(ἁυτόν)
		zc.addStretch()
		ἁυτόν.lesboutons=[('Quitter','quit', True), ('Auteurs', 'aut', True), ('Vocabulaire', 'vocab', False), ('Textes', 'texte', True) ]
		for tpl in ἁυτόν.lesboutons:
			btn=QPushButton(tpl[0])
			btn.setObjectName(tpl[1])
			btn.setEnabled(tpl[2])
			btn.clicked.connect(lambda : ἁυτόν.execut(tpl[1]))
			btn.clicked.connect(lambda cde=tpl[1] : ἁυτόν.execut(cde))			
			zc.addWidget(btn)
			zc.addStretch()
	def execut(ἁυτόν, cde):
		print(cde)
def afficher(ἁυτόν, ὄνομα, χωρίον=None):
	if χωρίον==None:
		χωρίον=(250,200,800,300)
	ἁυτόν.setGeometry(χωρίον[0],χωρίον[1],χωρίον[2],χωρίον[3])
	ἁυτόν.setWindowTitle(ὄνομα)
	ἁυτόν.show()
	
def main(args):
	app = QtWidgets.QApplication(args)
	application=Κοινή()
	application.init()
	afficher(application,'Κοινή', [300,150,300,250])
	app.exec()
	return 0

if __name__ == '__main__':
	import sys
	sys.exit(main(sys.argv))			
At launch, the window with the 4 buttons is displayed. Clicking on any active button sends two signals to execut. I have understood why the parameter of the first signal always is 'texte', but I do not understand why the parameter of the second one is a boolean.

Thank you to anybody explaining me how to have the second parameters of the tuples to be sent to the slot.

Arbiel
Your love of ancient Greek made it really hard for me to help you.

When you define a lambda like this:
x = lambda y=5: execute(y)
It is the same as:
def x(y=5):
    execute(y)
This will work as expected if I call x(), but what happens if I call x(False)? Since a value is provided for 'y' the default value is not used. This is what's happening in your program. The clicked signal is sending False as the first argument to the callback.

When trying to change the signature of the callback I prefer using functools partial over lambda. Your code workes when I replace the lambda with a partial.
from functools import partial
...
for title, name, active in ἁυτόν.lesboutons:
    btn=QPushButton(title)
    btn.setObjectName(name)
    btn.setEnabled(active)
    btn.clicked.connect(partial(ἁυτόν.execut, name))
Hi deanhystad

Thank you twice for helping me.

First you made the effort of understanding my trouble in spite of my love of ancient Greek

Secondly, you gave me the answer.

Arbiel
I could not work on your code at all at first and I it gave me a tiny bit of empathy for what it would be like to be a non-english speaking programmer. I think it was classes without "self" that messed me up. Getting too old and inflexible.
(Nov-04-2020, 04:06 PM)deanhystad Wrote: [ -> ]I could not work on your code at all at first and I it gave me a tiny bit of empathy for what it would be like to be a non-english speaking programmer. I think it was classes without "self" that messed me up. Getting too old and inflexible.

I quite understand that the use of "ἁυτόν" instead of "self" may surprise an english-speaking programmer. In fact, I read in the documentation that "self" is not mandatory at all, but rather sort of a unformal norm. As I certainly will be the only user of the application I'm coding, I decided to do otherwise.

I posted a new thread regarding how to display various layouts in a single window, and I used 'self'.