CustomTkinter
CustomTkinter copied to clipboard
Keep current window sizing when switching between modes.
I tested this out with the complex example script as well.
Whenever I change mode from light to dark or vice versa, the window size goes back to the size defined through class attributes, WIDTH and HEIGHT. If I don't set these explicitly, it goes back to whatever it size it first opened at. I'm still getting into tkinter so I don't know how it determines window size if it's not passed explicitly.
For my own gui I also tried running the following.
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
self.state('zoomed')
WIDTH = self.winfo_height()
HEIGHT = self.winfo_width()
X_POS = self.winfo_x()
Y_POS = self.winfo_y()
self.title("fullscreen")
self.myfont = font.Font(family="Courier", size=14)
self.geometry(f"{WIDTH}x{HEIGHT}+{X_POS}+{Y_POS}")
I wanted the window to cover the full screen, minus task bar, I used self.state('zoomed'). I tried to get the appropriate values from this and put them into geometry to see if this would at least push the window to it's that specific size on a state change but it doesn't. Ideally however, I would like it to just keep whatever size it has when the mode changes, even after it has been changed by the user.
For now I just put the self.state('zoomed') in the change mode function, but then you do see the window reset itself. I would prefer if the transition between light and dark was smoother.
Is there anyway to make this happen?
I can reproduce this on Windows 11. The reason for this is that I need to .withdraw() and .deiconify() the window, so that the titlebar color change becomes visible. And when you .withdraw() and then right after this .deiconify(), somehow the zoomed state is lost with tkinter. Maybe I will add some lines, so that I save if the state was "zoomed" before I withdraw, and then apply it again afterwards, but with this method, I don't catch if the user maximised the window with the maximise button on the top right. I will try to find a solution for this.
Thanks for looking into it!
From tkinter's perspective I think withdraw and deiconify are states themselves, so I doubt there is anyway to keep the zoom state around. And then I think the issue is that applying the zoom state in windows always creates this 'filling' animation, and this is what creates the flicker when I change modes. I am not sure if this can be helped.
However, I tested on my system and it looks like tkinter also registers the window state as zoomed when set by the user (via aerosnap or the maximize button). I am still on windows 10 though, so it might not work anymore. If it does though, your solution should already work as you proposed.
I now have the following change-mode method as a workaround, in case anyone wants it
def change_mode(self):
WIDTH = self.winfo_width()
HEIGHT = self.winfo_height()
X_POS = self.winfo_x()
Y_POS = self.winfo_y()
current_state = self.state()
self.state('normal')
self.geometry("%dx%d+%d+%d" % (WIDTH, HEIGHT, X_POS, Y_POS))
if self.switch_1.get() == 1:
customtkinter.set_appearance_mode("dark")
else:
customtkinter.set_appearance_mode("light")
if current_state == 'zoomed':
self.state('zoomed')
The zoomed state animation looks a little less grating when I first move it to a normal state of the same size and position. There's still a flicker, but it's a bit smaller visually.
The following code works on Linux, but I don't know if the same is correct to Windows, and Mac. The window doesn't resize and the color mode changes.
import tkinter
import customtkinter # <- import the CustomTkinter module
from functools import partial
DARK_MODE = "dark"
customtkinter.set_appearance_mode(DARK_MODE)
customtkinter.set_default_color_theme("blue")
class App(customtkinter.CTk):
color = "dark"
def __init__():
super().__init__()
def toggle_color(self):
if App.color == "dark":
App.color = "light"
return "light"
else:
App.color = "dark"
return "dark"
def alter_color(self):
self.color = self.toggle_color()
customtkinter.set_appearance_mode(self.color)
def __init__(self):
super().__init__()
# self.state('withdraw')
self.title("fullscreen")
WIDTH = self.winfo_screenwidth()
print("Width: " + str(WIDTH))
HEIGHT = self.winfo_screenheight()
print("Height: " + str(HEIGHT))
X_POS = self.winfo_x()
print("X_POS: " + str(X_POS))
Y_POS = self.winfo_y()
print("Y_POS: " + str(Y_POS))
# self.myfont = font.Font(family="Courier", size=14)
self.geometry(f"{WIDTH}x{HEIGHT}+{X_POS}+{Y_POS}")
bt = customtkinter.CTkButton(self, width=100, height=50, text="Click", command=self.alter_color)
bt.place(anchor="center", relx="0.5", rely="0.5")
a = App()
a.mainloop()
Hope it helps
Switching between modes now preserves the "zoomed", "withdraw" and "iconic" state on Windows with version 4.5.11.