Hallo alle zusammen,
ich habe das Problem, dass wenn ich die Funktion "update" aufrufe meine Progressbar nicht Stück für Stück sich updatet,
sondern erst wenn die gesamte Funktion "update" abgelaufen ist. Dann sehe ich allerdings auch nur den letzten Wert
der Progressbar.
Ich danke schon einmal im Vorraus für euro Antworten.
from tkinter import *
from tkinter import ttk
import time
root = Tk()
root.geometry('600x400')
my_progress = ttk.Progressbar(root, orient=HORIZONTAL,length=200,mode='determinate')
my_progress.pack()
def update():
my_progress['value']= 0
time.sleep(0.5)
my_progress['value']= 20
time.sleep(0.5)
my_progress['value']= 40
time.sleep(0.5)
my_progress['value']= 60
time.sleep(0.5)
my_progress['value']= 80
time.sleep(0.5)
my_progress['value']= 100
time.sleep(0.5)
my_button = Button(root,text='Progress',command=update)
my_button.pack()
root.mainloop()
Progressbar updatet nicht
*-Importe benutzt man nicht, ein my-Präfix ist unsinnig, solange es nicht auch ein our_progress gibt. Globale Variablen darf man nicht benutzen; für GUIs bedeutet das, dass man fast zwangsläufig mit Klassendefinitionen arbeiten muß.
Bei GUIs darf es keine langlaufenden Funktionen geben, weil die GUI erst am Ende der Funktion weiterarbeitet.
Will man was wiederholt aufrufen, benutzt man after.
Bei GUIs darf es keine langlaufenden Funktionen geben, weil die GUI erst am Ende der Funktion weiterarbeitet.
Will man was wiederholt aufrufen, benutzt man after.
Code: Alles auswählen
import tkinter as tk
from tkinter import ttk
from functools import partial
def update(progress, value):
progress['value']= value
if value < 100:
progress.after(500, update, progress, value + 20)
def main():
root = tk.Tk()
progress = ttk.Progressbar(root, orient=tk.HORIZONTAL, length=200, mode='determinate')
progress.pack()
tk.Button(root,text='Progress',command=partial(update, progress, 0)).pack()
root.mainloop()
if __name__ == "__main__":
main()
Vielen Dank für die schnelle Antwort Sirius3.
Leider reichen meine Python Kenntnisse nicht aus, um mit deiner Antwort etwas anzufangen.
Ich habe meinen Code umgeschreiben, aber leider habe ich noch immer das gleiche Problem.
In deinem Beispielcode ist es so, dass der Fortschritt der Progressbar durch die Zeile "progress.after(500, update, progress, value + 20)" in der Funktion "update" stattfindet. Aber ich will, dass der Fortschritt der Progressbar in der Funktion "main" bestimmt wird.
Du musst dir vorstellen, dass die Zeilen "time.sleep(0.5) eigentlich eigenständige Funktionen mit "SQL" Abfragen sind.
Ich will halt visuell mitkriegen, wie weit die 5 SQL Abfragen abgearbeitet sind.
Ich habe mal deinen Code auf mein Problem umgeschrieben, aber leider funktioniert das nicht.
Wäre nett, wenn jamand mir hier helfen könnte:
import tkinter as tk
from tkinter import ttk
from functools import partial
import time
def update(progress, value):
progress['value']= value
#if value < 100:
#progress.after(500, update, progress, value + 20)
def main():
root = tk.Tk()
progress = ttk.Progressbar(root, orient=tk.HORIZONTAL, length=200, mode='determinate')
progress.pack()
#tk.Button(root,text='Progress',command=partial(update, progress, 20)).pack()
partial(update, progress, 20)()
time.sleep(0.5)
partial(update, progress, 40)()
time.sleep(0.5)
partial(update, progress, 60)()
time.sleep(0.5)
partial(update, progress, 80)()
time.sleep(0.5)
partial(update, progress,100)()
time.sleep(0.5)
root.mainloop()
if __name__ == "__main__":
main()
Leider reichen meine Python Kenntnisse nicht aus, um mit deiner Antwort etwas anzufangen.
Ich habe meinen Code umgeschreiben, aber leider habe ich noch immer das gleiche Problem.
In deinem Beispielcode ist es so, dass der Fortschritt der Progressbar durch die Zeile "progress.after(500, update, progress, value + 20)" in der Funktion "update" stattfindet. Aber ich will, dass der Fortschritt der Progressbar in der Funktion "main" bestimmt wird.
Du musst dir vorstellen, dass die Zeilen "time.sleep(0.5) eigentlich eigenständige Funktionen mit "SQL" Abfragen sind.
Ich will halt visuell mitkriegen, wie weit die 5 SQL Abfragen abgearbeitet sind.
Ich habe mal deinen Code auf mein Problem umgeschrieben, aber leider funktioniert das nicht.
Wäre nett, wenn jamand mir hier helfen könnte:
import tkinter as tk
from tkinter import ttk
from functools import partial
import time
def update(progress, value):
progress['value']= value
#if value < 100:
#progress.after(500, update, progress, value + 20)
def main():
root = tk.Tk()
progress = ttk.Progressbar(root, orient=tk.HORIZONTAL, length=200, mode='determinate')
progress.pack()
#tk.Button(root,text='Progress',command=partial(update, progress, 20)).pack()
partial(update, progress, 20)()
time.sleep(0.5)
partial(update, progress, 40)()
time.sleep(0.5)
partial(update, progress, 60)()
time.sleep(0.5)
partial(update, progress, 80)()
time.sleep(0.5)
partial(update, progress,100)()
time.sleep(0.5)
root.mainloop()
if __name__ == "__main__":
main()
@Borneo: Was du denkst, was du willst, funktioniert halt nicht. GUI-Frameworks haben eine Loop, mit dem sie sich selbst zeichnen. Bei Tkinter heißt der sogar mainloop.
Der mainloop darf nicht unterbrochen noch durch im selben Thread laufende Dinge verzögert werden.
Du tust da schon Dinge, bevor du den mainloop startest. Das kann nicht funktionieren, weil eben dieser Loop die Darstellung neu zeichnen würde.
Den Loop vorher zu starten und in der selben Funktion danach Dinge tun, funktioniert auch nicht, denn der mainloop wird nicht mehr verlassen.
Die Lösung hat Sirius dir bereits genannt. Du musst dich mit "after" und mindestens mit Funktionen beschäftigen.
GUI-Origrammierung hat eine gewisse Komplexität.
Der mainloop darf nicht unterbrochen noch durch im selben Thread laufende Dinge verzögert werden.
Du tust da schon Dinge, bevor du den mainloop startest. Das kann nicht funktionieren, weil eben dieser Loop die Darstellung neu zeichnen würde.
Den Loop vorher zu starten und in der selben Funktion danach Dinge tun, funktioniert auch nicht, denn der mainloop wird nicht mehr verlassen.
Die Lösung hat Sirius dir bereits genannt. Du musst dich mit "after" und mindestens mit Funktionen beschäftigen.
GUI-Origrammierung hat eine gewisse Komplexität.
Wenn Deine Python-Kenntnisse noch nicht reichen, dann ist vielleicht die Aufgabe, die Du Dir vorgenommen hast, noch zu groß. GUI-Programmierung ist ein sehr komplexes Thema, weil man von einem linearen Programmablauf zu einem umdenken muß, wo man auf Ereignisse reagieren muß. Dazu muß man sich noch den Zustand des Programms zwischen den Ereignisbehandlungen merken, was man mit Klassen machen muß.
Bedeutet, man muß Funktionen gut beherrschen, Objektorientierte Programmierung gut beherrschen und dann kann man sich dem Thema GUI zuwenden, um ein paar einfache Projekte damit umzusetzen.
Eine große Stufe schwieriger wird es dann, wenn noch Langlaufende Berechnungen dazu kommen, denn dann muß man sich mit dem Abarbeiten von Aufgaben im Hintergrund beschäftigen, der Kommunikation mit dem Vordergrund-GUI-Prozess usw.
Ein Minimal-Beispiel könnte so aussehen:
Bedeutet, man muß Funktionen gut beherrschen, Objektorientierte Programmierung gut beherrschen und dann kann man sich dem Thema GUI zuwenden, um ein paar einfache Projekte damit umzusetzen.
Eine große Stufe schwieriger wird es dann, wenn noch Langlaufende Berechnungen dazu kommen, denn dann muß man sich mit dem Abarbeiten von Aufgaben im Hintergrund beschäftigen, der Kommunikation mit dem Vordergrund-GUI-Prozess usw.
Ein Minimal-Beispiel könnte so aussehen:
Code: Alles auswählen
import random
import tkinter as tk
from tkinter import ttk
from threading import Thread
from queue import Queue, Empty
import time
def do_processing(queue):
progress = 0
while progress < 100:
time.sleep(random.random())
progress += random.randint(2, 10)
queue.put(progress)
class Window(tk.Tk):
def __init__(self):
super().__init__()
self.progress = ttk.Progressbar(self, orient=tk.HORIZONTAL, length=200, mode='determinate')
self.progress.pack()
self.start_button = tk.Button(self, text='Progress', command=self.start_process)
self.start_button.pack()
self.thread = None
self.queue = None
def start_process(self):
if self.thread is None:
self.start_button['state'] = tk.DISABLED
self.queue = Queue()
self.thread = Thread(target=do_processing, args=(self.queue,))
self.update()
self.thread.start()
def stop_process(self):
self.thread.join()
self.start_button['state'] = tk.ACTIVE
self.thread = None
self.queue = None
def update(self):
try:
value = self.queue.get_nowait()
self.progress['value']= value
if value >= 100:
self.stop_process()
return
except Empty:
pass
self.after(100, self.update)
def main():
root = Window()
root.mainloop()
if __name__ == "__main__":
main()
- __blackjack__
- User
- Beiträge: 14053
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Borneo: ``partial(update, progress, 20)()`` ist eine umständliche Art ``update(progress, 20)`` zu schreiben. Das macht keinen Sinn das mit `partial()` unnötig komplizierter zu machen. Und da die Funktion letztlich nur aus einer Zeile besteht, könnte man auch gleich ``progress['value'] = 20`` schreiben.
Muss es denn unbedingt eine GUI-Anwendung sein? Es gibt ja auch diverse Möglichkeiten Fortschrittsbalken in der Konsole anzuzeigen. Hier ein Beispiel mit `rich`:
Muss es denn unbedingt eine GUI-Anwendung sein? Es gibt ja auch diverse Möglichkeiten Fortschrittsbalken in der Konsole anzuzeigen. Hier ein Beispiel mit `rich`:
Code: Alles auswählen
#!/usr/bin/env python3
from time import sleep
from rich.progress import track
def main():
progress = track(range(5))
next(progress)
sleep(0.5)
next(progress)
sleep(0.5)
next(progress)
sleep(0.5)
next(progress)
sleep(0.5)
next(progress)
sleep(0.5)
next(progress, None)
if __name__ == "__main__":
main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari