Seite 1 von 1
WXPython-Probleme mit Events
Verfasst: Mittwoch 15. September 2004, 10:55
von Stolzi
Hallo,
ich verstehe bei den Events etwas nicht. Ich kann ja in einem Event eine Funktion bestimmen die ausgeführt wird. Ich kann dieser aber keine Optionen übergeben!?!
Nun müsste ich das aber in einem Fall. Ich habe es dann umständlich gelöst.
Code: Alles auswählen
for i in self.lines:
self.LoadImg(default_img,i)
self.bitmap[i].Bind(wx.EVT_LEFT_DOWN, self.OnClick)
Ich erzeuge in dieser Schleife mehrere Bilder. Wenn man auf diese Klickt wird eine Funktion OnClick ausgelöst, die aber "i" wissen müsste...
Ich habe das dann so gemacht, dass ich dem Bild die selbe id gab wie die Zahl die i enthält (darum übergebe ich an LoadImg i). Die id kann ich ja dann mit dem wxEvent.GetId bekommen.
Das halte ich aber für keine elegante Lösung.... Und was wenn i keine Zahl wäre in einem anderen Fall? Dann könnte ich das nicht über die ID lösen.
Hat da wer Rat??
Danke
Stolzi
Verfasst: Mittwoch 15. September 2004, 11:13
von mawe
Hi!
Wenn ich dich richtig verstehe, kannst Du
lambda verwenden:
Code: Alles auswählen
self.bitmap[i].Bind(wx.EVT_LEFT_DOWN, lambda e: self.OnClick(i))
Gruß, mawe
Verfasst: Mittwoch 15. September 2004, 12:16
von Stolzi
Hmm, nein geht nicht:
Vielleicht sollte ich den Fall etwas genauer schildern... In der Schleife werden mehrere Bilder geladen. Die dann durch das Klicken auf das Bild geändert werden können. Dazu muss ich wissen auf welches Bild geklickt wurde.
Hier ist meine Notlösung in der ich wie gesagt den Umweg über die id nahm. Wie gesagt habe ich den 2. Parameter von LoadImg auch als id hergenommen und so konnte ich dann in der OnClick Funktion die id des Bildes übergeben und wusste somit welches gemeint ist:
Code: Alles auswählen
for i in self.lines:
self.LoadImg(default_img,i)
self.bitmap[i].Bind(wx.EVT_LEFT_DOWN, self.OnClick)
...................
def OnClick(self,evt):
id=evt.GetId()
self.LoadImg(self.dir,id)
Dann nach deinem Vorschlag so:
Code: Alles auswählen
for i in self.lines:
self.LoadImg(default_img,i)
self.bitmap[i].Bind(wx.EVT_LEFT_DOWN, lambda e: self.OnClick(i))
...................
def OnClick(self,evt):
self.LoadImg(self.dir,evt)
evt enthält dann ja das übergebene i. Leider referenziert es aber dann komischerweise immer auf das letzte erzeugte Bild... Kanns mir leider nicht zusammendenken warum, da mir das lambda neu ist...
Danke
Stolzi
Verfasst: Mittwoch 15. September 2004, 13:57
von mawe
Hi!
Hab gerade beim wx-Demo DragImage.py gesehen. Ist das nicht in etwa was Du brauchst?
Gruß, mawe
Verfasst: Mittwoch 15. September 2004, 14:56
von Stolzi
Nein ich denke nicht.
Die Funktion LoadImage macht nur folgendes:
Code: Alles auswählen
def LoadImg(self,path,i):
if os.path.isfile(path):
try:
self.bitconst = wx.Image(path, wx.BITMAP_TYPE_ANY)
self.bitconst = self.bitconst.Scale(self.thumb['width'],self.thumb['height'])
except:
self.bitconst = wx.EmptyImage(self.thumb['width'],self.thumb['height'])
else:
self.bitconst = wx.EmptyImage(self.thumb['width'],self.thumb['height'])
self.bitconst=wx.BitmapFromImage(self.bitconst)
if self.load[i]==0:
self.bitmap[i] = wx.StaticBitmap(self.panel, i, self.bitconst)
self.load[i]=1
else:
self.bitmap[i].SetBitmap(self.bitconst)
Sie ladet ein Bild self.bitmap
. Und ich brauche halt den Bezug i dann beim Event, dass ich das richtige Bild überschreibe.
Verstehst du was ich meine?
Nochmal was das Script tun soll:
Bilder werden in der Schleife erzeugt. Beim Klick auf ein Bild wird ein neues über das alte geladen (das ich per File Dialog auswähle, aber das ist ja nebensächlich). Und da brauche ich halt die Referenz zum alten damit self.bitmap das richtige Bild überschreibt.
Kompilziert zu erklären, aber eigentlich ein einfaches Vorhaben
Wenn ich noch anders erklären soll bitte sagen.
Danke
Stolzi
Verfasst: Mittwoch 15. September 2004, 15:33
von mawe
Hi!
Stolzi hat geschrieben:
Kompilziert zu erklären
Ja

Also wenn ich's jetzt richtig verstanden habe ist das Problem folgendes:
Wenn Du auf ein Bild klickst, soll das Programm wissen, welches Bild das ist, oder? Ich hab mal etwas versucht:
Code: Alles auswählen
import wx
class TestFrame(wx.Frame):
def __init__(self,parent,size):
wx.Frame.__init__(self,parent,-1,"",(0,0),size)
self.bitmap = []
x,y=20,20
for i in range(10):
self.DrawImg("homer.bmp",i,(x*3*i,y))
def DrawImg(self,path,i,pos):
self.bitconst = wx.Image(path,wx.BITMAP_TYPE_ANY)
self.bitconst = wx.BitmapFromImage(self.bitconst)
self.bitmap.append(wx.StaticBitmap(self,-1,self.bitconst,pos))
self.bitmap[i].Bind(wx.EVT_LEFT_DOWN, lambda e:self.OnClick(i))
def OnClick(self,i):
self.bitmap[i].Hide()
class MyApp(wx.App):
def OnInit(self):
t = TestFrame(None,wx.Size(700,500))
t.Show(True)
self.SetTopWindow(t)
return True
app = MyApp(0)
app.MainLoop()
Hier verschwindet immer das angeklickte Bild. Hilft das?
Gruß, mawe
Verfasst: Donnerstag 16. September 2004, 06:27
von Stolzi
*g* sehr komisch.
Wenn ich die Events direkt in der Schleife erzeugte, dann wurde beim Klick auf ein Bild immer das letzte i übergeben. Wenn ich sie jedoch wie du in einer seperaten Funktion erzeugte, dann funktioniert es. Gut dass ich da überhaupt nicht mitkomme. Kommt doch aufs gleiche raus, oder?
So mit dem lambda komme ich nun aber nicht wirklich mit. Auch der kurze Text in der Python Doku brachte keinen Aufschluss. Ok macht eine Funktion in einer Zeile, oder so, aber warum funktioniert das was du mir da gezeigt hast, was tut es?
Wohin verschwindet dann eigentlich das Event Objekt? Was wenn ich das auch noch brauche??
Das kann doch aber nicht der übliche Weg sein sowas zu machen, oder? Glaubst du es ist normal nicht gedacht einem Event eine Variable mitzugeben??
Danke
Stolzi
PS:Ich hoffe das waren nicht zu viele Fragen in aller Früh

Verfasst: Donnerstag 16. September 2004, 07:17
von mawe
Guten Morgen Stolzi!
Stolzi hat geschrieben:
Gut dass ich da überhaupt nicht mitkomme.
Da sind wir schon zu zweit

Wegen dem Event: Der wird bei meiner Version schon vom
lambda abgefangen
Wenn Du es später noch brauchst, kannst Du e ja der Funktion mitgeben:
Ob das der normale Weg ist weiß ich auch nicht. Funktioniert aber (ist das nicht die Hauptsache?

) Es ist jedenfalls (glaube ich) die einzige Möglichkeit einem Event ein Argument mitzuschicken.
Bei dem Demo von dem ich oben gesprochen habe, machen sie das ja etwas anders. Zuerst die Position bestimmen, wo man mit der Maus geklickt hat, die Rechteckskoordinaten von jedem Bild bestimmen, dann nachsehen ob die Mausposition in einem der Rechtecke war.
Irgendwie umständlich, weil immer alle Bilder behandelt werden müssen, aber vielleicht gibt's da andere Vorteile?
Gruß, mawe
Verfasst: Donnerstag 16. September 2004, 07:38
von Stolzi
Hast auf die Frage mit dem lambda auch noch eine Antwort? Würde gerne verstehen was das genau macht...
Danke
Verfasst: Donnerstag 16. September 2004, 08:00
von Milan
Hi. Obiges Beispiel macht dasselbe wie dieses hier:
Es wird eine lokale Funktion definiert (wird ja erst in der Schleife erzeugt) und die wird gleich an eventhandler übergeben. Also ist der Name "eine_funktion" egal, da er danach nicht mehr benutzt wird. Dafür eignet sich lambda ganz prima (einzige Einschränkung: es dürfen nur Ausdrücke verwendet werden, keine expressions)... Du kannst ja mal in der Komandozeile den Unterschied zwischen f1 und f2 testen:
Verfasst: Donnerstag 16. September 2004, 10:13
von mawe
Hi!
Milan hat's ja schon gut erklärt. Wenn Du mehr über funktionale Programmierung mit Python wissen willst, schau mal da:
fp1,
fp2,
fp3
Gruß, mawe
Verfasst: Donnerstag 16. September 2004, 12:48
von Dookie
Hi zusammen,
ich hab gerade einen alten Beitrag von mir gesucht, ich wusste doch daß ich da auch mal was zu lambda geschrieben hatte.
http://python.sandtner.org/viewtopic.ph ... ght=lambda
Gruß
Dookie
Verfasst: Donnerstag 16. September 2004, 17:37
von intruder0815
Hallo,
hab mal das Beispiel von mawe einwenig
modifiziert. Wenn man jetzt auf das Bild klickt, dann
wird halt der Index des Bildes geprintet und man könnte
über die Liste (self.bitmap
) alle Sachen mit diesem
Bild machen.
Code: Alles auswählen
import wx
class TestFrame(wx.Frame):
def __init__(self,parent,size):
wx.Frame.__init__(self,parent,-1,"",(0,0),size)
self.bitmap = []
x,y=20,20
for i in range(10):
self.DrawImg("Python.bmp",i,(x*3*i,y))
def DrawImg(self,path,i,pos):
self.bitconst = wx.Image(path,wx.BITMAP_TYPE_ANY)
self.bitconst = wx.BitmapFromImage(self.bitconst)
self.bitmap.append(wx.StaticBitmap(self,-1,self.bitconst,pos))
wx.EVT_LEFT_DOWN(self.bitmap[i], lambda e:self.OnClick(i))
def OnClick(self, i):
print i
class MyApp(wx.App):
def OnInit(self):
t = TestFrame(None,wx.Size(700,500))
t.Show(True)
self.SetTopWindow(t)
return True
app = MyApp(0)
app.MainLoop()
Vielleicht hilft das ja weiter.
Gruß
Christian
Verfasst: Donnerstag 16. September 2004, 20:58
von Stolzi
Ok das nächste mal suche ich erst

Der beitrag von Dookie wäre wohl genug gewesen. Danke auf alle Fälle
@mawe: deine Links funzen nicht

@intruder0815: ich kann keinen Unterschied feststellen, als den dass du für das Event die alte schreibweise verwendet hast. Oder hab ich nicht genau genug geschaut?
Verfasst: Donnerstag 16. September 2004, 21:07
von Dookie
Hi Stolzi,
das mit den Links, liegt an der neuen Unterteilung der GUI-Foren. Die müssen erst angepasst werden. Aber ich denk, jetzt blickst beim Lambda auch soweit durch um es zu verwenden.
Gruß
Dookie
Verfasst: Donnerstag 16. September 2004, 21:47
von mawe
Hi!
Wegen den Links: Das sind externe. Kann die Seiten derzeit aber auch so nicht laden. Vielleicht ein Problem mit dem dortigen Server?
Gruß, mawe
Verfasst: Freitag 17. September 2004, 07:01
von Stolzi
Werds später nochmal versuchen.
Juhuuu ich glaub der Stolzi hats nun gelöst. Das dürfte der einfachste Weg sein denke ich. Hat mir einfach keine Ruhe gelassen.
Hab Mawes Beispiel ein wenig modifiziert. Sollte selbsterklärend sein:
Code: Alles auswählen
import wx
class TestFrame(wx.Frame):
def __init__(self,parent,size):
wx.Frame.__init__(self,parent,-1,"",(0,0),size)
self.bitmap = []
x,y=20,20
for i in range(10):
self.DrawImg("C:\Dokumente und Einstellungen\Administrator\Desktop\Python\phpEditor\DSCF0009.jpg",i,(x*4*i,y))
def DrawImg(self,path,i,pos):
self.bitconst = wx.Image(path,wx.BITMAP_TYPE_ANY)
self.bitconst = wx.BitmapFromImage(self.bitconst)
self.bitmap.append(wx.StaticBitmap(self,-1,self.bitconst,pos))
self.bitmap[i].Bind(wx.EVT_LEFT_DOWN, self.OnClick)
self.bitmap[i].var="Hello World! "+str(i)
def OnClick(self,evt):
obj=evt.GetEventObject()
print obj.var
obj.Hide()
class MyApp(wx.App):
def OnInit(self):
t = TestFrame(None,wx.Size(700,500))
t.Show(True)
self.SetTopWindow(t)
return True
app = MyApp(0)
app.MainLoop()
Der Schlüssel wäre GetEventObject() gewesen. Warum einfach wenns auch kompliziert geht

? Haben wir wohl alle übersehen.