Ladebalken mit Python erstellen (tkinter)

Für eine grafische Python-Anwendung einen animierten Ladebalken zu erstellen mag zwar kein großes Hindernis darstellen, doch wie sinnvoll ist dieser schon, wenn sonst nichts weiter im Hintergrund ausgeführt wird und er zur Laufzeit praktisch ein einsames Dasein stiftet?!
Nachdem ich das Internet vergebens nach einer Lösung abgesucht habe, Kommando UND Ladebalken im friedlichem miteinander existieren zu lassen, möchte ich an dieser Stelle meine Lösung für dieses Problem vorstellen.

Der Schlüssel, um einen Ladebalken solange laufen zu lassen wie ein anderer Prozess läuft, liegt primär in die Auslagerung der Funktionen in einzelne Threads. 3 dieser Threads benötigen wir insgesamt für unser Vorhaben. Der erste startet den Ladebalken, der zweite führt das eigentliche Kommando aus und der dritte überprüft, ob das Kommando noch aktiv ist und schließt es wenn dem nicht so ist.
Es folgt der Code und eine anschließende Erklärung:

#!/usr/bin/python3

from tkinter import *
from tkinter import ttk
import time
import threading

window = Tk()
window.title("Progressbar")

### Window size
window_width = 300
window_height = 50

### Screen dimension, center point and positioning of the window
screen_width = window.winfo_screenwidth()
screen_height = window.winfo_screenheight()
center_x = int(screen_width/4 - window_width / 2)
center_y = int(screen_height/2 - window_height / 2)
window.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}')


### Klasse 'progressbar'
class progressbar():
  def start_progressbar(self):
    ### Erstellung des Ladefensters
    global loadingWindow
    loadingWindow = Toplevel(window)

    ### Position und Kosmetik
    loadingWindow.geometry(f'{300}x{95}+{center_x}+{center_y}')
    loadingWindow.overrideredirect(True)
    loadingWindow.lift()
    loadingWindow_frame = Frame(loadingWindow, highlightbackground="black", highlightthickness=2, bg='white')
    loadingWindow_frame.pack()

    ### Ladeanimation
    pb = ttk.Progressbar(loadingWindow_frame, orient='horizontal', mode='indeterminate', length=280)
    pb.pack(padx=10, pady=10)
    loadingWindow_lbl = Label(loadingWindow_frame, text="Prozess gestartet.\nBitte warten ...", font=("Arial", 15), bg='white')
    loadingWindow_lbl.pack()

    ### Start progressbar
    threading.Thread(target=pb.start()).start()

  def close_progressbar(self):
    loadingWindow.destroy()

  def check_process(self):
    z = proc.is_alive()
    while z is True:
      z = proc.is_alive()
    self.close_progressbar()

  def check_process_thread(self):
    threading.Thread(target=self.check_process).start()

### Klasse 'action_timer'
class action_timer():
  def action_timer_command(self):
    time.sleep(5)

  def action_timer_thread(self):
    global proc
    proc = threading.Thread(target=self.action_timer_command)
    proc.start()


progressbar_btn = Button(window, text="Prozess starten", bg='white', command=lambda: [progressbar().start_progressbar(), action_timer().action_timer_thread(), progressbar().check_process_thread()])
progressbar_btn.pack()

window.mainloop()

Eine kurze Anmerkung vorab. Das importierte Modul ‘time’ benutze ich lediglich, um das Beispiel-Kommando auszuführen. Die eigentlich wichtigen Module sind ‘tkinter’ und ‘threading’.
In den Zeilen 8-20 wird ein Fenster namens window initiiert, auf dem sich eine Schaltfläche befindet, die auf Druck ein Kommando und eine Ladeanimation starten soll.
Für dieses Kommando und für die Ladeanimation werden 2 Klassen erzeugt.
Die Klasse der Ladeanimation heisst progressbar (Zeile 24) und verfügt über insgesamt 4 Unterfunktionen. Die erste ‘start_progressbar’ ist für das Fenster samt Zeichnung der Ladeanimation zuständig (Zeile 25-44), die zweite ‘close_progressbar’ schließt das Fenster, welches in der ersten Unterfunktion erstellt werden würde (Zeile 46-47), die dritte ‘check_process’ wertet den boolschen Wert der Variable ‘proc’ aus und ruft die Unterfunktion ‘close_progressbar’ auf, falls der boolsche Wert False zurückgibt (Zeile 49-53). Diese Variable ‘proc’ wird später erstellt. Die vierte Unterfunktion ‘check_process_thread’ ruft die obere Unterfunktion ‘check_process’ derselben Klasse auf und startet diese als Thread, bzw. im Hintergrund. Dies ist notwendig, damit das Programm an dieser Stelle nicht hängen bleiben würde.
Die nächste Klasse lautet ‘action_timer’ (Zeile 59-66) und beinhaltet 2 Unterfunktionen, der erste ‘action_timer_command’ startet einen 8 sekündigen Sleep-Befehl (Zeile 59-61), der zweite ‘action_timer_thread’ (Zeile 63-66) ruft die erste Unterfunktion ebenfalls als Thread bzw. im Hintergrund auf. Dies geschieht auch hier um das Programm nicht zum Stillstand zu bewegen.

In Zeile 69 wird schlußendlich eine Schaltfläche erstellt, die auf Druck 3 Threads startet, nämlich die Ladeanimation, das ‘action_timer’-Kommando, und die Schleife, die das ‘action_timer’-Kommando abfragt ob es noch läuft und falls dem nicht mehr so ist, die Ladeanimation beendet (Zeile 69).

Das Ergebnis ist folgendes:

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Nach oben scrollen