Aufbau Tkinter-Programm

Fragen zu Tkinter.
Antworten
Ctrl-Z
User
Beiträge: 12
Registriert: Freitag 1. Mai 2015, 03:55

Hi,

ich habe mal eine richtig schön dämliche Frage... wie strukturiere ich eigentlich ein simples Tkinter-Programm?

Meine "Anforderung" als Pseudocode:

Code: Alles auswählen

readBlackbox
displayValuesFromBlackboxInGUI
if EventInGUI:
    readValuesFromGUI
    setValuesToBlackbox
Ich habe mal folgenden ultimativen Schrott-Code produziert und erziele wohl offensichtlich keinen Zähler, der auf dem Bildschirm von 0 bis 99 anzeigt...

Code: Alles auswählen

from Tkinter import *
import time
root = Tk()
v = StringVar()
w = Label(root,textvariable=v)
for i in range(100):
    v.set(str(i))
    time.sleep(0.1)
    w.config(textvariable=v)
    w.pack()
root.mainloop()
Der Code ist Schrott. Wie gehe ich richtig vor, siehe "Anforderung"?
:oops:
Ctrl-Z
User
Beiträge: 12
Registriert: Freitag 1. Mai 2015, 03:55

Ich schreibe mal gerade keine Antwort sondern eine Ergänzung:

Wenn ich mit der GUI-Programmierung fertig bin, im Sinne: Ich kann knöpfen drücken etc.... woher weiß die Hauptroutine denn, was "draußen" los ist? Wenn nix gedrückt ist, aber sich Werte ändern?

Danke....
BlackJack

@Ctrl-Z: Das Hauptprogramm *ist* die GUI, darum heisst die entsprechende Methode auch `mainloop()`. Und so lange *die* nicht läuft wird nichts angezeigt, aktualisiert, oder auch keine Benutzereingaben über die GUI verarbeitet. GUI-Programmierung krempelt die Kontrolle ziemlich um, nicht mehr der Programmierer bestimmt direkt den Programmablauf, sondern das GUI-Rahmenwerk bei dem man für Ereignisse die von der GUI erkannt oder ausgelöst werden Rückruffunktionen registrieren kann, die dann aufgerufen werden wenn das Ereignis (Benutzer hat Schaltfläche geklickt, Zeit ist abgelaufen, …) eingetreten ist. Die dürfen dann aber auch nur relativ kurz etwas machen, denn solange die Rückruffunktion läuft, reagiert die GUI nicht, die Funktion muss erst zu der Aufrufenden GUI-Hauptschleife zurückkehren bevor die GUI aktualisiert werden und wieder auf Benutzereingaben und andere Ereignisse reagieren kann.

Wenn tatsächlich nebenher Code laufen muss, dann muss man sich mit nebenläufiger Programmierung mit Threads beschäftigen. Und hat da dann gleich die Einschränkung, dass man die GUI nur aus dem Thread verändern darf in dem die `mainloop()` läuft, das heisst man muss mit anderen Threads die Werte haben die in der GUI dargestellt werden müssen, irgendwie regelmässig und threadsicher kommunizieren. In der Regel über `Queue.Queue`-Objekte die vom GUI-Thread mittels der `after()`-Methode auf Widgets regelmässig abgefragt werden.
BlackJack

Der Zähler mit `after()`:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
import Tkinter as tk


def update(label, numbers):
    try:
        number = next(numbers)
    except StopIteration:
        pass  # Intentionally ignore.
    else:
        label['text'] = str(number)
        label.after(100, update, label, numbers)


def main():
    root = tk.Tk()
    label = tk.Label(root)
    label.pack()
    update(label, iter(xrange(100)))
    root.mainloop()


if __name__ == '__main__':
    main()
Antworten