CustomTkinter icon indicating copy to clipboard operation
CustomTkinter copied to clipboard

flashes white when loading widgets

Open Forsaken-dev opened this issue 3 years ago • 9 comments
trafficstars

i am creating my first app with python and i choose customtkinter but I have this problem of "blinking" every time I load the widgets(e.g. frame, button, label)

I believe it is something related to color, I tried to set it later using ( label.configure(bg='dark_color') but without success, always the #DEDEDE (default tkinter color) wins

any solution for this? https://i.imgur.com/YIkDwZT.mp4 (click to play video/gif)

my same problem can be seen directly from the source code CustomTkinter-master\test\test_button_antialiasing.py you just spam

Forsaken-dev avatar Mar 26 '22 05:03 Forsaken-dev

Hey, I will have a look a this and test it out, but with the test_button_antialiasing.py I can see a very short blinking, but it isn't that long as yours. Maybe you can post your code somewhere, so I can have a look how you create the widgets dynamically.

TomSchimansky avatar Mar 30 '22 13:03 TomSchimansky

Hey, I will have a look a this and test it out, but with the test_button_antialiasing.py I can see a very short blinking, but it isn't that long as yours. Maybe you can post your code somewhere, so I can have a look how you create the widgets dynamically.

ok, here is some sample code to demonstrate

import tkinter, threading
import tkinter.messagebox
import customtkinter
import sys

customtkinter.set_appearance_mode("Dark")  # Modes: "System" (standard), "Dark", "Light"
customtkinter.set_default_color_theme("blue")  # Themes: "blue" (standard), "green", "dark-blue"


class App(customtkinter.CTk):

    WIDTH = 780
    HEIGHT = 520

    def __init__(self):
        super().__init__()

        self.title("CustomTkinter complex example")
        self.geometry(f"{App.WIDTH}x{App.HEIGHT}")
        # self.minsize(App.WIDTH, App.HEIGHT)

        self.protocol("WM_DELETE_WINDOW", self.on_closing)
        if sys.platform == "darwin":
            self.bind("<Command-q>", self.on_closing)
            self.bind("<Command-w>", self.on_closing)
            self.createcommand('tk::mac::Quit', self.on_closing)

        # ============ create two frames ============

        # configure grid layout (1x2)
        self.grid_columnconfigure(1, weight=1)
        self.rowconfigure(0, weight=1)

        self.frame_left = customtkinter.CTkFrame(master=self,
                                                 width=180,
                                                 corner_radius=0)
        self.frame_left.grid(row=0, column=0, sticky="nswe")

        self.frame_right = customtkinter.CTkFrame(master=self)
        self.frame_right.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)

        # ============ frame_left ============

        # configure grid layout
        self.frame_left.grid_rowconfigure(0, minsize=10)   # empty row with minsize as spacing
        self.frame_left.grid_rowconfigure(5, weight=1)  # empty row as spacing
        self.frame_left.grid_rowconfigure(8, minsize=20)    # empty row with minsize as spacing
        self.frame_left.grid_rowconfigure(11, minsize=10)  # empty row with minsize as spacing

        self.label_1 = customtkinter.CTkLabel(master=self.frame_left,
                                              text="CustomTkinter",
                                              text_font=("Roboto Medium", -16))  
        self.label_1.grid(row=1, column=0, pady=10, padx=10)

        self.button_1 = customtkinter.CTkButton(master=self.frame_left,
                                                text="SysInfo",
                                                fg_color=("gray75", "gray30"))
        self.button_1.grid(row=2, column=0, pady=10, padx=20)

        self.button_2 = customtkinter.CTkButton(master=self.frame_left,
                                                text="Create widgets loop",
                                                fg_color=("gray75", "gray30"),  
                                                command=self.start_thread)
        self.button_2.grid(row=3, column=0, pady=10, padx=20)



        for i in [0, 1, 2, 3]:
            self.frame_right.rowconfigure(i, weight=1)
        self.frame_right.rowconfigure(7, weight=10)
        self.frame_right.columnconfigure(0, weight=1)
        self.frame_right.columnconfigure(1, weight=1)
        self.frame_right.columnconfigure(2, weight=0)
        self.canvas = customtkinter.CTkCanvas(self.frame_right, bg="#2E2E2E", bd=0, highlightthickness=0, relief='ridge')
        self.canvas.propagate(0) 
        self.canvas.pack(fill='both', expand=True, pady=0)



    def start_thread(self):
        pr=threading.Thread(target=self.button_event)
        pr.start()

    def button_event(self):
        position = 0
        for program_element in range(7):

            self.label = customtkinter.CTkButton(self.canvas, text='test', height=60, hover_color=None, border_width=0, fg_color=("#DEDEDE", "#2E2E2E"))
            self.label.grid(row=position, column=0, sticky=tkinter.W)
            self.checkButton = customtkinter.CTkSwitch(self.canvas, text='', bd=0)
            self.canvas.create_window(550, (position+1)*40, anchor='nw', window=self.checkButton, height=26)
            position += 1
        self.after(30, self.button_event)    


    def on_closing(self, event=0):
        self.destroy()

    def start(self):
        self.mainloop()


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

configure line 93 to understand what it is about

thanks for your interest

Forsaken-dev avatar Mar 31 '22 01:03 Forsaken-dev

Unfortunately, I think I can't do anything about this, this is a problem of Tkinter itself. In the following video you can see that the normal tkinter buttons also appear white first and then get rendered properly, and so do the customtkinter widgets:

https://user-images.githubusercontent.com/66446067/162038796-d7b155c2-9763-46e5-a308-89082d5cafad.mov

Maybe you can put the buttons on a frame, which isn't placed on the window yet, and then place the frame when the window already opened, with a tkinter.after() call (a slight delay). But I didn't test this yet. But I can imagine that you don't see how the buttons get rendered one by one then.

TomSchimansky avatar Apr 06 '22 18:04 TomSchimansky

Unfortunately, I think I can't do anything about this, this is a problem of Tkinter itself. In the following video you can see that the normal tkinter buttons also appear white first and then get rendered properly, and so do the customtkinter widgets:

Bildschirmaufnahme.2022-04-06.um.19.57.49.mov Maybe you can put the buttons on a frame, which isn't placed on the window yet, and then place the frame when the window already opened, with a tkinter.after() call (a slight delay). But I didn't test this yet. But I can imagine that you don't see how the buttons get rendered one by one then.

I was pretty sure the problem was with tkinter itself

I will insist on a solution, as soon as I find it I will post back here to help others with the same problem.

congratulations for your work!

Forsaken-dev avatar Apr 06 '22 22:04 Forsaken-dev

still can't solve this problem =( any suggestion? so i need to solve this to launch my app

Forsaken-dev avatar May 11 '22 13:05 Forsaken-dev

Unfortunately, I think I can't do anything about this, this is a problem of Tkinter itself. In the following video you can see that the normal tkinter buttons also appear white first and then get rendered properly, and so do the customtkinter widgets:

Bildschirmaufnahme.2022-04-06.um.19.57.49.mov Maybe you can put the buttons on a frame, which isn't placed on the window yet, and then place the frame when the window already opened, with a tkinter.after() call (a slight delay). But I didn't test this yet. But I can imagine that you don't see how the buttons get rendered one by one then.

I did a test with pure tkinter and the result was this, without blinking

https://user-images.githubusercontent.com/99703655/167865086-56c0469a-2e5a-4400-87c2-62e4f1bd7cea.mp4

https://user-images.githubusercontent.com/99703655/167865107-608a36db-79ac-454e-8420-070b63fc68c5.mp4

on weaker devices, white flashes are even more visible

Forsaken-dev avatar May 11 '22 13:05 Forsaken-dev

Unfortunately, I think I can't do anything about this, this is a problem of Tkinter itself. In the following video you can see that the normal tkinter buttons also appear white first and then get rendered properly, and so do the customtkinter widgets:

Bildschirmaufnahme.2022-04-06.um.19.57.49.mov Maybe you can put the buttons on a frame, which isn't placed on the window yet, and then place the frame when the window already opened, with a tkinter.after() call (a slight delay). But I didn't test this yet. But I can imagine that you don't see how the buttons get rendered one by one then.

follows an example with pure tkinter

from tkinter import *
top = Tk()
for i in range(25):
    Entry(top, text=i, background='black').pack()
top.mainloop()

follows an example with customtkinter

import customtkinter
customtkinter.set_appearance_mode("dark")
customtkinter.set_default_color_theme("blue")
root_tk = customtkinter.CTk()
for i in range(25):
    customtkinter.CTkButton(master=root_tk, text=i).pack()
root_tk.mainloop()

Forsaken-dev avatar May 11 '22 14:05 Forsaken-dev

OK, I will look into this, this seems to be only a Windows problem, on macOS I tested your example code with 1000 CTkButton's and its completely smooth without any white flashing.

TomSchimansky avatar May 11 '22 21:05 TomSchimansky

OK, I will look into this, this seems to be only a Windows problem, on macOS I tested your example code with 1000 CTkButton's and its completely smooth without any white flashing.

After a lot of searching, I found something If I change the key of

Computer\HKEY_CURRENT_USER\Control Panel\Colors 
"ButtonFace"

to match the theme it seems to work, but it is necessary to restart the computer, which makes this option unfeasible maybe this helps us find the solution.

Forsaken-dev avatar May 12 '22 00:05 Forsaken-dev

I think the solution to these kind of problems would be to place the widgets you want to hide in a frame and forget or place the frame. This causes less flickering in my experience. But on slower machines there will be always some flickering when placing a lot of widgets and it also depends on the platform, on macOS there are not such problems for example.

TomSchimansky avatar Dec 02 '22 22:12 TomSchimansky