Progress Bar als GUI

Hier werden alle anderen GUI-Toolkits sowie Spezial-Toolkits wie Spiele-Engines behandelt.
Antworten
Mirk_Man
User
Beiträge: 1
Registriert: Freitag 4. Februar 2022, 10:59

Guten Tag,

Zeil soll es sein ein Programm zu haben, in dem in verschiedenen Funktionen verschiedene Prozesse ablaufen Das nenne ich der übersicht halber mal "rechnen". Ich will nun während ich "rechne" auf eine dritte Funktion zugreifen, in der ich zuerst eine Progress Bar erstelle und dann immer wieder update.
Bisher und in sämtlichen Anleitungen und Foren habe ich es nur genau anders herum gesehen. Also eine Funktion in der die Progressbar erstellt wird ruft eine dritte Funktion auf, in der "gerechnet" wird. Das führt aber dazu dass ich riesige Arrays quer durch die Funktionen schieben muss und das erscheint mir nicht so elegant.

Hier mal der Code, wie ich ihn bisher habe.

Im Prinzip steckt mein Problem bei "button1", weil dort ja die funktion "Start" aufgerufen wird, die die Progressbar updatet...

Vielen Dank für Eure Hilfe! :)

Code: Alles auswählen

from tkinter import *
from tkinter.ttk import *
import time

images = 100

class Rechnen:
    def __init__(self):
        pass
    def func_Rechnen(self, d):
        time.sleep(0.05)
        return 5 + d

class Progress:
    def start(self ,percent, text, bar, images):
        
        download = 0
        speed = 1
        
        while(download<images):
        
            d=10
            
            print(Rechnen.func_Rechnen(self, d))
            
            bar['value']+=(speed/images)*100
            download+=speed
            percent.set(str(int((download/images)*100))+"%")
            text.set(str(download)+"/"+str(images)+" Images Saved")
            self.progwin.update_idletasks()
    
    def __init__(self, images):
        self.progwin = Tk()
        percent = StringVar()
        text = StringVar()
    
        bar = Progressbar(self.progwin,orient=HORIZONTAL,length=300)
        bar.pack(pady=10)
        
        percentLabel = Label(self.progwin,textvariable=percent).pack()
        taskLabel = Label(self.progwin,textvariable=text).pack()
        
        button1 = Button(self.progwin,text="download",command=self.start(percent, text, bar, images))
        
        self.progwin.mainloop()
        

progress = Progress(images)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

GUI-Programme erfordern eben eine ganz bestimmten Aufbau des Programms.
Rechen-Operationen müssen in einem Hintergrundthread laufen, der über Queues mit dem Hauptthread, in dem die GUI läuft kommuniziert. Dazu gibt es hier im Forum hunderte Beispiele.
Dort werden auch die anderen Probleme Deines Skripts angesprochen, wie *-Importe, mainloop in __init__, update_ideltasks, Stringzusammenstückelung, Klassen, die keine sind, usw.
Bei `StringVar` fehlt das Hauptfenster als Argument.
`percentLabel` und `taskLabel` werden nicht verwendet, steht sowieso nur None drin.
Der Button wird nicht ge`pack`t. Dafür wird die Funktion `start` direkt aufgerufen.

Du hast eine Klasse, also sind die Argumente von `start` eigentlich überflüssig, da sie Attribute der Instanz sein sollten.

Code: Alles auswählen

import tkinter as tk
import threading
import queue
from tkinter import ttk
import time

def rechnen(queue, images):
    for download in range(1, images + 1):
        queue.put((download, images))
        time.sleep(0.05)

class Progress:
    def __init__(self, images):
        self.images = images
        self.queue = queue.Queue()
        self.thread = None

        self.progwin = tk.Tk()
        self.percent = tk.StringVar(self.progwin)
        self.text = tk.StringVar(self.progwin)
    
        self.bar = ttk.Progressbar(self.progwin,orient=tk.HORIZONTAL, length=300, maximum=1)
        self.bar.pack(pady=10)
        
        tk.Label(self.progwin, textvariable=self.percent).pack()
        tk.Label(self.progwin, textvariable=self.text).pack()
        tk.Button(self.progwin,text="download",command=self.start).pack()
    
    def update(self):
        try:
            download, images = self.queue.get(block=False)
            progress = download / images
            self.bar['value'] = progress
            self.percent.set(f"{progress:.0%}")
            self.text.set(f"{download}/{images} Images Saved")
        except queue.Empty:
            pass
        self.progwin.after(10, self.update)
    
    def start(self):
        self.thread = threading.Thread(target=rechnen, args=(self.queue, self.images))
        self.thread.start()
        self.update()

        
def main():
    progress = Progress(100)
    progress.progwin.mainloop()

if __name__ == "__main__":
    main()
einfachTobi
User
Beiträge: 491
Registriert: Mittwoch 13. November 2019, 08:38

Mirk_Man hat geschrieben: Freitag 4. Februar 2022, 11:10 Das führt aber dazu dass ich riesige Arrays quer durch die Funktionen schieben muss und das erscheint mir nicht so elegant.
Unabhängig von deinem Problem, ist das wiederum kein Problem. Es handelt sich dabei um die gleichen Objekte, es wird lediglich die Referenz übergeben, weshalb es kein Problem ist auch Variablen, welche große Datenmengen enthalten über Funktionsargumente "umherzureichen".

Code: Alles auswählen

def foo(variable):
    print(id(variable))

bar = 23
print(id(bar))
foo(bar)
Antworten