pythonloopstkinterbackground-colortkinter-label

Changing Background Colour with a While Loop in Python


I am trying to configure a label in my window with the result of an iteration that produces the range of hexadecimal colour codes from #000000 to #FFFFFF so that the label’s background colour fades through all the possible colors between #000000 and #FFFFFF with a fraction of a second interval but it doesn’t seem to complete the loop before stating at #000000 again.

I have used the the print method to display the colour code being deployed with every loop and it doesn’t seem to be restarting as the display does.

from time import *
from time import sleep
from tkinter import *


def changing_color():
    global color
    while True:
        for i in range(0, 2**24):
            r = format(i, "02x")
            for j in range(0, 255):
                g = format(j, "02x")
                for k in range(0, 255):
                    b = format(k, "02x")
                    color = "#"+r+g+b
                    print(color)
                    date_label.config(bg=color)
                    day_label.config(bg=color)
                    window.update()
                    sleep(0.01)


def update_frame1():

    day_string = strftime("%A")
    day_label.config(text=day_string)

    date_string = strftime("%d, %B %Y")
    date_label.config(text=date_string)

    frame1.after(1000, update_frame1)

def update_frame2():

    time_string = strftime("%I:%M:%S:%p")
    time_label.config(text=time_string)

    frame2.after(1000, update_frame2)


window = Tk()
window.title("RO'Clock")

color = ""


frame1 = Frame(window)
frame1.pack(expand=True, fill="both")

frame2 = Frame(window)
frame2.pack(expand=True, fill="both")

date_label = Label(frame1, font=("Ink Free", 20))
date_label.pack(expand=True, fill="both")

day_label = Label(frame1, font=("Ink Free", 15))
day_label.pack(expand=True, fill="both")

time_label = Label(frame2, font=("Consolas", 30), fg="#00FF00", bg="black")
time_label.pack(expand=True, fill="both")


update_frame2()

update_frame1()

changing_color()


window.mainloop()

Solution

  • I cleaned your imports and translated it into an OOP approach for better readability and also to get rid of global variables. Your endless loop is now a recursive function using after and incrementing the color values each cycle.

    from tkinter import Tk, Frame, Label
    from time import strftime
    
    
    class RoClock(Tk):
        def __init__(self):
            super().__init__()
            self.title("RO'Clock")
            self.color = ""
    
            self.frame1 = Frame(self)
            self.frame1.pack(expand=True, fill="both")
    
            self.frame2 = Frame(self)
            self.frame2.pack(expand=True, fill="both")
    
            self.date_label = Label(self.frame1, font=("Ink Free", 20))
            self.date_label.pack(expand=True, fill="both")
    
            self.day_label = Label(self.frame1, font=("Ink Free", 15))
            self.day_label.pack(expand=True, fill="both")
    
            self.time_label = Label(self.frame2, font=("Consolas", 30), fg="#00FF00", bg="black")
            self.time_label.pack(expand=True, fill="both")
    
            self.update_frame2()
    
            self.update_frame1()
    
            self.changing_color(0, 0, 0)  # passing starting values
    
        def changing_color(self, k, j, i):  # new recursive function using after instead of endless while loop
            if k == 256:
                k = 0
                j += 1
            if j == 256:
                j = 0
                i += 1
            if i == 256:
                i = 0
    
            r = format(i, "02x")
            g = format(j, "02x")
            b = format(k, "02x")
            color = "#"+r+g+b
            print(color)
            self.date_label.config(bg=color)
            self.day_label.config(bg=color)
            self.after(1, self.changing_color, k+1, j, i)
    
        def update_frame1(self):
            day_string = strftime("%A")
            self.day_label.config(text=day_string)
    
            date_string = strftime("%d, %B %Y")
            self.date_label.config(text=date_string)
    
            self.frame1.after(1000, self.update_frame1)
    
        def update_frame2(self):
            time_string = strftime("%I:%M:%S:%p")
            self.time_label.config(text=time_string)
    
            self.frame2.after(1000, self.update_frame2)
    
    r = RoClock()
    r.mainloop()
    

    While this is working it is not pretty! To get rid of the flickering you have to rethink how you calculate your colors to get colors of equal brightness!