Seite 1 von 1

[PyQt4] lambda in QObject.connect()

Verfasst: Samstag 16. August 2008, 14:34
von cg909
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

Verfasst: Samstag 16. August 2008, 16:59
von 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:…``

Verfasst: Samstag 16. August 2008, 17:22
von 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.

Verfasst: Samstag 16. August 2008, 22:40
von cg909
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. ^^

Verfasst: Sonntag 17. August 2008, 09:03
von 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.

Verfasst: Freitag 23. Januar 2009, 15:46
von insensate
Hi naa,
was ist eigendlich dieses lambda?

Verfasst: Freitag 23. Januar 2009, 16:06
von Leonidas
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.