Seite 1 von 1
Label als Klasse ableiten und <Button-1> an Objekt binden
Verfasst: Dienstag 25. November 2014, 00:04
von mintpc
Hallo zusammen,
ein kleines Problem, wo ich nicht weiter komme.
Ich möchte vom Label aus tkinter eine Klasse ableiten. Bei den erzeugten Objekten
soll man draufklicken können, so dass etwas passiert.
Konkret sollen mit diesen Objekten einfach mehrere Lampen simuliert werden, die
beim Draufklicken an- bzw. ausgehen, dargestellt durch die Farben weiß und rot.
Ich hab nun schon eine Klasse von Label abgeleitet, mehrere Instanzen erzeugt und
auf dem Fenster platziert. Das funktioniert. Der Code sieht so aus:
Code: Alles auswählen
class Lampe(Label):
def __init__ (self, master, bg=None, width=None, height = None):
Label.__init__(self, master, bg=bg, width=width, height = height)
Nun bleibt da also noch das Problem mit dem binden des Button-Ereignisses.
Ich hab viiiieeeeele Varianten probiert, auch das Folgende, klappt aber alles
nicht wirklich.
Code: Alles auswählen
def LampeClick ():
print("Hallo")
class Lampe(Label):
def __init__ (self, master, bg=None, width=None, height = None):
Label.__init__(self, master, bg=bg, width=width, height = height)
Label.bind(self,sequence="<Button-1>", func = LampeClick)
Wie geht es richtig?
Danke schonmal
mintpc
Re: Label als Klasse ableiten und <Button-1> an Objekt binde
Verfasst: Dienstag 25. November 2014, 08:58
von bfm
Hallo,
und wenn du das Label gleich durch einen Button ersetzt und bei einem Klick dynamisch die Hintergrundfarbe wechselst?
Re: Label als Klasse ableiten und <Button-1> an Objekt binde
Verfasst: Dienstag 25. November 2014, 10:17
von Michael Schneider
Hi mintpc,
mintpc hat geschrieben:klappt aber alles nicht wirklich.
damit meinst Du wahrscheinlich, dass Python sich beschwert, weil Du im Handler das event-Objekt nicht entgegennimmst?
Ich würde den Handler auch in die abgeleitete Klasse integrieren, da sie von ihr ausgelöst wird und sich auf sie bezieht:
Code: Alles auswählen
from Tkinter import *
class Lampe(Label):
BG_COLOR_ON = "yellow"
BG_COLOR_OFF = "red"
def __init__ (self, *args, **kwds):
Label.__init__(self, *args, **kwds)
self.bind(self,sequence="<ButtonPress-1>", func=self.toggle_lamp)
def toggle_lamp(self, event=None):
print("Lampe angeklickt")
if self["bg"] == self.BG_COLOR_ON:
self.config(bg=self.BG_COLOR_OFF)
else:
self.config(bg=self.BG_COLOR_ON)
if __name__ == "__main__":
lamp = Lampe(bg="yellow", text="Lampe")
lamp.grid()
lamp.mainloop()
VG,
Michael
EDIT: Blackjacks Kommentaren kann ich nur zustimmen - habe das Beispiel entsprechend angepasst. Dass sich das 'bind' auf die Klasse bezieht, habe ich übersehen und mitkopiert. Es könnte sogar Sinn machen, ein Ereignis einmalig an eine Klassencallbackfunktion zu binden, damit sie für alle Lampen gilt. Dann aber nicht im Konstruktor der Instanzen.
Die Konstanten BG_COLOR_ON und BG_COLOR_OFF sind auf Klassenebene definiert, werden aber von der Instanz abgerufen. So kann man bei Bedarf eigene Farben für einzelne Lampen in der Instanz definieren.
Re: Label als Klasse ableiten und <Button-1> an Objekt binde
Verfasst: Dienstag 25. November 2014, 10:40
von BlackJack
Aus dem ``Lamp.bind(…)`` würde ich noch ein ``self.bind(…)`` machen und vielleicht den Zustand der Lampe von den Zeichenketten für die Farbe trennen.
Edit: Und die Rückruffunktion passender benennen, zum Beispiel in `toggle()` oder `switch()` oder so, denn die möchte man vielleicht auch von aussen mal aufrufen.
Re: Label als Klasse ableiten und <Button-1> an Objekt binde
Verfasst: Dienstag 25. November 2014, 12:12
von wuf
Hier noch ergänzend gestützt auf Anregungen von BlackJack:
Code: Alles auswählen
try:
import Tkinter as tk
except ImportError:
import tkinter as tk
NUM_OF_LAMPS = 8
LAMP_NAME = "Lampe"
LAMP_ON_COLOR = "red"
LAMP_OFF_COLOR = 'yellow'
ON_STATE = "ein"
OFF_STATE = "aus"
class Lamp(tk.Label):
def __init__ (self, parent, callback=None, *args, **kwds):
self.parent = parent
self.callback = callback
tk.Label.__init__(self, parent, *args, **kwds)
self.bind("<ButtonPress-1>", self.toggle)
self.state = False
self.switch()
def toggle(self, event=None):
if self.state:
self.state = False
else:
self.state = True
self.switch(self.state)
def switch(self, state=False):
self.state = state
self.lamp_color(state)
if self.callback != None:
if state:
state_name = ON_STATE
else:
state_name = OFF_STATE
self.callback(self['text'], state_name)
def lamp_color(self, state):
if state:
self.config(bg=LAMP_ON_COLOR)
else:
self.config(bg=LAMP_OFF_COLOR)
def lamp_callback(lamp_name, state):
print(lamp_name, state)
def main():
lamps = list()
app_win = tk.Tk()
for lamp_nr in range(NUM_OF_LAMPS):
lamp = Lamp(app_win, lamp_callback, bg=LAMP_OFF_COLOR,
text="{}-{}".format(LAMP_NAME, lamp_nr), padx=4)
lamp.pack(padx=10, pady=5)
lamps.append(lamp)
lamps[0].switch(True)
app_win.mainloop()
if __name__ == "__main__":
main()
Gruss wuf

Re: Label als Klasse ableiten und <Button-1> an Objekt binde
Verfasst: Dienstag 25. November 2014, 20:19
von Michael Schneider
Puh wuf, da hast Du aber weit ausgeholt. Ich wollte eigentlich nur ein kleines (funktionierendes) Beispiel für die Funktion geben und jetzt hat der Fragesteller ein ganzes Rahmenprogramm inklusive globale Konstanten, Hilfsfunktionen und modulsicherer Startfunktionalität.

Re: Label als Klasse ableiten und <Button-1> an Objekt binde
Verfasst: Dienstag 25. November 2014, 21:07
von mintpc
Super. Vielen Dank für die beiden sehr ausführlichen Beispiele.
Hab mich grad mal ne Zeit lang in beide Beispiele eingearbeitet und
hab's jetzt verstanden.
Nochmals vielen vielen Dank für die Mühe und die Hilfe.
mintpc
Re: Label als Klasse ableiten und <Button-1> an Objekt binde
Verfasst: Mittwoch 26. November 2014, 08:16
von Sirius3
@wuf: die toggle-Methode sieht etwas seltsam aus, da sie sowohl `self.state` setzt als auch `switch` aufruft, das selbst auch `self.state` setzt. Toggle würde ich so schreiben:
Code: Alles auswählen
def toggle(self, event=None):
self.switch(not self.state)
Das Defaultargument von switch ist auch unintuitiv. Warum bevorzugst Du AUS vor AN beim Schalten? Wenn es keine Vorbelegung gibt, die tatsächlich dem Normalfall entspricht, sollte man gar keine Default-Werte setzen, dann ist bei jedem Aufruf klar, wie da geswitcht wird. Dann würde ich die AN-AUS-Konstanten in ein Dictionary zusammenfassen:
Code: Alles auswählen
LAMP_COLOR = {False:'yellow', True:'red'}
STATE_NAME = {False:'aus', True: 'ein'}
[...]
def switch(self, state):
self.state = state
self.lamp_color(state)
if self.callback is not None:
self.callback(self['text'], STATE_NAME[state])
def lamp_color(self, state):
self.config(bg=LAMP_COLOR[state])
Re: Label als Klasse ableiten und <Button-1> an Objekt binde
Verfasst: Donnerstag 27. November 2014, 22:52
von wuf
Hi Sirius3
Besten Dank für deine lehrreichen Anregungen. Habe diese in mein Skript einfliessen lassen. Werde sie auch in Zukunft bei ähnliche Konstellationen anwenden.
Gruss wuf
