Anfängerfrage: Wann wird der geänderte Text übernommen ?

Fragen zu Tkinter.
Antworten
Werniman
User
Beiträge: 4
Registriert: Montag 18. Februar 2019, 13:37

Hallo,
ich arbeite gerade einen Anfängerkurs bei Youtube durch und bin da in einer Lektion auf dieses kleine Programm gestoßen:

Code: Alles auswählen

import tkinter

i = 0  

def handleButton(event):  
    global i
    i = i + 1
    w['text'] = "Hello World " + str(i) 

top = tkinter.Tk()

w = tkinter.Label(top, text="")

w.pack()

b = tkinter.Button(top, text="Drück mich!")

b.pack()

b.bind('<Button-1>', handleButton)

top.mainloop()
Dieses kleine Programm erzeugt ein Fenster mit einem Label. Das Label ist zunächst leer, wird erst später mit Inhalten gefüllt. Zudem ist noch ein Button enthalten. Drückt man da drauf, erscheint "Hello World" gefolgt von einer hochlaufenden Zahl. Und das Ganze läuft in einer Endlosschleife.
Nun, das Grundprinzip habe ich ja verstanden, aber an welcher Stelle wird eigentlich der geänderte Inhalt des Parameters Text ins Fenster eingeblendet ? Wenn das nächste Mal w.pack() durchlaufen wird ?
Das hiesse doch aber auch, dass die Erzeugung des Objektes w durch die Zeile w = tkinter.Label(top,text="") doch nur 1x pro Programmstart stattfinden würde und bei jedem weiteren Durchlauf übersprungen wird,da es bereits vorhanden ist...sonst würde doch sonst der gerade in der Funktion befüllte Textparameter doch wieder geleert, noch bevor der geänderte Inhalt überhaupt angezeigt wurde, oder ?
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

'w.pack()' wird nur ein mal "durchlaufen".
In Zeile 20 wird eine Funktion an den Button gebunden. Jedes mal wenn der Button gedrückt wird, wird die Funktion 'handleButton' aufgerufen.

Edit: Vergiss am besten auch gleich wieder das es 'global' gibt. Man will keine globalen Variablen in einem Programm. Das führt zu sehr unübersichtlichen, schlecht wartbaren und chaotischen Programme. Grafische Oberflächen zu schreiben ist nicht unbedingt anfängerfreundlich. Gewöhn dir auch gleich an sprechende Namen zu wählen und keine einbuchstabigen "Namen" die einem nichts sagen.

Vielleicht ist das Tutorial besser geeignet:
https://docs.python.org/3/tutorial/

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
juwido
User
Beiträge: 20
Registriert: Donnerstag 15. Dezember 2022, 13:41

@Werniman:
Also, stark vereinfacht zu deiner Frage:
Der Programmcode, wird so, wie er da steht, nur einmal durchlaufen. Dabei wird das Programmfenster mit den entsprechenden Elementen aufgebaut. Dazu wird im Hintergrund die "mainloop"-Methode zusammengebaut. Die wird dann am Ende aufgerufen und fragt die im Programm definierten Ereignisse ab und stößt die damit verknüpften Abläufe an....
Grüße juwido
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Werniman: Der geänderte Text wird angezeigt wenn `handleButton()` zu dem Code zurückkehrt der die Funktion aufgerufen hat und der irgendwo in der `mainloop()` von `tkinter`/Tk steckt.

Zu den Namen noch: Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase). Also `handle_button()`.

Und das mit den globalen Variablen, oder korrekter *keine* globalen Variablen, bedeutet bei GUIs, dass man jenseits von trivialen GUIs nicht um objektorientierte Programmierung (OOP) herum kommt. Also eigene Klassen. Das sollte man besser vor der GUI-Programmierung lernen, denn sonst hat man zwei grössere neue Themen, OOP und ereignisorientierte Programmierung, auf einmal.

Hier kommt man noch mit `functools.partial()` und `tkinter.IntVar` aus, aber das skaliert nicht.

Was in dem Beispiel auch falsch ist: Wenn man die Behandlung von Mausklicks direkt per `bind()` regelt, statt die `command`-Option von `Button` zu verwenden, dann verhält sich der Button anders als der Benutzer das normalerweise erwartet. Also zum Beispiel das das Ereignis erst beim loslassen ausgelöst wird, oder das man bei gedrückter Maustaste den Button auch wieder verlassen kann und dann kein Ereignis ausgelöst wird.

Das zusammenstückeln von Zeichenketten und Werten mittels ``+`` und `str()` ist eher BASIC als Python. Dafür gibt es die `format()`-Methode auf Zeichenketten und f-Zeichenkettenliterale.

Code: Alles auswählen

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


def handle_button(count_var, label):
    value = count_var.get() + 1
    count_var.set(value)
    label["text"] = f"Hello World {value}"


def main():
    root = tkinter.Tk()

    count_var = tkinter.IntVar()

    label = tkinter.Label(root)
    label.pack()
    tkinter.Button(
        root,
        text="Drück mich!",
        command=partial(handle_button, count_var, label),
    ).pack()

    root.mainloop()


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten