TomSchimansky / CustomTkinter

A modern and customizable python UI-library based on Tkinter
MIT License
11.43k stars 1.07k forks source link

CTkFrame question #1078

Closed orztrickster closed 1 year ago

orztrickster commented 1 year ago

This is a progress bar that can show a percentage But it seems that after running for a while, the numbers will go to the upper left corner of the screen I'm not sure if this could be a bug or a problem with my programming

import tkinter
import customtkinter
import random

customtkinter.set_appearance_mode("dark")  # Modes: system (default), light, dark
customtkinter.set_default_color_theme("blue")  # Themes: blue (default), dark-blue, green

app = customtkinter.CTk()  # create CTk window like you do with the Tk window
app.title("GUI")
app.geometry("500x500")

class Progressbar_and__Percentage():
    def __init__(self,class_frame,name,quantity=1,logo_label_top_name=""):

        for i in range(quantity):
            if(i==0):
                self.progressbar_Frame=[]
                self.logo_label_top=[]
                self.progressbar=[]
                self.logo_label=[]
                self.jjj=[]
            self.progressbar_Frame.append([])
            self.logo_label_top.append([])
            self.progressbar.append([])
            self.logo_label.append([])
            self.jjj.append(0)
        self.logo = customtkinter.CTkLabel(class_frame, text=str(name), font=customtkinter.CTkFont(family="Microsoft JhengHei",size=15, weight="bold"))
        self.logo.grid(row=0, column=0, padx=5, pady=(15, 10))

        for i in range(quantity):
            self.progressbar_Frame[i]= customtkinter.CTkFrame(class_frame,fg_color="transparent") 
            self.progressbar_Frame[i].grid(row=i+1, column=0,pady=0)
            if(quantity!=1):
                logo_label_top_text=logo_label_top_name+str(i)
            else:
                logo_label_top_text=logo_label_top_name
            if(logo_label_top_name!=""):
                self.logo_label_top[i] = customtkinter.CTkLabel(self.progressbar_Frame[i], text=logo_label_top_text, font=customtkinter.CTkFont(family="Microsoft JhengHei",size=10, weight="bold")) 
                self.logo_label_top[i].grid(row=0, column=0, padx=5, pady=0,sticky=tkinter.W, ipadx=5)

                self.progressbar[i]= customtkinter.CTkProgressBar(self.progressbar_Frame[i],mode="determinate",width=100)
                self.progressbar[i].set(0)
                self.progressbar[i].grid(row=0, column=1,padx=5, pady=0, ipadx=10)

                self.logo_label[i] = customtkinter.CTkLabel(self.progressbar_Frame[i], text="0%", font=customtkinter.CTkFont(family="Microsoft JhengHei",size=10, weight="bold"))
                self.logo_label[i].grid(row=0, column=2, padx=5, pady=0,sticky=tkinter.E, ipadx=5)
            else:

                self.progressbar[i]= customtkinter.CTkProgressBar(self.progressbar_Frame[i],mode="determinate",width=100)  
                self.progressbar[i].set(0)
                self.progressbar[i].grid(row=0, column=0,padx=5, pady=0, ipadx=10)

                self.logo_label[i] = customtkinter.CTkLabel(self.progressbar_Frame[i], text="0%", font=customtkinter.CTkFont(family="Microsoft JhengHei",size=10, weight="bold"))
                self.logo_label[i].grid(row=0, column=2, padx=5, pady=0,sticky=tkinter.E, ipadx=5)
    def run(self,schedule_percentage,N=0):
        if(schedule_percentage==0):
            self.logo_label[N].destroy()
        self.progressbar[N].set(schedule_percentage/100)  

        self.logo_label[N] = customtkinter.CTkLabel(self.progressbar_Frame[N], text=str(int(schedule_percentage))+"%", font=customtkinter.CTkFont(family="Microsoft JhengHei",size=10, weight="bold")) 
        self.logo_label[N].grid(row=0, column=2, padx=5, pady=0,sticky=tkinter.E, ipadx=5)

frame= customtkinter.CTkFrame(app)   
frame.grid(row=0, column=0,padx=10, pady=10,sticky=tkinter.W)       
PPP=Progressbar_and__Percentage(frame,"Progressbar",quantity=6,logo_label_top_name="CPU")

N=[0,0,0,0,0,0]

def aa():
    global N
    for j in range(20):
        i=random.randint(0,5)
        N[i]+=1
        if(N[i]==101):
            N[i]=0

        PPP.run(N[i],i)

    app.after(100,aa)

app.after(500,aa)

app.mainloop()
TomSchimansky commented 1 year ago

The problem is that you create a new label every time you change the text:

    def run(self, schedule_percentage, N=0):
        if schedule_percentage == 0:
            self.logo_label[N].destroy()
        self.progressbar[N].set(schedule_percentage / 100)

        self.logo_label[N] = customtkinter.CTkLabel(self.progressbar_Frame[N], text=str(int(schedule_percentage)) + "%",
                                                    font=customtkinter.CTkFont(family="Microsoft JhengHei", size=10, weight="bold"))
        self.logo_label[N].grid(row=0, column=2, padx=5, pady=0, sticky=tkinter.E, ipadx=5)

I don't know if that's causing your problem, but for me that's causing that the app freezes after a certain time. You have to configure the existing the label.

TomSchimansky commented 1 year ago

That's how you would correctly implement your example with classes:

import customtkinter
import random

customtkinter.set_appearance_mode("dark")

class LabeledProgressbar(customtkinter.CTkFrame):
    def __init__(self, *args, name="", **kwargs):
        super().__init__(*args, fg_color="transparent", **kwargs)

        self.name_label = customtkinter.CTkLabel(self, width=40, text=name, font=customtkinter.CTkFont(family="Microsoft JhengHei", size=10, weight="bold"))
        self.name_label.grid(row=0, column=0, padx=5, pady=0, sticky=customtkinter.W)

        self.progressbar = customtkinter.CTkProgressBar(self, mode="determinate", width=100)
        self.progressbar.set(0)
        self.progressbar.grid(row=0, column=1, padx=5, pady=0)

        self.percent_label = customtkinter.CTkLabel(self, width=40, text="0%", font=customtkinter.CTkFont(family="Microsoft JhengHei", size=10, weight="bold"))
        self.percent_label.grid(row=0, column=2, padx=5, pady=0, sticky=customtkinter.E)

    def set_percent(self, value):
        self.progressbar.set(value / 100)
        self.percent_label.configure(text=f"{value}%")

class ProgressbarAndPercentage(customtkinter.CTkFrame):
    def __init__(self, *args, name="", progressbar_names=(), **kwargs):
        super().__init__(*args, **kwargs)

        self.logo = customtkinter.CTkLabel(self, text=name, font=customtkinter.CTkFont(family="Microsoft JhengHei", size=15, weight="bold"))
        self.logo.grid(row=0, column=0, padx=5, pady=(15, 10))

        self.progressbar_names = progressbar_names
        self.progressbar_frames_dict = {}
        for i in range(len(self.progressbar_names)):
            labeled_progressbar_frame = LabeledProgressbar(self, name=self.progressbar_names[i])
            labeled_progressbar_frame.grid(row=i+1, column=0)
            self.progressbar_frames_dict[self.progressbar_names[i]] = labeled_progressbar_frame

    def set_progressbar_value(self, name, value):
        self.progressbar_frames_dict[name].set_percent(value)

class App(customtkinter.CTk):
    def __init__(self):
        super().__init__()

        self.title("GUI")
        self.geometry("500x500")

        self.cpu_names = ["CPU 1", "CPU 2", "CPU 3", "CPU 4", "CPU 5", "CPU 6"]
        self.cpu_values = [0, 0, 0, 0, 0, 0]

        self.ppp = ProgressbarAndPercentage(self, name="Progressbar", progressbar_names=self.cpu_names)
        self.ppp.grid(row=0, column=0, padx=10, pady=10, sticky=customtkinter.W)

        self.ppp.set_progressbar_value("CPU 5", 30)  # set single progressbar value

        self.loop()  # start loop

    def loop(self):
        for i in range(len(self.cpu_names)):

            self.cpu_values[i] += random.randint(0, 5)
            if self.cpu_values[i] > 100:
                self.cpu_values[i] = 0

            self.ppp.set_progressbar_value(self.cpu_names[i], self.cpu_values[i])

        self.after(100, self.loop)

if __name__ == "__main__":
    app = App()
    app.mainloop()

I changed a few variable names, but the functionality should be somehow the same. I thought referencing the individual progress bars by their name much easier...