Seite 1 von 1
Ändern des Textes eines Labels durch eine anderes Objekt
Verfasst: Mittwoch 29. April 2015, 18:25
von Umsteiger73
Hallo
Ich mache meine ersten Versuche mit Tkinter. Die Idee ist ein Objekt, dass den Text eines Labels während der Laufzeit ändert. Das versuche ich mit folgendem Code:
Code: Alles auswählen
import tkinter as tk
class TextSetter():
def __init__(self):
self.single_label = SingleLabel()
self.change_label()
def change_label(self):
self.single_label.label_variable.set("Come on!") # does not work
self.single_label.set_label("What the ...!") # does not work either
class SingleLabel():
def __init__(self):
self.root = tk.Tk()
self.label_variable = tk.StringVar()
self.start()
def set_label(self,text):
self.label_variable.set(text)
def start(self):
self.label = tk.Label(self.root,textvariable=self.label_variable)
self.label.pack()
self.label_variable.set("So far so good")
self.root.mainloop()
def main():
TextSetter()
if __name__ == '__main__':
main()
Ich erwarte eigentlich, dass der Text im Label "What the ...!" oder zumindest "Come on!" sein sollte. Statdessen bleibt der Text "So far so Good".
Es kommt keine Fehlermeldung. Ich mache irgend ein Denkfehler. Kann mir allenfall jemand auf die Sprünge helfen?
Danke im Voraus
Gruss
Thomas
Re: Ändern des Textes eines Labels durch eine anderes Objekt
Verfasst: Mittwoch 29. April 2015, 19:24
von BlackJack
@Umsteiger73: Der Aufruf von `mainloop()` kehrt erst zurück wenn das Fenster geschlossen wird, deshalb wird nichts ausgeführt was nach dem Aufruf von `SingleLabel()` kommt bis das Fenster geschlossen wird.
Re: Ändern des Textes eines Labels durch eine anderes Objekt
Verfasst: Mittwoch 29. April 2015, 21:05
von Umsteiger73
@BlackJack
Danke für den Hinweis. Genau das habe ich gebraucht. Jetzt kann ich in der richtigen Richtung nach einer Lösung suchen.
Gruss
Thomas
Re: Ändern des Textes eines Labels durch eine anderes Objekt
Verfasst: Freitag 1. Mai 2015, 09:50
von Umsteiger73
Nachtrag, für alle die es interessiert.
Ein rekursiver Aufruf der after Methode und das umstellen der Mainloop hat mir weiter geholfen. Spannenderweise ist auch das erwartete Problem mit der Rekursionstiefe nicht aufgetreten.
Code: Alles auswählen
import tkinter as tk
class SingleLabel(object):
def __init__(self,root):
self.root = root
self.data = Countdown()
def draw_label(self):
frame=tk.Frame(self.root)
frame.pack()
self.text=tk.Label(frame)
self.text.pack()
def refresh_label(self):
self.number= self.data.number()
self.text.configure(text=self.number)
self.root.after(1000, self.refresh_label) # des Pudels Kern
class Countdown(object):
def __init__(self):
self.countdown = [1,2,3,4,5,6,7,8,9,10]
def number(self):
if self.countdown:
return self.countdown.pop()
else:
self.countdown = [1,2,3,4,5,6,7,8,9,10]
return [0]
root=tk.Tk()
sl = SingleLabel(root)
sl.draw_label()
sl.refresh_label()
root.mainloop()
@BlackJack: Nochmals danke für den Fingerzeig.
Gruss Thomas
Re: Ändern des Textes eines Labels durch eine anderes Objekt
Verfasst: Freitag 1. Mai 2015, 10:18
von Sirius3
@Umsteiger73: Außerhalb von __init__ sollten keine neuen Attribute mehr hinzugefügt werden. Warum gibt es die draw_label-Methode überhaupt separat? number an self zu binden ist schlicht weg falsch. number in Countdown sollte besser next_number heißen, um den zustandsändernden Charakter der Methode deutlich zu machen. Auf Modulebene sollten kein Code direkt ausgeführt werden, das heißt, ab Zeile 32 sollte alles in eine Funktion wandern, die üblicherweise main genannt wird und per
aufgerufen wird.
Re: Ändern des Textes eines Labels durch eine anderes Objekt
Verfasst: Freitag 1. Mai 2015, 12:08
von BlackJack
@Umsteiger73: Man könnte/sollte aus dem `Countdown` vielleicht auch ein iterierbares Objekt machen statt eine Methode zur Verfügung zu stellen die nicht nicht den dafür üblichen Namen trägt. Und das mit der Liste und `pop()` ist eine *sehr* eigenartige Implementierung. Das die literale Liste zweimal im Quelltext steht ist zudem auch fehleranfällig. Eigentlich bräuchte man gar keine eigene Klasse dafür sondern höchstens eine Funktion die ein passendes iterierbares Objekt mit eingebauten Funktionen (`range()`, `reversed()`) und Mitteln aus der Standardbibliothek (`itertools.cycle()`) erstellt.
Es ist eher ungewöhnlich das die Initialisierung eines Objekts GUI-Elemente auf einem Widget erstellt das als Argument übergeben wurde. Da hat der Aufrufer ja keinerlei Kontrolle was diese Methode in einem eigentlich *übergeordneten* Widget anstellt. Normalerweise würde man von einem Container-Widget erben, dort *drin* anzeigen was man lustig ist, und dem *Aufrufer* die Entscheidung überlassen wie und wo er das dann in einem übergeordneten Widget anordnet. Kann ja sein das am Ende mehrere solcher `SingleLabel` (was soll das eigentlich bedeuten?) in einem Frame in einer `grid()`-Anordnung angezeigt werden sollen. Dazu sollte man die `SingleLabel`-Klasse nicht ändern müssen.
Ungetestet:
Code: Alles auswählen
import tkinter as tk
from itertools import cycle
class CountdownUI(tk.Frame):
def __init__(self, root):
tk.Frame.__init__(self, root)
self.countdown_label = tk.Label(self)
self.countdown_label.pack()
self.countdown_numbers = cycle(reversed(range(11)))
self.event_id = None
def _update_countdown(self):
self.countdown_label['text'] = next(self.countdown_numbers)
self.event_id = self.after(1000, self._update_countdown)
def start_countdown(self):
if self.event_id is None:
self._update_countdown()
def stop_countdown(self):
if self.event_id is not None:
self.after_cancel(self.event_id)
def main():
root = tk.Tk()
countdown_ui = CountdownUI(root)
countdown_ui.pack()
countdown_ui.start_countdown()
root.mainloop()
if __name__ == '__main__':
main()
Re: Ändern des Textes eines Labels durch eine anderes Objekt
Verfasst: Sonntag 3. Mai 2015, 11:08
von Umsteiger73
Hallo
Wow, danke für die Denkanstösse. Werde sie berücksichtigen.
Gruss
Thomas