Problem mit Ausgabe auf ein Label in Tkinter

Fragen zu Tkinter.
Antworten
magifix
User
Beiträge: 29
Registriert: Samstag 20. Januar 2018, 16:45

Hallo an alle!

ich kämpfe mit Tkinter unter Python
der nachfolgende Codeschnipsel zeigt das Problem
ich möchte, dass nach Betätigen der Schaltfläche erst der Text 1! und nach 5 Sekunden der Text 2! angezeigt wird.
stattdessen ändert sich bei Betätigen des Buttons nichts und nach 10 Sek. werden beide Texte angezeigt.
Sieht jemand den Fehler im Programm?


from Tkinter import *
import time
root = Tk()
w = Label(root, text="Hello Tkinter!")
w.pack()
def test():
w = Label(root, text="1!")
w.pack()
time.sleep(5)
w = Label(root, text="2!")
w.pack()
time.sleep(5)
button = Button(root,text='Testen',command=test)
button.pack()
root.mainloop()
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@magifix: bei GUI-Programmen dürfen Methoden nicht blockieren. Daher ist sleep verboten. Statt dessen die after-Methode verwenden. Es gibt etliche Beispiele dafür hier im Forum.
magifix
User
Beiträge: 29
Registriert: Samstag 20. Januar 2018, 16:45

Hallo Sirius,
auf after bin ich schon gestoßen
aber ich habe nicht verstanden was ich beim 2. Attribut eintragen muss
die Zahl ist wohl die Zeit in ms
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@magifix: 2. Attribut? Meinst Du vielleicht Argument? Das zweite Argument ist die Funktion oder Methode die nach der Anzahl der Millisekunden aufgerufen werden soll. Weitere Argumente werden dem zweiten Argument dann als Argument(e) weiter gereicht. Du wirst Dir also mindestens Funktionen schreiben müssen. Eventuell kann man auch `functools.partial()` sinnvoll einsetzen. Eigentlich sollte man sich für GUIs aber bereits mit Klassen und objektorientierter Programmierung vertraut gemacht haben, denn das braucht man für jede nicht-triviale GUI.

Den Sternchen-Import aus `Tkinter` solltest Du nicht machen. Üblicherweise wird das als ``import Tkinter as tk`` importiert und die Objekte aus dem Modul dann über den Namen `tk` referenziert. Also beispielsweise `tk.Label`.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mal was ich vermute was Dein Code machen sollte:

Code: Alles auswählen

from functools import partial
import Tkinter as tk


def test(container_widget, texts):
    texts = iter(texts)
    try:
        text = next(texts)
    except StopIteration:
        pass  # No more texts.
    else:
        tk.Label(container_widget, text=text).pack()
        container_widget.after(5000, test, container_widget, texts)


def main():
    root = tk.Tk()
    tk.Label(root, text='Hello Tkinter!').pack()
    tk.Button(
        root,
        text='Testen',
        command=partial(test, root, ['1!', '2!']),
    ).pack()
    root.mainloop()
            

if __name__ == '__main__':
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
magifix
User
Beiträge: 29
Registriert: Samstag 20. Januar 2018, 16:45

Nachdem ich es nicht geschafft habe den Vorschlag mit meinem Problem zu verbinden sende ich anbei nochmal einen Codeausschnitt.
Die Aktualiseirung des Labels klappt nun
Aber ich komme aus der Schleife nicht mehr raus

Das Programm soll 10 Messungen durchführen
die Werte werden in einer Liste gespeichert
weil die Messung etwas dauert brauche ich die Statusanzeige
am Ende werden die Messwerte angezeigt

import Tkinter as tk

counter = 0
def messen():

def count():
global counter
counter = counter+1
label.config(text=str(counter))
#messung 1 bis 10
label.after(1000, count)
#print ("Status")
count()

#print ("d",counter)
root = tk.Tk()
root.title("Test")
label = tk.Label(root, fg="green")
label.pack()

button1 = tk.Button(root, text='Messen', width=25, command=messen)
button1.pack()
button2 = tk.Button(root, text='Stop', width=25, command=root.destroy)
button2.pack()
root.mainloop()
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@magifix: Vergiss bitte ``global`` ganz schnell wieder. Und mit verschachtelten Funktionen solltest Du auch sparsam umgehen. Zumal das hier ja auch gar nicht nötig ist, solange `messen()` tatsächlich nichts anderes macht als einfach nur eine Funktion zu definieren und die dann aufzurufen.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Und dann kann `count()` auch nicht mehr so einfach auf ”magische” Weise auf `label` zugreifen. Alles was eine Funktion oder Methode ausser Konstanten benötigt, sollte als Argument(e) übergeben werden.

Du darfst halt nicht bedingungslos den Aufruf mit `after()` anfordern, sondern darfst das nur machen wenn es noch nicht 10 mal gemacht wurde. Das zählst Du ja mit.

Zudem sollte man verhindern das der Benutzer während die Messungen laufen noch einmal auf die „Messen“-Schaltfläche drücken kann.

Code: Alles auswählen

import Tkinter as tk
from functools import partial


def do_measurements(button, label, count):
    if count > 0:
        label['text'] = count
        label.after(1000, do_measurements, button, label, count - 1)
    else:
        label['text'] = 'Fertig'
        button['state'] = tk.NORMAL


def start_measurements(button, label, count):
    button['state'] = tk.DISABLED
    do_measurements(button, label, count)


def main():
    root = tk.Tk()
    root.title('Test')
    
    status_label = tk.Label(root, fg='green', bg='black', width=25)
    status_label.pack()

    start_button = tk.Button(root, text='Messen')
    start_button.pack(fill=tk.X)
    start_button['command'] = partial(
        start_measurements, start_button, status_label, 10
    )
    
    tk.Button(root, text='Stop', command=root.quit).pack(fill=tk.X)

    root.mainloop()


if __name__ == '__main__':
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten