Button trotz Deaktivierung aktiv

Fragen zu Tkinter.
Antworten
World_of_Tanks
User
Beiträge: 14
Registriert: Donnerstag 25. April 2019, 14:44

Hallo zusammen!

Ich experimentiere gerade etwas mit Tkinter, "grid" und "after", also verzeiht mir, wenn ich beim Import * und auch keine Klassen verwende. Das kommt alles nicht in den abschließenden Code. Im folgenden Code will ich einfach nur in einem Label ein paar Zahlen aufwärtszählend mir anzeigen lassen. Mit einer "after" Funktion soll ein gewisser delay eingebracht werden (die Variable zeit hat nicht wirklich was mit Zeit zu tun). Anfangen soll es durch einen Knopfdruck und für die Zeit der Zählung, soll der Knopf deaktiviert sein. Leider passiert hier ein Fehler den ich nicht nachvollziehen kann. Obwohl er deaktiviert zu sein scheint (ausgegraut, keine Klick-Animation), wird jedesmal wenn ich ihn erneut drücke, die Zählung immer schneller und schneller. Was passiert da und wie kann ich das abstellen?

Code: Alles auswählen

from tkinter import *

zeit = 0

def setup():
    global zeit_label
    zeit_fenster = Tk()
    zeit_fenster.title("Zeit")
    
    zeit_label = Label(zeit_fenster, text = "", width = 50)
    start_button = Button(zeit_fenster, text="Start", width = 10)
    
    zeit_label.grid(row=0, columnspan=5, padx=10, pady=10)
    start_button.grid(row=5, columnspan=2, padx=10, pady=10)
    start_button.bind("<Button-1>", begin)

def begin(event):
    global start_button, zeit
    
    if start_button["text"] == "Start":
        start_button.config(state = "disabled")
        fenster_update()
    elif start_button["text"] == "Zurück":
        zeit_fenster.destroy()

def fenster_update():
    global zeit_fenster, start_button, zeit
    
    zeit += 1
    if zeit <= 50:
        if zeit == 50:
            start_button.config(text="Zurück", state="normal")
        zeit_label.config(text=str(zeit))
           
    if start_button["text"] == "Start":
        spieltag_fenster.after(300, fenster_update)

if __name__ == '__main__':
    setup()
    mainloop()
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi World_of_Tanks

So sollte es funktionieren:

Code: Alles auswählen

from tkinter import *

zeit = 0

def setup():
    #global zeit_label
    global zeit_label, start_button, zeit_fenster
    zeit_fenster = Tk()
    zeit_fenster.title("Zeit")
    
    zeit_label = Label(zeit_fenster, text = "", width = 50)
    start_button = Button(zeit_fenster, text="Start", width = 10)
    
    zeit_label.grid(row=0, columnspan=5, padx=10, pady=10)
    start_button.grid(row=5, columnspan=2, padx=10, pady=10)
    start_button.bind("<Button-1>", begin)

def begin(event):
    global start_button, zeit
    
    if start_button["text"] == "Start":
        start_button.config(state = "disabled")
        fenster_update()
    elif start_button["text"] == "Zurück":
        zeit_fenster.destroy()

def fenster_update():
    global zeit_fenster, start_button, zeit
    
    zeit += 1
    if zeit <= 50:
        if zeit == 50:
            start_button.config(text="Zurück", state="normal")
        zeit_label.config(text=str(zeit))
           
    if start_button["text"] == "Start":
        #spieltag_fenster.after(300, fenster_update)
        zeit_fenster.after(300, fenster_update)

if __name__ == '__main__':
    setup()
    mainloop()
Gruss wuf :-)
Take it easy Mates!
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Auch wenn man etwas ausprobiert, sollte man sich an die Grunderfordernisse halten, denn wenn man nicht schon im kleinen anfängt, dann wird es für größere Projekte nicht besser. Das Programm läuft auch so überhaupt nicht, weil etliche Variablen nicht definiert sind. Warum benutzt Du einmal config und einmal den Zugriff über eckige Klammern?

Du benutzt Knöpfe falsch. Knopfe haben das command-Argument, `bind` greift auf einer viel tieferen Ebene an und ignoriert alles, was einen Knopf ausmacht (gedrückt, ausgegraut, etc).
World_of_Tanks
User
Beiträge: 14
Registriert: Donnerstag 25. April 2019, 14:44

@Sirius3 Nun es erspart mir aber doch etwas Zeit und davon hab ich nun mal nicht allzu viel. Außerdem gab es bei "import tkinter as tk" Probleme mit "grid". Aber wie auch immer. Du hattest Recht. Mit "command" hat es super funktioniert (sowas steht natürlich nicht in den Lehrbüchern), also vielen Dank!
Benutzeravatar
sparrow
User
Beiträge: 4165
Registriert: Freitag 17. April 2009, 10:28

@World_of _Tanks: Wenn es bei diesem Mini-Beispiel schon Probleme gibt, wird es bei größeren Projekten auch nicht funktionieren: Deshalb ist es sinnvoll immer korrekt zu arbeiten und hat nichts mit Zeitaufwand zu tun. Bei der Verwendung von "global" musst dich immer ein tiefgreifender Schmerz durchfahren. Es gibt nur ganz wenige Ausnahmen, wo der Einsatz sinnvoll ist. Ein Minibeispiel zähl ich nicht dazu.
World_of_Tanks
User
Beiträge: 14
Registriert: Donnerstag 25. April 2019, 14:44

Nun ich lerne von einem Buch und da wird es genutzt. Da ich noch lerne und es so benutzt wird, kann ich es halt noch nicht besser.
Benutzeravatar
__blackjack__
User
Beiträge: 13007
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@World_of_Tanks: Die Frage ist ob es wirklich im Deine Zeit gehen sollte wenn Du andere nach Hilfe fragst, oder nicht auch um deren. Wenn Du Code zeigst der so gar nicht läuft, muss jemand der helfen will, ja erst einmal Zeit investieren um heraus zu finden warum der nicht läuft. `spieltag_fenster` ist ja nicht mal durch ein zusätzliches ``global`` erreichbar.

Wie viel Zeit geht denn dabei drauf `tk.Label` statt `Label` zu schreiben?

Und das ganze in eine Klasse zu schreiben benötigt auch nicht viel Zeit.

Man kann es auch ohne Klasse und ``global`` lösen, muss dann aber halt ein paar Argumente durch die gegend reichen.

Dabei fällt mir auf, dass das alles viel umständlicher formuliert ist als nötig. Texte aus Schaltflächen auslesen um zu entscheiden was getan werden soll ist an sich ja schon unsauber, aber hier doch auch überhaupt nicht notwendig. Wenn man den Timer gestartet hat, dann steht da auf jeden Fall 'Start' drin. Und wenn 'Zurück' dein steht, kann man nicht neu starten. Also wäre es doch viel einfacher statt über den Text zu gehen, einfach das `command` entsprechend auszutauschen.

Der Test auf ``<= 50`` macht keinen Sinn, der kann weg.

Code: Alles auswählen

#!/usr/bin/env python3
from functools import partial
import tkinter as tk


def update(start_button, zeit_var, zeit_label):
    zeit_var.set(zeit_var.get() + 1)
    zeit_label['text'] = zeit_var.get()
    
    if zeit_var.get() >= 50:
        start_button.config(
            text='Zurück', command=start_button.quit, state=tk.NORMAL
        )
    else:
        zeit_label.after(300, update, start_button, zeit_var, zeit_label)


def on_start_button(start_button, zeit_var, zeit_label):
    start_button['state'] = tk.DISABLED
    update(start_button, zeit_var, zeit_label)
    

def main():
    fenster = tk.Tk()
    fenster.title('Zeit')
    
    zeit_var = tk.IntVar(value=0)
    
    zeit_label = tk.Label(fenster, width=50)
    zeit_label.grid(row=0, columnspan=5, padx=10, pady=10)

    start_button = tk.Button(fenster, text='Start', width=10)
    start_button.grid(row=5, columnspan=2, padx=10, pady=10)
    start_button['command'] = partial(
        on_start_button, start_button, zeit_var, zeit_label
    )
    
    fenster.mainloop()


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