[PyQt4] lambda in QObject.connect()

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
cg909
User
Beiträge: 2
Registriert: Samstag 16. August 2008, 13:54

Hallo,

ich habe eine Widget-Klasse für PyQt4 geschrieben, die mehrere QPushButtons mit Checkable=True tabellarisch angeordnet erzeugt. Dabei habe ich der Einfachheit halber im connect, das das toggeled()-Signal vom Button mit einer Funktion in der Klasse verbindet, eine lambda-Funktion benutzt, damit ich QPushButton nicht ableiten muss um die Koordinaten des angeklickten Buttons zu übermitteln.

Seltsamerweise habe ich beim Testlauf mit einer 5x5-Matrix immer die Ausgabe

Code: Alles auswählen

TOGGLED: 4 4 True
(also dass der letzte Button unten rechts angeklickt wurde) bekommen, egal welchen Button ich anklickte.

Ich kann mir das Ergebnis einfach nicht erklären, es wird ja für jeden Button eine eigene Lambda-Funktion erzeugt, die auch andere Koordinaten enthält, trotzdem erzeugt jeder Button die gleiche Ausgabe.

Hat hier jemand eine Idee, woran das liegen könnte?

Code: Alles auswählen

class Widget (QtGui.QWidget):
	
	def __init__(self, width, height, parent=None):
		super(Widget, self).__init__(parent)
		
		layout = QtGui.QGridLayout(self)
		widgets = []
		
		for x in xrange(width):
			xlist = []
			for y in xrange(height):
				obj = QtGui.QPushButton('%i,%i'%(x,y), self)
				self.connect(obj, SIGNAL('toggled(bool)'), lambda checked: self._toggled(x,y,checked))
				layout.addWidget(obj, y, x)
				obj.setCheckable(True)
				xlist.append( obj )
			widgets.append(xlist)
	
	def _toggled(self, x, y, checked):
		print 'TOGGLED:', x,y,checked
BlackJack

Die Namen `x` und `y` in der ``lambda``-Funktion werden erst dereferenziert, wenn die Funktion aufgerufen wird. Und zu dem Zeitpunkt sind halt beide an den Wert 4 gebunden.

Default-Argumente werden gebunden, wenn die Funktion erzeugt wird: ``lambda checked, x=x, y=y:…``
lunar

Der Weg über die Lambda-Funktion ist auch unnötig. Du kommst im Slot auch ohne Vererbung an die Koordinaten des angeklickten Buttons. Möglichkeit eins ist einfach "self.sender()" im Slot ("self._toggled") aufzurufen. Möglichkeit zwei ist der Einsatz von "QtCore.QSignalMapper". Das ist zwar aufwendiger, aber imho der elegantere und saubere Weg, weil es die Modularität erhält. Für ein so kleines Programm ist QSignalMapper aber wohl overkill.

Wenn du unbedingt die Koordinaten als Parameter übergeben willst, dann solltest du "functools.partial" auf "self._toggled" anwenden und das dann als Slot nutzen. Würde ich aber nicht empfehlen.
cg909
User
Beiträge: 2
Registriert: Samstag 16. August 2008, 13:54

BlackJack:
Die Namen `x` und `y` in der ``lambda``-Funktion werden erst dereferenziert, wenn die Funktion aufgerufen wird. Und zu dem Zeitpunkt sind halt beide an den Wert 4 gebunden.
Dass ich daran nicht gedacht habe... :oops:
Danke!
lunar:
Möglichkeit zwei ist der Einsatz von "QtCore.QSignalMapper". Das ist zwar aufwendiger, aber imho der elegantere und saubere Weg, weil es die Modularität erhält. Für ein so kleines Programm ist QSignalMapper aber wohl overkill.
Das werde ich mir merken wenn mal ein größeres Projekt ansteht, bis dahin bleibe ich bei meinen Lambda-Funktionen.
Trotzdem Danke. ^^
lunar

Ich sehe gerade, dass dir das eh nicht geholfen hätte. Ich hatte gedacht, du wolltest die absoluten Koordinaten des Buttons herausfinden (die wären über QPushButton zu erfahren gewesen), aber dir geht es ja um die logische Position im Layout. Die bekommst du über QPushButton eh nicht heraus, ergo helfen dir meine Tipps nicht wirklich ;)

Sorry.
insensate
User
Beiträge: 11
Registriert: Samstag 20. Dezember 2008, 13:13

Hi naa,
was ist eigendlich dieses lambda?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

insensate hat geschrieben:was ist eigendlich dieses lambda?
Du solltest besser die Dokumentation lesen statt dich an fremde Threads zu hängen und dort so triviale Fragen die mit dem Thema nichts zu tun haben stellen.

Dennoch eine kurze Antwort (mit der ich gleichzeitig alle anderen bitten will hier im Thread keine Antworten zu geben): ``lambda`` erstellt Funktionen, die keinen Namen haben, auch bekannt als anonyme Funktionen.
Antworten