added scaling to every widget

This commit is contained in:
Tom Schimansky 2022-04-21 18:34:58 +02:00
parent 59a8574f4c
commit 6342bf8034
15 changed files with 193 additions and 98 deletions

View File

@ -14,9 +14,10 @@ from .widgets.ctk_canvas import CTkCanvas
from .widgets.ctk_switch import CTkSwitch
from .widgets.ctk_toplevel import CTkToplevel
from .customtkinter_settings import CTkSettings
from .ctk_settings import CTkSettings
from .appearance_mode_tracker import AppearanceModeTracker
from .theme_manager import CTkThemeManager
from .scaling_tracker import ScalingTracker
from distutils.version import StrictVersion as Version
import tkinter

View File

@ -2,9 +2,9 @@ import tkinter
import sys
from .ctk_canvas import CTkCanvas
from ..customtkinter_theme_manager import CTkThemeManager
from ..customtkinter_settings import CTkSettings
from ..customtkinter_draw_engine import CTkDrawEngine
from ..theme_manager import CTkThemeManager
from ..ctk_settings import CTkSettings
from ..ctk_draw_engine import CTkDrawEngine
from .widget_base_class import CTkBaseClass
@ -65,8 +65,8 @@ class CTkButton(CTkBaseClass):
self.canvas = CTkCanvas(master=self,
highlightthickness=0,
width=self.width,
height=self.height)
width=self.width * self.scaling,
height=self.height * self.scaling)
self.canvas.grid(row=0, column=0, rowspan=2, columnspan=2, sticky="nsew")
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
@ -75,9 +75,7 @@ class CTkButton(CTkBaseClass):
self.canvas.bind("<Leave>", self.on_leave)
self.canvas.bind("<Button-1>", self.clicked)
self.canvas.bind("<Button-1>", self.clicked)
# Each time an item is resized due to pack position mode, the binding Configure is called on the widget
self.bind('<Configure>', self.update_dimensions)
self.bind('<Configure>', self.update_dimensions_event)
self.set_cursor()
self.draw() # initial draw
@ -90,7 +88,10 @@ class CTkButton(CTkBaseClass):
self.grid_columnconfigure(1, weight=1)
def draw(self, no_color_updates=False):
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width, self.height, self.corner_radius, self.border_width)
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width * self.scaling,
self.height * self.scaling,
self.corner_radius * self.scaling,
self.border_width * self.scaling)
if no_color_updates is False or requires_recoloring:
@ -115,7 +116,9 @@ class CTkButton(CTkBaseClass):
if self.text is not None and self.text != "":
if self.text_label is None:
self.text_label = tkinter.Label(master=self, font=self.text_font, textvariable=self.textvariable)
self.text_label = tkinter.Label(master=self,
font=self.apply_font_scaling(self.text_font),
textvariable=self.textvariable)
self.text_label.bind("<Enter>", self.on_enter)
self.text_label.bind("<Leave>", self.on_leave)
@ -172,26 +175,35 @@ class CTkButton(CTkBaseClass):
# create grid layout with just an image given
if self.image_label is not None and self.text_label is None:
self.image_label.grid(row=0, column=0, rowspan=2, columnspan=2, sticky="", pady=self.border_width)
self.image_label.grid(row=0, column=0, rowspan=2, columnspan=2, sticky="", pady=self.border_width * self.scaling)
# create grid layout with just text given
if self.image_label is None and self.text_label is not None:
self.text_label.grid(row=0, column=0, padx=self.corner_radius, pady=self.border_width, rowspan=2, columnspan=2, sticky="")
self.text_label.grid(row=0, column=0, rowspan=2, columnspan=2, sticky="",
padx=self.corner_radius * self.scaling, pady=self.border_width * self.scaling)
# create grid layout of image and text label in 2x2 grid system with given compound
if self.image_label is not None and self.text_label is not None:
if self.compound == tkinter.LEFT or self.compound == "left":
self.image_label.grid(row=0, column=0, padx=(max(self.corner_radius, self.border_width), 2), sticky="e", rowspan=2, columnspan=1, pady=self.border_width)
self.text_label.grid(row=0, column=1, padx=(2, max(self.corner_radius, self.border_width)), sticky="w", rowspan=2, columnspan=1, pady=self.border_width)
self.image_label.grid(row=0, column=0, sticky="e", rowspan=2, columnspan=1,
padx=(max(self.corner_radius * self.scaling, self.border_width * self.scaling), 2), pady=self.border_width * self.scaling)
self.text_label.grid(row=0, column=1, sticky="w", rowspan=2, columnspan=1,
padx=(2, max(self.corner_radius * self.scaling, self.border_width * self.scaling)), pady=self.border_width * self.scaling)
elif self.compound == tkinter.TOP or self.compound == "top":
self.image_label.grid(row=0, column=0, padx=max(self.corner_radius, self.border_width), sticky="s", columnspan=2, rowspan=1, pady=(self.border_width, 2))
self.text_label.grid(row=1, column=0, padx=max(self.corner_radius, self.border_width), sticky="n", columnspan=2, rowspan=1, pady=(2, self.border_width))
self.image_label.grid(row=0, column=0, sticky="s", columnspan=2, rowspan=1,
padx=max(self.corner_radius * self.scaling, self.border_width * self.scaling), pady=(self.border_width * self.scaling, 2))
self.text_label.grid(row=1, column=0, sticky="n", columnspan=2, rowspan=1,
padx=max(self.corner_radius * self.scaling, self.border_width * self.scaling), pady=(2, self.border_width * self.scaling))
elif self.compound == tkinter.RIGHT or self.compound == "right":
self.image_label.grid(row=0, column=1, padx=(2, max(self.corner_radius, self.border_width)), sticky="w", rowspan=2, columnspan=1, pady=self.border_width)
self.text_label.grid(row=0, column=0, padx=(max(self.corner_radius, self.border_width), 2), sticky="e", rowspan=2, columnspan=1, pady=self.border_width)
self.image_label.grid(row=0, column=1, sticky="w", rowspan=2, columnspan=1,
padx=(2, max(self.corner_radius * self.scaling, self.border_width * self.scaling)), pady=self.border_width * self.scaling)
self.text_label.grid(row=0, column=0, sticky="e", rowspan=2, columnspan=1,
padx=(max(self.corner_radius * self.scaling, self.border_width * self.scaling), 2), pady=self.border_width * self.scaling)
elif self.compound == tkinter.BOTTOM or self.compound == "bottom":
self.image_label.grid(row=1, column=0, padx=max(self.corner_radius, self.border_width), sticky="n", columnspan=2, rowspan=1, pady=(2, self.border_width))
self.text_label.grid(row=0, column=0, padx=max(self.corner_radius, self.border_width), sticky="s", columnspan=2, rowspan=1, pady=(self.border_width, 2))
self.image_label.grid(row=1, column=0, sticky="n", columnspan=2, rowspan=1,
padx=max(self.corner_radius * self.scaling, self.border_width * self.scaling), pady=(2, self.border_width * self.scaling))
self.text_label.grid(row=0, column=0, sticky="s", columnspan=2, rowspan=1,
padx=max(self.corner_radius * self.scaling, self.border_width * self.scaling), pady=(self.border_width * self.scaling, 2))
def configure(self, *args, **kwargs):
require_redraw = False # some attribute changes require a call of self.draw() at the end

View File

@ -1,5 +1,5 @@
import tkinter
from ..customtkinter_settings import CTkSettings
from ..ctk_settings import CTkSettings
class CTkCanvas(tkinter.Canvas):

View File

@ -2,9 +2,9 @@ import tkinter
import sys
from .ctk_canvas import CTkCanvas
from ..customtkinter_theme_manager import CTkThemeManager
from ..customtkinter_settings import CTkSettings
from ..customtkinter_draw_engine import CTkDrawEngine
from ..theme_manager import CTkThemeManager
from ..ctk_settings import CTkSettings
from ..ctk_draw_engine import CTkDrawEngine
from .widget_base_class import CTkBaseClass
@ -68,14 +68,15 @@ class CTkCheckBox(CTkBaseClass):
# configure grid system (1x3)
self.grid_columnconfigure(0, weight=0)
self.grid_columnconfigure(1, weight=0, minsize=6)
self.grid_columnconfigure(1, weight=0, minsize=6 * self.scaling)
self.grid_columnconfigure(2, weight=1)
self.grid_rowconfigure(0, weight=1)
self.canvas = CTkCanvas(master=self,
highlightthickness=0,
width=self.width,
height=self.height)
self.canvas.grid(row=0, column=0, padx=0, pady=0, columnspan=1)
width=self.width * self.scaling,
height=self.height * self.scaling)
self.canvas.grid(row=0, column=0, padx=0, pady=0, columnspan=1, rowspan=1)
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
if self.hover is True:
@ -103,15 +104,20 @@ class CTkCheckBox(CTkBaseClass):
super().destroy()
def draw(self, no_color_updates=False):
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width, self.height, self.corner_radius, self.border_width)
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width * self.scaling,
self.height * self.scaling,
self.corner_radius * self.scaling,
self.border_width * self.scaling)
if self.check_state is True:
self.draw_engine.draw_checkmark(self.width, self.height, self.height * 0.58)
self.draw_engine.draw_checkmark(self.width * self.scaling,
self.height * self.scaling,
self.height * 0.58 * self.scaling)
else:
self.canvas.delete("checkmark")
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
self.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
if self.check_state is True:
self.canvas.itemconfig("inner_parts",
@ -134,11 +140,12 @@ class CTkCheckBox(CTkBaseClass):
fill=CTkThemeManager.single_color(self.border_color, self.appearance_mode))
if self.text_label is None:
print("create label")
self.text_label = tkinter.Label(master=self,
bd=0,
text=self.text,
justify=tkinter.LEFT,
font=self.text_font)
font=self.apply_font_scaling(self.text_font))
self.text_label.grid(row=0, column=2, padx=0, pady=0, sticky="w")
self.text_label["anchor"] = "w"

View File

@ -1,9 +1,9 @@
import tkinter
from .ctk_canvas import CTkCanvas
from ..customtkinter_theme_manager import CTkThemeManager
from ..customtkinter_settings import CTkSettings
from ..customtkinter_draw_engine import CTkDrawEngine
from ..theme_manager import CTkThemeManager
from ..ctk_settings import CTkSettings
from ..ctk_draw_engine import CTkDrawEngine
from .widget_base_class import CTkBaseClass
@ -46,8 +46,8 @@ class CTkEntry(CTkBaseClass):
self.canvas = CTkCanvas(master=self,
highlightthickness=0,
width=self.width,
height=self.height)
width=self.width * self.scaling,
height=self.height * self.scaling)
self.canvas.grid(column=0, row=0, sticky="we")
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
@ -55,11 +55,12 @@ class CTkEntry(CTkBaseClass):
bd=0,
width=1,
highlightthickness=0,
font=self.text_font,
font=self.apply_font_scaling(self.text_font),
**kwargs)
self.entry.grid(column=0, row=0, sticky="we", padx=self.corner_radius if self.corner_radius >= 6 else 6)
self.entry.grid(column=0, row=0, sticky="we",
padx=self.corner_radius * self.scaling if self.corner_radius >= 6 * self.scaling else 6 * self.scaling)
super().bind('<Configure>', self.update_dimensions)
super().bind('<Configure>', self.update_dimensions_event)
self.entry.bind('<FocusOut>', self.set_placeholder)
self.entry.bind('<FocusIn>', self.clear_placeholder)
@ -90,7 +91,10 @@ class CTkEntry(CTkBaseClass):
def draw(self, no_color_updates=False):
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width, self.height, self.corner_radius, self.border_width)
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width * self.scaling,
self.height * self.scaling,
self.corner_radius * self.scaling,
self.border_width * self.scaling)
if CTkThemeManager.single_color(self.fg_color, self.appearance_mode) is not None:
self.canvas.itemconfig("inner_parts",

View File

@ -1,9 +1,9 @@
import tkinter
from .ctk_canvas import CTkCanvas
from ..customtkinter_theme_manager import CTkThemeManager
from ..customtkinter_settings import CTkSettings
from ..customtkinter_draw_engine import CTkDrawEngine
from ..theme_manager import CTkThemeManager
from ..ctk_settings import CTkSettings
from ..ctk_draw_engine import CTkDrawEngine
from .widget_base_class import CTkBaseClass
@ -41,13 +41,13 @@ class CTkFrame(CTkBaseClass):
self.canvas = CTkCanvas(master=self,
highlightthickness=0,
width=self.width,
height=self.height)
width=self.width * self.scaling,
height=self.height * self.scaling)
self.canvas.place(x=0, y=0, relwidth=1, relheight=1)
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
self.bind('<Configure>', self.update_dimensions)
self.bind('<Configure>', self.update_dimensions_event)
self.draw()
@ -64,7 +64,10 @@ class CTkFrame(CTkBaseClass):
def draw(self, no_color_updates=False):
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width, self.height, self.corner_radius, self.border_width)
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width * self.scaling,
self.height * self.scaling,
self.corner_radius * self.scaling,
self.border_width * self.scaling)
if no_color_updates is False or requires_recoloring:
self.canvas.itemconfig("inner_parts",

View File

@ -1,9 +1,9 @@
import tkinter
from .ctk_canvas import CTkCanvas
from ..customtkinter_theme_manager import CTkThemeManager
from ..customtkinter_settings import CTkSettings
from ..customtkinter_draw_engine import CTkDrawEngine
from ..theme_manager import CTkThemeManager
from ..ctk_settings import CTkSettings
from ..ctk_draw_engine import CTkDrawEngine
from .widget_base_class import CTkBaseClass
@ -45,8 +45,8 @@ class CTkLabel(CTkBaseClass):
self.canvas = CTkCanvas(master=self,
highlightthickness=0,
width=self.width,
height=self.height)
width=self.width * self.scaling,
height=self.height * self.scaling)
self.canvas.grid(row=0, column=0, sticky="nswe")
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
@ -54,15 +54,18 @@ class CTkLabel(CTkBaseClass):
highlightthickness=0,
bd=0,
text=self.text,
font=self.text_font,
font=self.apply_font_scaling(self.text_font),
**kwargs)
self.text_label.grid(row=0, column=0, padx=self.corner_radius)
self.bind('<Configure>', self.update_dimensions)
self.bind('<Configure>', self.update_dimensions_event)
self.draw()
def draw(self, no_color_updates=False):
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width, self.height, self.corner_radius, 0)
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width * self.scaling,
self.height * self.scaling,
self.corner_radius * self.scaling,
0)
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))

View File

@ -1,9 +1,9 @@
import tkinter
from .ctk_canvas import CTkCanvas
from ..customtkinter_theme_manager import CTkThemeManager
from ..customtkinter_draw_engine import CTkDrawEngine
from ..customtkinter_settings import CTkSettings
from ..theme_manager import CTkThemeManager
from ..ctk_draw_engine import CTkDrawEngine
from ..ctk_settings import CTkSettings
from .widget_base_class import CTkBaseClass
@ -40,15 +40,18 @@ class CTkProgressBar(CTkBaseClass):
self.border_width = CTkThemeManager.theme["shape"]["progressbar_border_width"] if border_width == "default_theme" else border_width
self.value = 0.5
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(1, weight=1)
self.canvas = CTkCanvas(master=self,
highlightthickness=0,
width=self.width,
height=self.height)
self.canvas.place(x=0, y=0, relwidth=1, relheight=1)
width=self.width * self.scaling,
height=self.height * self.scaling)
self.canvas.grid(row=0, column=0, rowspan=1, columnspan=1)
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
# Each time an item is resized due to pack position mode, the binding Configure is called on the widget
self.bind('<Configure>', self.update_dimensions)
self.bind('<Configure>', self.update_dimensions_event)
self.draw() # initial draw
@ -65,8 +68,13 @@ class CTkProgressBar(CTkBaseClass):
super().destroy()
def draw(self, no_color_updates=False):
print("progress", self.scaling)
requires_recoloring = self.draw_engine.draw_rounded_progress_bar_with_border(self.width, self.height, self.corner_radius, self.border_width, self.value, "w")
requires_recoloring = self.draw_engine.draw_rounded_progress_bar_with_border(self.width * self.scaling,
self.height * self.scaling,
self.corner_radius * self.scaling,
self.border_width * self.scaling,
self.value, "w")
if no_color_updates is False or requires_recoloring:
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))

View File

@ -2,9 +2,9 @@ import tkinter
import sys
from .ctk_canvas import CTkCanvas
from ..customtkinter_theme_manager import CTkThemeManager
from ..customtkinter_settings import CTkSettings
from ..customtkinter_draw_engine import CTkDrawEngine
from ..theme_manager import CTkThemeManager
from ..ctk_settings import CTkSettings
from ..ctk_draw_engine import CTkDrawEngine
from .widget_base_class import CTkBaseClass
@ -65,13 +65,13 @@ class CTkRadioButton(CTkBaseClass):
# configure grid system (3x1)
self.grid_columnconfigure(0, weight=0)
self.grid_columnconfigure(1, weight=0, minsize=6)
self.grid_columnconfigure(1, weight=0, minsize=6 * self.scaling)
self.grid_columnconfigure(2, weight=1)
self.canvas = CTkCanvas(master=self,
highlightthickness=0,
width=self.width,
height=self.height)
width=self.width * self.scaling,
height=self.height * self.scaling)
self.canvas.grid(row=0, column=0, padx=0, pady=0, columnspan=1)
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
@ -97,7 +97,10 @@ class CTkRadioButton(CTkBaseClass):
super().destroy()
def draw(self, no_color_updates=False):
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width, self.height, self.corner_radius, self.border_width)
requires_recoloring = self.draw_engine.draw_rounded_rect_with_border(self.width * self.scaling,
self.height * self.scaling,
self.corner_radius * self.scaling,
self.border_width * self.scaling)
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
self.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
@ -120,7 +123,7 @@ class CTkRadioButton(CTkBaseClass):
bd=0,
text=self.text,
justify=tkinter.LEFT,
font=self.text_font)
font=self.apply_font_scaling(self.text_font))
self.text_label.grid(row=0, column=2, padx=0, pady=0, sticky="w")
self.text_label["anchor"] = "w"

View File

@ -2,9 +2,9 @@ import tkinter
import sys
from .ctk_canvas import CTkCanvas
from ..customtkinter_theme_manager import CTkThemeManager
from ..customtkinter_settings import CTkSettings
from ..customtkinter_draw_engine import CTkDrawEngine
from ..theme_manager import CTkThemeManager
from ..ctk_settings import CTkSettings
from ..ctk_draw_engine import CTkDrawEngine
from .widget_base_class import CTkBaseClass
@ -64,8 +64,8 @@ class CTkSlider(CTkBaseClass):
self.canvas = CTkCanvas(master=self,
highlightthickness=0,
width=self.width,
height=self.height)
width=self.width * self.scaling,
height=self.height * self.scaling)
self.canvas.grid(column=0, row=0, sticky="nswe")
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
@ -75,7 +75,7 @@ class CTkSlider(CTkBaseClass):
self.canvas.bind("<B1-Motion>", self.clicked)
# Each time an item is resized due to pack position mode, the binding Configure is called on the widget
self.bind('<Configure>', self.update_dimensions)
self.bind('<Configure>', self.update_dimensions_event)
self.set_cursor()
self.draw() # initial draw
@ -104,8 +104,13 @@ class CTkSlider(CTkBaseClass):
self.configure(cursor="hand2")
def draw(self, no_color_updates=False):
requires_recoloring = self.draw_engine.draw_rounded_slider_with_border_and_button(self.width, self.height, self.corner_radius, self.border_width,
self.button_length, self.button_corner_radius, self.value, "w")
requires_recoloring = self.draw_engine.draw_rounded_slider_with_border_and_button(self.width * self.scaling,
self.height * self.scaling,
self.corner_radius * self.scaling,
self.border_width * self.scaling,
self.button_length * self.scaling,
self.button_corner_radius * self.scaling,
self.value, "w")
if no_color_updates is False or requires_recoloring:
self.canvas.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
@ -131,7 +136,7 @@ class CTkSlider(CTkBaseClass):
outline=CTkThemeManager.single_color(self.button_color, self.appearance_mode))
def clicked(self, event=None):
self.value = event.x / self.width
self.value = (event.x / self.width) / self.scaling
if self.value > 1:
self.value = 1

View File

@ -2,9 +2,9 @@ import tkinter
import sys
from .ctk_canvas import CTkCanvas
from ..customtkinter_theme_manager import CTkThemeManager
from ..customtkinter_settings import CTkSettings
from ..customtkinter_draw_engine import CTkDrawEngine
from ..theme_manager import CTkThemeManager
from ..ctk_settings import CTkSettings
from ..ctk_draw_engine import CTkDrawEngine
from .widget_base_class import CTkBaseClass
@ -70,13 +70,13 @@ class CTkSwitch(CTkBaseClass):
# configure grid system (3x1)
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=0, minsize=6)
self.grid_columnconfigure(1, weight=0, minsize=6 * self.scaling)
self.grid_columnconfigure(2, weight=0)
self.canvas = CTkCanvas(master=self,
highlightthickness=0,
width=self.width,
height=self.height)
width=self.width * self.scaling,
height=self.height * self.scaling)
self.canvas.grid(row=0, column=0, padx=0, pady=0, columnspan=1, sticky="nswe")
self.draw_engine = CTkDrawEngine(self.canvas, CTkSettings.preferred_drawing_method)
@ -110,11 +110,21 @@ class CTkSwitch(CTkBaseClass):
def draw(self, no_color_updates=False):
if self.check_state is True:
requires_recoloring = self.draw_engine.draw_rounded_slider_with_border_and_button(self.width, self.height, self.corner_radius, self.border_width,
self.button_length, self.corner_radius, 1, "w")
requires_recoloring = self.draw_engine.draw_rounded_slider_with_border_and_button(self.width * self.scaling,
self.height * self.scaling,
self.corner_radius * self.scaling,
self.border_width * self.scaling,
self.button_length * self.scaling,
self.corner_radius * self.scaling
, 1, "w")
else:
requires_recoloring = self.draw_engine.draw_rounded_slider_with_border_and_button(self.width, self.height, self.corner_radius, self.border_width,
self.button_length, self.corner_radius, 0, "w")
requires_recoloring = self.draw_engine.draw_rounded_slider_with_border_and_button(self.width * self.scaling,
self.height * self.scaling,
self.corner_radius * self.scaling,
self.border_width * self.scaling,
self.button_length * self.scaling,
self.corner_radius * self.scaling,
0, "w")
if no_color_updates is False or requires_recoloring:
self.configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
@ -145,7 +155,7 @@ class CTkSwitch(CTkBaseClass):
bd=0,
text=self.text,
justify=tkinter.LEFT,
font=self.text_font)
font=self.apply_font_scaling(self.text_font))
self.text_label.grid(row=0, column=2, padx=0, pady=0, sticky="w")
self.text_label["anchor"] = "w"
if self.textvariable is not None:

View File

@ -1,9 +1,13 @@
import tkinter
import tkinter.ttk as ttk
import copy
import re
from .ctk_tk import CTk
from .ctk_toplevel import CTkToplevel
from ..appearance_mode_tracker import AppearanceModeTracker
from ..scaling_tracker import ScalingTracker
from ..theme_manager import CTkThemeManager
class CTkBaseClass(tkinter.Frame):
@ -12,12 +16,18 @@ class CTkBaseClass(tkinter.Frame):
self.bg_color = self.detect_color_of_master() if bg_color is None else bg_color
self.width = width # width and height in pixel, represent current size of the widget (not the desired size by init)
self.height = height
self.height = height # width and height are independent of the scale
# add set_scaling method to callback list of ScalingTracker for automatic scaling changes
ScalingTracker.add_widget(self.set_scaling, self)
self.scaling = ScalingTracker.get_widget_scaling(self)
# add set_appearance_mode method to callback list of AppearanceModeTracker for appearance mode changes
AppearanceModeTracker.add(self.set_appearance_mode, self)
self.appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark"
super().configure(bg=CTkThemeManager.single_color(self.bg_color, self.appearance_mode))
# overwrite configure methods of master when master is tkinter widget, so that bg changes get applied on child CTk widget too
if isinstance(self.master, (tkinter.Tk, tkinter.Toplevel, tkinter.Frame)) and not isinstance(self.master, (CTkBaseClass, CTk, CTkToplevel)):
master_old_configure = self.master.config
@ -64,11 +74,11 @@ class CTkBaseClass(tkinter.Frame):
if require_redraw:
self.draw()
def update_dimensions(self, event):
def update_dimensions_event(self, event):
# only redraw if dimensions changed (for performance)
if self.width != event.width or self.height != event.height:
self.width = event.width # adjust current size according to new size given by event
self.height = event.height
if self.width != int(event.width * self.scaling) or self.height != int(event.height * self.scaling):
self.width = int(event.width / self.scaling) # adjust current size according to new size given by event
self.height = int(event.height / self.scaling) # width and height are independent of the scale
self.draw(no_color_updates=True) # faster drawing without color changes
@ -104,6 +114,33 @@ class CTkBaseClass(tkinter.Frame):
self.draw()
def set_scaling(self, new_scaling):
self.scaling = new_scaling
super().configure(width=self.width * self.scaling, height=self.height * self.scaling)
def apply_font_scaling(self, font):
if type(font) == tuple or type(font) == list:
font_list = list(font)
for i in range(len(font_list)):
if (type(font_list[i]) == int or type(font_list[i]) == float) and font_list[i] < 0:
font_list[i] = int(font_list[i] * self.scaling)
return tuple(font_list)
elif type(font) == str:
for negative_number in re.findall(r" -\d* ", font):
font = font.replace(negative_number, f" {int(int(negative_number) * self.scaling)} ")
return font
elif isinstance(font, tkinter.font.Font):
new_font_object = copy.copy(font)
if font.cget("size") < 0:
new_font_object.config(size=int(font.cget("size") * self.scaling))
return new_font_object
else:
return font
def draw(self, no_color_updates=False):
""" abstract of draw method to be overridden """
pass

View File

@ -4,6 +4,8 @@ import customtkinter # <- import the CustomTkinter module
customtkinter.set_appearance_mode("dark") # Modes: "System" (standard), "Dark", "Light"
customtkinter.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue"
customtkinter.ScalingTracker.set_user_scaling(0.9)
root_tk = customtkinter.CTk() # create CTk window like you do with the Tk window (you can also use normal tkinter.Tk window)
root_tk.geometry("400x480")
root_tk.title("CustomTkinter Test")