changed transparent color value from None to "transparent", fixed type hints, added color type and value checking

This commit is contained in:
Tom Schimansky 2022-11-10 23:27:55 +01:00
parent 1387e834b5
commit cbbc9efda3
27 changed files with 566 additions and 574 deletions

View File

@ -10,6 +10,7 @@ ToDo:
- add new button attributes to wiki
- cursor configuring
- overwrite winfo methods
- renew input dialog
## Unreleased - 2022-10-2
### Added

View File

@ -1,5 +1,6 @@
![PyPI](https://img.shields.io/pypi/v/customtkinter)
![PyPI - Downloads](https://img.shields.io/pypi/dm/customtkinter?color=green&label=pip%20downloads)
![PyPI - Downloads](https://img.shields.io/pypi/dm/customtkinter?color=green&label=downloads)
![Downloads](https://static.pepy.tech/personalized-badge/customtkinter?period=total&units=international_system&left_color=grey&right_color=green&left_text=downloads)
![PyPI - License](https://img.shields.io/pypi/l/customtkinter)
![Total lines](https://img.shields.io/tokei/lines/github.com/tomschimansky/customtkinter?color=green&label=total%20lines)

View File

@ -12,7 +12,7 @@
"frame_border": ["#979DA2", "#565B5E"],
"frame_low": ["#D1D5D8", "#2A2D2E"],
"frame_high": ["#C0C2C5", "#343638"],
"label": [null, null],
"label": "transparent",
"text": ["gray10", "#DCE4EE"],
"text_disabled": ["gray60", "gray45"],
"text_button": ["#DCE4EE", "#DCE4EE"],
@ -78,7 +78,6 @@
"slider_button_corner_radius": 1000,
"switch_border_width": 3,
"switch_corner_radius": 1000,
"switch_button_corner_radius": 1000,
"switch_button_length": 0,
"scrollbar_corner_radius": 1000,
"scrollbar_border_spacing": 4

View File

@ -15,20 +15,20 @@ class CTkInputDialog(CTkToplevel):
def __init__(self,
master: any = None,
fg_color: Union[str, Tuple[str, str]] = "default_theme",
button_fg_color: Union[str, Tuple[str, str]] = "default_theme",
button_hover_color: Union[str, Tuple[str, str]] = "default_theme",
text_color: Union[str, Tuple[str, str]] = "default_theme",
fg_color: Union[str, Tuple[str, str]] = "default",
button_fg_color: Union[str, Tuple[str, str]] = "default",
button_hover_color: Union[str, Tuple[str, str]] = "default",
text_color: Union[str, Tuple[str, str]] = "default",
title: str = "CTkDialog",
text: str = "CTkDialog"):
super().__init__(master=master, fg_color=fg_color)
self._fg_color = ThemeManager.theme["color"]["window"] if fg_color == "default_theme" else fg_color
self._button_fg_color = ThemeManager.theme["color"]["button"] if button_fg_color == "default_theme" else button_fg_color
self._button_hover_color = ThemeManager.theme["color"]["button_hover"] if button_hover_color == "default_theme" else button_hover_color
self._text_color = ThemeManager.theme["color"]["text"] if button_hover_color == "default_theme" else button_hover_color
self._fg_color = ThemeManager.theme["color"]["window"] if fg_color == "default" else fg_color
self._button_fg_color = ThemeManager.theme["color"]["button"] if button_fg_color == "default" else button_fg_color
self._button_hover_color = ThemeManager.theme["color"]["button_hover"] if button_hover_color == "default" else button_hover_color
self._text_color = ThemeManager.theme["color"]["text"] if button_hover_color == "default" else button_hover_color
self._user_input: Union[str, None] = None
self._running: bool = False
self._height: int = len(text.split("\n")) * 20 + 150

View File

@ -4,7 +4,7 @@ import sys
import os
import platform
import ctypes
from typing import Union, Tuple
from typing import Union, Tuple, Optional
from .widgets.theme.theme_manager import ThemeManager
from .widgets.scaling.scaling_base_class import CTkScalingBaseClass
@ -19,17 +19,17 @@ class CTk(tkinter.Tk, CTkAppearanceModeBaseClass, CTkScalingBaseClass):
For detailed information check out the documentation.
"""
_valid_tk_constructor_arguments = {"screenName", "baseName", "className", "useTk", "sync", "use"}
_valid_tk_constructor_arguments: set = {"screenName", "baseName", "className", "useTk", "sync", "use"}
_valid_tk_configure_arguments = {'bd', 'borderwidth', 'class', 'menu', 'relief', 'screen',
_valid_tk_configure_arguments: set = {'bd', 'borderwidth', 'class', 'menu', 'relief', 'screen',
'use', 'container', 'cursor', 'height',
'highlightthickness', 'padx', 'pady', 'takefocus', 'visual', 'width'}
_deactivate_macos_window_header_manipulation = False
_deactivate_windows_window_header_manipulation = False
_deactivate_macos_window_header_manipulation: bool = False
_deactivate_windows_window_header_manipulation: bool = False
def __init__(self,
fg_color: Union[str, Tuple[str, str]] = "default_theme",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
**kwargs):
self._enable_macos_dark_title_bar()
@ -48,7 +48,7 @@ class CTk(tkinter.Tk, CTkAppearanceModeBaseClass, CTkScalingBaseClass):
self._max_height: int = 1_000_000
self._last_resizable_args: Union[Tuple[list, dict], None] = None # (args, kwargs)
self._fg_color = ThemeManager.theme["color"]["window"] if fg_color == "default_theme" else fg_color
self._fg_color = ThemeManager.theme["color"]["window"] if fg_color is None else self._check_color_type(fg_color)
# set bg of tkinter.Tk
super().configure(bg=self._apply_appearance_mode(self._fg_color))
@ -195,7 +195,7 @@ class CTk(tkinter.Tk, CTkAppearanceModeBaseClass, CTkScalingBaseClass):
def configure(self, **kwargs):
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"))
super().configure(bg=self._apply_appearance_mode(self._fg_color))
for child in self.winfo_children():

View File

@ -4,7 +4,7 @@ import sys
import os
import platform
import ctypes
from typing import Union, Tuple
from typing import Union, Tuple, Optional
from .widgets.theme.theme_manager import ThemeManager
from .widgets.scaling.scaling_base_class import CTkScalingBaseClass
@ -19,15 +19,15 @@ class CTkToplevel(tkinter.Toplevel, CTkAppearanceModeBaseClass, CTkScalingBaseCl
For detailed information check out the documentation.
"""
_valid_tk_toplevel_arguments = {"bd", "borderwidth", "class", "container", "cursor", "height",
_valid_tk_toplevel_arguments: set = {"bd", "borderwidth", "class", "container", "cursor", "height",
"highlightbackground", "highlightthickness", "menu", "relief",
"screen", "takefocus", "use", "visual", "width"}
_deactivate_macos_window_header_manipulation = False
_deactivate_windows_window_header_manipulation = False
_deactivate_macos_window_header_manipulation: bool = False
_deactivate_windows_window_header_manipulation: bool = False
def __init__(self, *args,
fg_color: Union[str, Tuple[str, str]] = "default_theme",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
**kwargs):
self._enable_macos_dark_title_bar()
@ -46,7 +46,7 @@ class CTkToplevel(tkinter.Toplevel, CTkAppearanceModeBaseClass, CTkScalingBaseCl
self._max_height: int = 1_000_000
self._last_resizable_args: Union[Tuple[list, dict], None] = None # (args, kwargs)
self._fg_color = ThemeManager.theme["color"]["window"] if fg_color == "default_theme" else fg_color
self._fg_color = ThemeManager.theme["color"]["window"] if fg_color is None else self._check_color_type(fg_color)
# set bg color of tkinter.Toplevel
super().configure(bg=self._apply_appearance_mode(self._fg_color))
@ -153,7 +153,7 @@ class CTkToplevel(tkinter.Toplevel, CTkAppearanceModeBaseClass, CTkScalingBaseCl
def configure(self, **kwargs):
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"))
super().configure(bg=self._apply_appearance_mode(self._fg_color))
for child in self.winfo_children():

View File

@ -44,3 +44,18 @@ class CTkAppearanceModeBaseClass:
return color[self.__appearance_mode]
else:
return color
@staticmethod
def _check_color_type(color: any, transparency: bool = False):
if color is None:
raise ValueError(f"color is None, for transparency set color='transparent'")
elif isinstance(color, (tuple, list)) and (color[0] == "transparent" or color[1] == "transparent"):
raise ValueError(f"transparency is not allowed in tuple color {color}, use 'transparent'")
elif color == "transparent" and transparency is False:
raise ValueError(f"transparency is not allowed for this attribute")
elif isinstance(color, str):
return color
elif isinstance(color, (tuple, list)) and len(color) == 2 and isinstance(color[0], str) and isinstance(color[1], str):
return color
else:
raise ValueError(f"color {color} must be string ('transparent' or 'color-name' or 'hex-color') or tuple of two strings, not {type(color)}")

View File

@ -1,44 +1,38 @@
import tkinter
import sys
from typing import Union, Tuple, Callable, List
from typing import Union, Tuple, Callable, List, Optional
from ..theme.theme_manager import ThemeManager
from ..scaling.scaling_tracker import ScalingTracker
from ..font.ctk_font import CTkFont
from ..appearance_mode.appearance_mode_tracker import AppearanceModeTracker
from ..appearance_mode.appearance_mode_base_class import CTkAppearanceModeBaseClass
from ..scaling.scaling_base_class import CTkScalingBaseClass
class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass):
class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass, CTkScalingBaseClass):
def __init__(self, *args,
min_character_width: int = 18,
fg_color: Union[str, Tuple[str, str]] = "default_theme",
hover_color: Union[str, Tuple[str, str]] = "default_theme",
text_color: Union[str, Tuple[str, str]] = "default_theme",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
hover_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
font: Union[tuple, CTkFont] = "default_theme",
command: Callable = None,
values: List[str] = None,
font: Optional[Union[tuple, CTkFont]] = None,
command: Union[Callable, None] = None,
values: Optional[List[str]] = None,
**kwargs):
# call init methods of super classes
tkinter.Menu.__init__(self, *args, **kwargs)
CTkAppearanceModeBaseClass.__init__(self)
ScalingTracker.add_widget(self._set_scaling, self)
self._widget_scaling = ScalingTracker.get_widget_scaling(self)
AppearanceModeTracker.add(self._set_appearance_mode, self)
self._appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark"
CTkScalingBaseClass.__init__(self, scaling_type="widget")
self._min_character_width = min_character_width
self._fg_color = ThemeManager.theme["color"]["dropdown_color"] if fg_color == "default_theme" else fg_color
self._hover_color = ThemeManager.theme["color"]["dropdown_hover"] if hover_color == "default_theme" else hover_color
self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
self._fg_color = ThemeManager.theme["color"]["dropdown_color"] if fg_color is None else self._check_color_type(fg_color)
self._hover_color = ThemeManager.theme["color"]["dropdown_hover"] if hover_color is None else self._check_color_type(hover_color)
self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color)
# font
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
self._font = CTkFont() if font is None else self._check_font_type(font)
if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font)
@ -125,16 +119,16 @@ class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass):
def configure(self, **kwargs):
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
super().configure(bg=ThemeManager._apply_appearance_mode(self._fg_color, self._appearance_mode))
self._fg_color = self._check_color_type(kwargs.pop("fg_color"))
super().configure(bg=self._apply_appearance_mode(self._fg_color))
if "hover_color" in kwargs:
self._hover_color = kwargs.pop("hover_color")
super().configure(activebackground=ThemeManager._apply_appearance_mode(self._hover_color, self._appearance_mode))
self._hover_color = self._check_color_type(kwargs.pop("hover_color"))
super().configure(activebackground=self._apply_appearance_mode(self._hover_color))
if "text_color" in kwargs:
self._text_color = kwargs.pop("text_color")
super().configure(fg=ThemeManager._apply_appearance_mode(self._text_color, self._appearance_mode))
self._text_color = self._check_color_type(kwargs.pop("text_color"))
super().configure(fg=self._apply_appearance_mode(self._text_color))
if "font" in kwargs:
if isinstance(self._font, CTkFont):
@ -175,29 +169,6 @@ class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass):
else:
return super().cget(attribute_name)
def _apply_widget_scaling(self, value: Union[int, float, str]) -> Union[float, str]:
if isinstance(value, (int, float)):
return value * self._widget_scaling
else:
return value
def _apply_font_scaling(self, font: Union[Tuple, CTkFont]) -> tuple:
""" Takes CTkFont object and returns tuple font with scaled size, has to be called again for every change of font object """
if type(font) == tuple:
if len(font) == 1:
return font
elif len(font) == 2:
return font[0], -abs(round(font[1] * self._widget_scaling))
elif len(font) == 3:
return font[0], -abs(round(font[1] * self._widget_scaling)), font[2]
else:
raise ValueError(f"Can not scale font {font}. font needs to be tuple of len 1, 2 or 3")
elif isinstance(font, CTkFont):
return font.create_scaled_tuple(self._widget_scaling)
else:
raise ValueError(f"Can not scale font '{font}' of type {type(font)}. font needs to be tuple or instance of CTkFont")
@staticmethod
def _check_font_type(font: any):
if isinstance(font, CTkFont):
@ -211,23 +182,17 @@ class DropdownMenu(tkinter.Menu, CTkAppearanceModeBaseClass):
return font
else:
raise ValueError(f"Wrong font type {type(font)}\n" +
raise ValueError(f"Wrong font type {type(font)} for font '{font}'\n" +
f"For consistency, Customtkinter requires the font argument to be a tuple of len 2 or 3 or an instance of CTkFont.\n" +
f"\nUsage example:\n" +
f"font=customtkinter.CTkFont(family='<name>', size=<size in px>)\n" +
f"font=('<name>', <size in px>)\n")
def _set_scaling(self, new_widget_scaling, new_window_scaling):
self._widget_scaling = new_widget_scaling
super()._set_scaling(new_widget_scaling, new_window_scaling)
self._configure_menu_for_platforms()
def _set_appearance_mode(self, mode_string):
""" colors won't update on appearance mode change when dropdown is open, because it's not necessary """
if mode_string.lower() == "dark":
self._appearance_mode = 1
elif mode_string.lower() == "light":
self._appearance_mode = 0
super()._set_appearance_mode(mode_string)
self._configure_menu_for_platforms()

View File

@ -1,7 +1,7 @@
import sys
import tkinter
import tkinter.ttk as ttk
from typing import Union, Callable, Tuple
from typing import Union, Callable, Tuple, Optional
try:
from typing import TypedDict
@ -20,7 +20,7 @@ from ....utility.utility_functions import pop_from_dict_by_set, check_kwargs_emp
class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClass):
""" Base class of every CTk widget, handles the dimensions, _bg_color,
""" Base class of every CTk widget, handles the dimensions, bg_color,
appearance_mode changes, scaling, bg changes of master if master is not a CTk widget """
# attributes that are passed to and managed by the tkinter frame only:
@ -29,11 +29,11 @@ class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClas
_cursor_manipulation_enabled: bool = True
def __init__(self,
master: any = None,
master: any,
width: int = 0,
height: int = 0,
bg_color: Union[str, Tuple[str, str], None] = None,
bg_color: Union[str, Tuple[str, str]] = "transparent",
**kwargs):
# call init methods of super classes
@ -61,7 +61,7 @@ class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClas
self._last_geometry_manager_call: Union[GeometryCallDict, None] = None
# background color
self._bg_color: Union[str, Tuple[str, str]] = self._detect_color_of_master() if bg_color is None else bg_color
self._bg_color: Union[str, Tuple[str, str]] = self._detect_color_of_master() if bg_color == "transparent" else self._check_color_type(bg_color, transparency=True)
# set bg color of tkinter.Frame
super().configure(bg=self._apply_appearance_mode(self._bg_color))
@ -116,11 +116,11 @@ class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClas
self._set_dimensions(height=kwargs.pop("height"))
if "bg_color" in kwargs:
new_bg_color = kwargs.pop("bg_color")
if new_bg_color is None:
new_bg_color = self._check_color_type(kwargs.pop("bg_color"), transparency=True)
if new_bg_color == "transparent":
self._bg_color = self._detect_color_of_master()
else:
self._bg_color = new_bg_color
self._bg_color = self._check_color_type(new_bg_color)
require_redraw = True
super().configure(**pop_from_dict_by_set(kwargs, self._valid_tk_frame_attributes)) # configure tkinter.Frame
@ -185,13 +185,13 @@ class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClas
self._draw(no_color_updates=True) # faster drawing without color changes
def _detect_color_of_master(self, master_widget=None) -> Union[str, Tuple[str, str]]:
""" detect color of self.master widget to set correct _bg_color """
""" detect foreground color of master widget for bg_color and transparent color """
if master_widget is None:
master_widget = self.master
if isinstance(master_widget, (CTkBaseClass, CTk, CTkToplevel)) and hasattr(master_widget, "_fg_color"):
if master_widget.cget("fg_color") is not None:
if isinstance(master_widget, (CTkBaseClass, CTk, CTkToplevel)):
if master_widget.cget("fg_color") is not None and master_widget.cget("fg_color") != "transparent":
return master_widget.cget("fg_color")
# if fg_color of master is None, try to retrieve fg_color from master of master

View File

@ -1,6 +1,6 @@
import tkinter
import sys
from typing import Union, Tuple, Callable
from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager
@ -16,80 +16,82 @@ class CTkButton(CTkBaseClass):
For detailed information check out the documentation.
"""
_image_label_spacing = 6
_image_label_spacing: int = 6
def __init__(self,
master: any = None,
master: any,
width: int = 140,
height: int = 28,
corner_radius: Union[int, str] = "default_theme",
border_width: Union[int, str] = "default_theme",
corner_radius: Optional[int] = None,
border_width: Optional[int] = None,
border_spacing: int = 2,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str], None] = "default_theme",
hover_color: Union[str, Tuple[str, str]] = "default_theme",
border_color: Union[str, Tuple[str, str]] = "default_theme",
text_color: Union[str, Tuple[str, str]] = "default_theme",
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
hover_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
background_corner_colors: Tuple[Union[str, Tuple[str, str]]] = None,
background_corner_colors: Union[Tuple[Union[str, Tuple[str, str]]], None] = None,
round_width_to_even_numbers: bool = True,
round_height_to_even_numbers: bool = True,
text: str = "CTkButton",
font: Union[tuple, CTkFont] = "default_theme",
textvariable: tkinter.Variable = None,
image: Union[tkinter.PhotoImage, CTkImage] = None,
font: Optional[Union[tuple, CTkFont]] = None,
textvariable: Union[tkinter.Variable, None] = None,
image: Union[tkinter.PhotoImage, CTkImage, None] = None,
state: str = "normal",
hover: bool = True,
command: Callable = None,
command: Union[Callable[[], None], None] = None,
compound: str = "left",
anchor: str = "center",
**kwargs):
# transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass
# transfer basic functionality (bg_color, size, appearance_mode, scaling) to CTkBaseClass
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color
self._fg_color = ThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_color
self._hover_color = ThemeManager.theme["color"]["button_hover"] if hover_color == "default_theme" else hover_color
self._border_color = ThemeManager.theme["color"]["button_border"] if border_color == "default_theme" else border_color
self._text_color = ThemeManager.theme["color"]["text_button"] if text_color == "default_theme" else text_color
self._text_color_disabled = ThemeManager.theme["color"]["text_button_disabled"] if text_color_disabled == "default_theme" else text_color_disabled
self._background_corner_colors = background_corner_colors # rendering options for DrawEngine
# shape
self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._border_width = ThemeManager.theme["shape"]["button_border_width"] if border_width == "default_theme" else border_width
self._round_width_to_even_numbers = round_width_to_even_numbers # rendering options for DrawEngine
self._round_height_to_even_numbers = round_height_to_even_numbers # rendering options for DrawEngine
self._corner_radius = min(self._corner_radius, round(self._current_height/2))
self._compound = compound
self._anchor = anchor
self._border_spacing = border_spacing
self._corner_radius: int = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius is None else corner_radius
self._corner_radius = min(self._corner_radius, round(self._current_height / 2))
self._border_width: int = ThemeManager.theme["shape"]["button_border_width"] if border_width is None else border_width
self._border_spacing: int = border_spacing
# text, image
self._image = self._check_image_type(image)
self._image_label: Union[tkinter.Label, None] = None
# color
self._fg_color: Union[str, Tuple[str, str]] = ThemeManager.theme["color"]["button"] if fg_color is None else self._check_color_type(fg_color, transparency=True)
self._hover_color: Union[str, Tuple[str, str]] = ThemeManager.theme["color"]["button_hover"] if hover_color is None else self._check_color_type(hover_color)
self._border_color: Union[str, Tuple[str, str]] = ThemeManager.theme["color"]["button_border"] if border_color is None else self._check_color_type(border_color)
self._text_color: Union[str, Tuple[str, str]] = ThemeManager.theme["color"]["text_button"] if text_color is None else self._check_color_type(text_color)
self._text_color_disabled: Union[str, Tuple[str, str]] = ThemeManager.theme["color"]["text_button_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled)
# rendering options
self._background_corner_colors: Union[Tuple[Union[str, Tuple[str, str]]], None] = background_corner_colors # rendering options for DrawEngine
self._round_width_to_even_numbers: bool = round_width_to_even_numbers # rendering options for DrawEngine
self._round_height_to_even_numbers: bool = round_height_to_even_numbers # rendering options for DrawEngine
# text, font
self._text = text
self._text_label: Union[tkinter.Label, None] = None
if isinstance(self._image, CTkImage):
self._image.add_configure_callback(self._update_image)
# font
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
self._textvariable: tkinter.Variable = textvariable
self._font: Union[tuple, CTkFont] = CTkFont() if font is None else self._check_font_type(font)
if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font)
# callback and hover functionality
self._command = command
self._textvariable = textvariable
self._state = state
self._hover = hover
# image
self._image = self._check_image_type(image)
self._image_label: Union[tkinter.Label, None] = None
if isinstance(self._image, CTkImage):
self._image.add_configure_callback(self._update_image)
# other
self._state: str = state
self._hover: bool = hover
self._command: Callable = command
self._compound: str = compound
self._anchor: str = anchor
self._click_animation_running: bool = False
# canvas
# canvas and draw engine
self._canvas = CTkCanvas(master=self,
highlightthickness=0,
width=self._apply_widget_scaling(self._desired_width),
@ -116,6 +118,9 @@ class CTkButton(CTkBaseClass):
if self._text_label is not None:
self._text_label.configure(font=self._apply_font_scaling(self._font))
if self._image_label is not None:
self._update_image()
self._canvas.configure(width=self._apply_widget_scaling(self._desired_width),
height=self._apply_widget_scaling(self._desired_height))
self._draw(no_color_updates=True)
@ -175,7 +180,7 @@ class CTkButton(CTkBaseClass):
fill=self._apply_appearance_mode(self._border_color))
# set color for inner button parts
if self._fg_color is None:
if self._fg_color == "transparent":
self._canvas.itemconfig("inner_parts",
outline=self._apply_appearance_mode(self._bg_color),
fill=self._apply_appearance_mode(self._bg_color))
@ -211,7 +216,7 @@ class CTkButton(CTkBaseClass):
else:
self._text_label.configure(fg=self._apply_appearance_mode(self._text_color))
if self._fg_color is None:
if self._apply_appearance_mode(self._fg_color) == "transparent":
self._text_label.configure(bg=self._apply_appearance_mode(self._bg_color))
else:
self._text_label.configure(bg=self._apply_appearance_mode(self._fg_color))
@ -228,6 +233,7 @@ class CTkButton(CTkBaseClass):
if self._image_label is None:
self._image_label = tkinter.Label(master=self)
self._update_image() # set image
self._create_grid()
self._image_label.bind("<Enter>", self._on_enter)
@ -237,13 +243,11 @@ class CTkButton(CTkBaseClass):
if no_color_updates is False:
# set image_label bg color (background color of label)
if self._fg_color is None:
if self._apply_appearance_mode(self._fg_color) == "transparent":
self._image_label.configure(bg=self._apply_appearance_mode(self._bg_color))
else:
self._image_label.configure(bg=self._apply_appearance_mode(self._fg_color))
self._update_image() # set image
else:
# delete text_label if no text given
if self._image_label is not None:
@ -334,23 +338,23 @@ class CTkButton(CTkBaseClass):
require_redraw = True
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True)
require_redraw = True
if "hover_color" in kwargs:
self._hover_color = kwargs.pop("hover_color")
self._hover_color = self._check_color_type(kwargs.pop("hover_color"))
require_redraw = True
if "border_color" in kwargs:
self._border_color = kwargs.pop("border_color")
self._border_color = self._check_color_type(kwargs.pop("border_color"))
require_redraw = True
if "text_color" in kwargs:
self._text_color = kwargs.pop("text_color")
self._text_color = self._check_color_type(kwargs.pop("text_color"))
require_redraw = True
if "text_color_disabled" in kwargs:
self._text_color_disabled = kwargs.pop("text_color_disabled")
self._text_color_disabled = self._check_color_type(kwargs.pop("text_color_disabled"))
require_redraw = True
if "background_corner_colors" in kwargs:
@ -486,7 +490,7 @@ class CTkButton(CTkBaseClass):
def _on_leave(self, event=None):
self._click_animation_running = False
if self._fg_color is None:
if self._fg_color == "transparent":
inner_parts_color = self._bg_color
else:
inner_parts_color = self._fg_color

View File

@ -1,6 +1,6 @@
import tkinter
import sys
from typing import Union, Tuple, Callable
from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager
@ -16,31 +16,31 @@ class CTkCheckBox(CTkBaseClass):
"""
def __init__(self,
master: any = None,
master: any,
width: int = 100,
height: int = 24,
checkbox_width: int = 24,
checkbox_height: int = 24,
corner_radius: Union[int, str] = "default_theme",
border_width: Union[int, str] = "default_theme",
corner_radius: Optional[int] = None,
border_width: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str]] = "default_theme",
hover_color: Union[str, Tuple[str, str]] = "default_theme",
border_color: Union[str, Tuple[str, str]] = "default_theme",
checkmark_color: Union[str, Tuple[str, str]] = "default_theme",
text_color: Union[str, Tuple[str, str]] = "default_theme",
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
hover_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Optional[Union[str, Tuple[str, str]]] = None,
checkmark_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
text: str = "CTkCheckBox",
font: Union[tuple, CTkFont] = "default_theme",
textvariable: tkinter.Variable = None,
font: Optional[Union[tuple, CTkFont]] = None,
textvariable: Union[tkinter.Variable, None] = None,
state: str = tkinter.NORMAL,
hover: bool = True,
command: Callable = None,
command: Union[Callable[[], None], None] = None,
onvalue: Union[int, str] = 1,
offvalue: Union[int, str] = 0,
variable: tkinter.Variable = None,
variable: Union[tkinter.Variable, None] = None,
**kwargs):
# transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass
@ -51,23 +51,23 @@ class CTkCheckBox(CTkBaseClass):
self._checkbox_height = checkbox_height
# color
self._fg_color = ThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_color
self._hover_color = ThemeManager.theme["color"]["button_hover"] if hover_color == "default_theme" else hover_color
self._border_color = ThemeManager.theme["color"]["checkbox_border"] if border_color == "default_theme" else border_color
self._checkmark_color = ThemeManager.theme["color"]["checkmark"] if checkmark_color == "default_theme" else checkmark_color
self._fg_color = ThemeManager.theme["color"]["button"] if fg_color is None else self._check_color_type(fg_color)
self._hover_color = ThemeManager.theme["color"]["button_hover"] if hover_color is None else self._check_color_type(hover_color)
self._border_color = ThemeManager.theme["color"]["checkbox_border"] if border_color is None else self._check_color_type(border_color)
self._checkmark_color = ThemeManager.theme["color"]["checkmark"] if checkmark_color is None else self._check_color_type(checkmark_color)
# shape
self._corner_radius = ThemeManager.theme["shape"]["checkbox_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._border_width = ThemeManager.theme["shape"]["checkbox_border_width"] if border_width == "default_theme" else border_width
self._corner_radius = ThemeManager.theme["shape"]["checkbox_corner_radius"] if corner_radius is None else corner_radius
self._border_width = ThemeManager.theme["shape"]["checkbox_border_width"] if border_width is None else border_width
# text
self._text = text
self._text_label: Union[tkinter.Label, None] = None
self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled == "default_theme" else text_color_disabled
self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color)
self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled)
# font
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
self._font = CTkFont() if font is None else self._check_font_type(font)
if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font)
@ -253,19 +253,19 @@ class CTkCheckBox(CTkBaseClass):
require_redraw = True
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"))
require_redraw = True
if "hover_color" in kwargs:
self._hover_color = kwargs.pop("hover_color")
self._hover_color = self._check_color_type(kwargs.pop("hover_color"))
require_redraw = True
if "text_color" in kwargs:
self._text_color = kwargs.pop("text_color")
self._text_color = self._check_color_type(kwargs.pop("text_color"))
require_redraw = True
if "border_color" in kwargs:
self._border_color = kwargs.pop("border_color")
self._border_color = self._check_color_type(kwargs.pop("border_color"))
require_redraw = True
if "hover" in kwargs:

View File

@ -1,6 +1,6 @@
import tkinter
import sys
from typing import Union, Tuple, Callable, List
from typing import Union, Tuple, Callable, List, Optional
from .core_widget_classes.dropdown_menu import DropdownMenu
from .core_rendering.ctk_canvas import CTkCanvas
@ -17,52 +17,50 @@ class CTkComboBox(CTkBaseClass):
"""
def __init__(self,
master: any = None,
master: any,
width: int = 140,
height: int = 28,
corner_radius: Union[int, str] = "default_theme",
border_width: Union[int, str] = "default_theme",
corner_radius: Optional[int] = None,
border_width: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str]] = "default_theme",
border_color: Union[str, Tuple[str, str]] = "default_theme",
button_color: Union[str, Tuple[str, str]] = "default_theme",
button_hover_color: Union[str, Tuple[str, str]] = "default_theme",
dropdown_fg_color: Union[str, Tuple[str, str]] = "default_theme",
dropdown_hover_color: Union[str, Tuple[str, str]] = "default_theme",
dropdown_text_color: Union[str, Tuple[str, str]] = "default_theme",
text_color: Union[str, Tuple[str, str]] = "default_theme",
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Optional[Union[str, Tuple[str, str]]] = None,
button_color: Optional[Union[str, Tuple[str, str]]] = None,
button_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
dropdown_fg_color: Optional[Union[str, Tuple[str, str]]] = None,
dropdown_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
dropdown_text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
font: Union[tuple, CTkFont] = "default_theme",
dropdown_font: Union[tuple, CTkFont] = "default_theme",
values: List[str] = None,
font: Optional[Union[tuple, CTkFont]] = None,
dropdown_font: Optional[Union[tuple, CTkFont]] = None,
values: Optional[List[str]] = None,
state: str = tkinter.NORMAL,
hover: bool = True,
variable: tkinter.Variable = None,
command: Callable = None,
variable: Union[tkinter.Variable, None] = None,
command: Union[Callable[[str], None], None] = None,
justify: str = "left",
**kwargs):
# transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color variables
self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color == "default_theme" else fg_color
self._border_color = ThemeManager.theme["color"]["combobox_border"] if border_color == "default_theme" else border_color
self._button_color = ThemeManager.theme["color"]["combobox_border"] if button_color == "default_theme" else button_color
self._button_hover_color = ThemeManager.theme["color"]["combobox_button_hover"] if button_hover_color == "default_theme" else button_hover_color
# shape
self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width == "default_theme" else border_width
self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius is None else corner_radius
self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width is None else border_width
# text and font
self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled == "default_theme" else text_color_disabled
# color
self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color is None else self._check_color_type(fg_color)
self._border_color = ThemeManager.theme["color"]["combobox_border"] if border_color is None else self._check_color_type(border_color)
self._button_color = ThemeManager.theme["color"]["combobox_border"] if button_color is None else self._check_color_type(button_color)
self._button_hover_color = ThemeManager.theme["color"]["combobox_button_hover"] if button_hover_color is None else self._check_color_type(button_hover_color)
self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color)
self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled)
# font
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
self._font = CTkFont() if font is None else self._check_font_type(font)
if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font)
@ -226,19 +224,19 @@ class CTkComboBox(CTkBaseClass):
require_redraw = True
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"))
require_redraw = True
if "border_color" in kwargs:
self._border_color = kwargs.pop("border_color")
self._border_color = self._check_color_type(kwargs.pop("border_color"))
require_redraw = True
if "button_color" in kwargs:
self._button_color = kwargs.pop("button_color")
self._button_color = self._check_color_type(kwargs.pop("button_color"))
require_redraw = True
if "button_hover_color" in kwargs:
self._button_hover_color = kwargs.pop("button_hover_color")
self._button_hover_color = self._check_color_type(kwargs.pop("button_hover_color"))
require_redraw = True
if "dropdown_fg_color" in kwargs:
@ -251,11 +249,11 @@ class CTkComboBox(CTkBaseClass):
self._dropdown_menu.configure(text_color=kwargs.pop("dropdown_text_color"))
if "text_color" in kwargs:
self._text_color = kwargs.pop("text_color")
self._text_color = self._check_color_type(kwargs.pop("text_color"))
require_redraw = True
if "text_color_disabled" in kwargs:
self._text_color_disabled = kwargs.pop("text_color_disabled")
self._text_color_disabled = self._check_color_type(kwargs.pop("text_color_disabled"))
require_redraw = True
if "font" in kwargs:

View File

@ -1,5 +1,5 @@
import tkinter
from typing import Union, Tuple
from typing import Union, Tuple, Optional
from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager
@ -24,21 +24,21 @@ class CTkEntry(CTkBaseClass):
"show", "takefocus", "validate", "validatecommand", "xscrollcommand"}
def __init__(self,
master: any = None,
master: any,
width: int = 140,
height: int = 28,
corner_radius: int = "default_theme",
border_width: int = "default_theme",
corner_radius: Optional[int] = None,
border_width: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str], None] = "default_theme",
border_color: Union[str, Tuple[str, str]] = "default_theme",
text_color: Union[str, Tuple[str, str]] = "default_theme",
placeholder_text_color: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
placeholder_text_color: Optional[Union[str, Tuple[str, str]]] = None,
textvariable: tkinter.Variable = None,
placeholder_text: str = None,
font: Union[tuple, CTkFont] = "default_theme",
textvariable: Union[tkinter.Variable, None] = None,
placeholder_text: Union[str, None] = None,
font: Optional[Union[tuple, CTkFont]] = None,
state: str = tkinter.NORMAL,
**kwargs):
@ -50,14 +50,14 @@ class CTkEntry(CTkBaseClass):
self.grid_columnconfigure(0, weight=1)
# color
self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color == "default_theme" else fg_color
self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
self._placeholder_text_color = ThemeManager.theme["color"]["entry_placeholder_text"] if placeholder_text_color == "default_theme" else placeholder_text_color
self._border_color = ThemeManager.theme["color"]["entry_border"] if border_color == "default_theme" else border_color
self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color is None else self._check_color_type(fg_color, transparency=True)
self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color)
self._placeholder_text_color = ThemeManager.theme["color"]["entry_placeholder_text"] if placeholder_text_color is None else self._check_color_type(placeholder_text_color)
self._border_color = ThemeManager.theme["color"]["entry_border"] if border_color is None else self._check_color_type(border_color)
# shape
self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width == "default_theme" else border_width
self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius is None else corner_radius
self._border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width is None else border_width
# text and state
self._is_focused: bool = True
@ -69,7 +69,7 @@ class CTkEntry(CTkBaseClass):
self._textvariable_callback_name: str = ""
# font
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
self._font = CTkFont() if font is None else self._check_font_type(font)
if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font)
@ -158,17 +158,7 @@ class CTkEntry(CTkBaseClass):
self._apply_widget_scaling(self._border_width))
if requires_recoloring or no_color_updates is False:
if self._apply_appearance_mode(self._fg_color) is not None:
self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._fg_color),
outline=self._apply_appearance_mode(self._fg_color))
self._entry.configure(bg=self._apply_appearance_mode(self._fg_color),
fg=self._apply_appearance_mode(self._text_color),
disabledbackground=self._apply_appearance_mode(self._fg_color),
disabledforeground=self._apply_appearance_mode(self._text_color),
highlightcolor=self._apply_appearance_mode(self._fg_color),
insertbackground=self._apply_appearance_mode(self._text_color))
else:
if self._apply_appearance_mode(self._fg_color) == "transparent":
self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._bg_color),
outline=self._apply_appearance_mode(self._bg_color))
@ -178,6 +168,16 @@ class CTkEntry(CTkBaseClass):
disabledforeground=self._apply_appearance_mode(self._text_color),
highlightcolor=self._apply_appearance_mode(self._bg_color),
insertbackground=self._apply_appearance_mode(self._text_color))
else:
self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._fg_color),
outline=self._apply_appearance_mode(self._fg_color))
self._entry.configure(bg=self._apply_appearance_mode(self._fg_color),
fg=self._apply_appearance_mode(self._text_color),
disabledbackground=self._apply_appearance_mode(self._fg_color),
disabledforeground=self._apply_appearance_mode(self._text_color),
highlightcolor=self._apply_appearance_mode(self._fg_color),
insertbackground=self._apply_appearance_mode(self._text_color))
self._canvas.itemconfig("border_parts",
fill=self._apply_appearance_mode(self._border_color),
@ -192,15 +192,19 @@ class CTkEntry(CTkBaseClass):
self._entry.configure(state=self._state)
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"))
require_redraw = True
if "text_color" in kwargs:
self._text_color = kwargs.pop("text_color")
self._text_color = self._check_color_type(kwargs.pop("text_color"))
require_redraw = True
if "placeholder_text_color" in kwargs:
self._placeholder_text_color = self._check_color_type(kwargs.pop("placeholder_text_color"))
require_redraw = True
if "border_color" in kwargs:
self._border_color = kwargs.pop("border_color")
self._border_color = self._check_color_type(kwargs.pop("border_color"))
require_redraw = True
if "border_width" in kwargs:
@ -221,10 +225,6 @@ class CTkEntry(CTkBaseClass):
else:
self._activate_placeholder()
if "placeholder_text_color" in kwargs:
self._placeholder_text_color = kwargs.pop("placeholder_text_color")
require_redraw = True
if "textvariable" in kwargs:
self._textvariable = kwargs.pop("textvariable")
self._entry.configure(textvariable=self._textvariable)

View File

@ -1,4 +1,4 @@
from typing import Union, Tuple, List
from typing import Union, Tuple, List, Optional
from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager
@ -15,28 +15,28 @@ class CTkFrame(CTkBaseClass):
"""
def __init__(self,
master: any = None,
master: any,
width: int = 200,
height: int = 200,
corner_radius: Union[int, str] = "default_theme",
border_width: Union[int, str] = "default_theme",
corner_radius: Optional[Union[int, str]] = None,
border_width: Optional[Union[int, str]] = None,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str], None] = "default_theme",
border_color: Union[str, Tuple[str, str]] = "default_theme",
background_corner_colors: Tuple[Union[str, Tuple[str, str]]] = None,
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Optional[Union[str, Tuple[str, str]]] = None,
background_corner_colors: Union[Tuple[Union[str, Tuple[str, str]]], None] = None,
overwrite_preferred_drawing_method: str = None,
overwrite_preferred_drawing_method: Union[str, None] = None,
**kwargs):
# transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color
self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color == "default_theme" else border_color
self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color is None else self._check_color_type(border_color)
# determine fg_color of frame
if fg_color == "default_theme":
if fg_color is None:
if isinstance(self.master, CTkFrame):
if self.master._fg_color == ThemeManager.theme["color"]["frame_low"]:
self._fg_color = ThemeManager.theme["color"]["frame_high"]
@ -45,13 +45,13 @@ class CTkFrame(CTkBaseClass):
else:
self._fg_color = ThemeManager.theme["color"]["frame_low"]
else:
self._fg_color = fg_color
self._fg_color = self._check_color_type(fg_color, transparency=True)
self._background_corner_colors = background_corner_colors # rendering options for DrawEngine
# shape
self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width == "default_theme" else border_width
self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius is None else corner_radius
self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width is None else border_width
self._canvas = CTkCanvas(master=self,
highlightthickness=0,
@ -80,7 +80,8 @@ class CTkFrame(CTkBaseClass):
def _set_scaling(self, *args, **kwargs):
super()._set_scaling(*args, **kwargs)
self._canvas.configure(width=self._apply_widget_scaling(self._desired_width), height=self._apply_widget_scaling(self._desired_height))
self._canvas.configure(width=self._apply_widget_scaling(self._desired_width),
height=self._apply_widget_scaling(self._desired_height))
self._draw()
def _set_dimensions(self, width=None, height=None):
@ -113,7 +114,7 @@ class CTkFrame(CTkBaseClass):
overwrite_preferred_drawing_method=self._overwrite_preferred_drawing_method)
if no_color_updates is False or requires_recoloring:
if self._fg_color is None:
if self._fg_color == "transparent":
self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._bg_color),
outline=self._apply_appearance_mode(self._bg_color))
@ -132,7 +133,7 @@ class CTkFrame(CTkBaseClass):
def configure(self, require_redraw=False, **kwargs):
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True)
require_redraw = True
# check if CTk widgets are children of the frame and change their bg_color to new frame fg_color
@ -141,14 +142,14 @@ class CTkFrame(CTkBaseClass):
child.configure(bg_color=self._fg_color)
if "bg_color" in kwargs:
# pass bg_color change to children if fg_color is None
if self._fg_color is None:
# pass bg_color change to children if fg_color is "transparent"
if self._fg_color == "transparent":
for child in self.winfo_children():
if isinstance(child, CTkBaseClass):
child.configure(bg_color=self._fg_color)
if "border_color" in kwargs:
self._border_color = kwargs.pop("border_color")
self._border_color = self._check_color_type(kwargs.pop("border_color"))
require_redraw = True
if "background_corner_colors" in kwargs:

View File

@ -1,5 +1,5 @@
import tkinter
from typing import Union, Tuple, Callable
from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager
@ -22,18 +22,18 @@ class CTkLabel(CTkBaseClass):
"textvariable", "state", "takefocus", "underline", "wraplength"}
def __init__(self,
master: any = None,
master: any,
width: int = 0,
height: int = 28,
corner_radius: Union[int, str] = "default_theme",
corner_radius: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str], None] = "default_theme",
text_color: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
text: str = "CTkLabel",
font: Union[tuple, CTkFont] = "default_theme",
image: Union[tkinter.PhotoImage, CTkImage] = None,
font: Optional[Union[tuple, CTkFont]] = None,
image: Union[tkinter.PhotoImage, CTkImage, None] = None,
compound: str = "center",
anchor: str = "center", # label anchor: center, n, e, s, w
**kwargs):
@ -42,11 +42,11 @@ class CTkLabel(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height)
# color
self._fg_color = ThemeManager.theme["color"]["label"] if fg_color == "default_theme" else fg_color
self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
self._fg_color = ThemeManager.theme["color"]["label"] if fg_color is None else self._check_color_type(fg_color, transparency=True)
self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color)
# shape
self._corner_radius = ThemeManager.theme["shape"]["label_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._corner_radius = ThemeManager.theme["shape"]["label_corner_radius"] if corner_radius is None else corner_radius
# text
self._anchor = anchor
@ -59,7 +59,7 @@ class CTkLabel(CTkBaseClass):
self._image.add_configure_callback(self._update_image)
# font
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
self._font = CTkFont() if font is None else self._check_font_type(font)
if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font)
@ -145,20 +145,20 @@ class CTkLabel(CTkBaseClass):
0)
if no_color_updates is False or requires_recoloring:
if self._apply_appearance_mode(self._fg_color) is not None:
self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._fg_color),
outline=self._apply_appearance_mode(self._fg_color))
self._label.configure(fg=self._apply_appearance_mode(self._text_color),
bg=self._apply_appearance_mode(self._fg_color))
else:
if self._apply_appearance_mode(self._fg_color) == "transparent":
self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._bg_color),
outline=self._apply_appearance_mode(self._bg_color))
self._label.configure(fg=self._apply_appearance_mode(self._text_color),
bg=self._apply_appearance_mode(self._bg_color))
else:
self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._fg_color),
outline=self._apply_appearance_mode(self._fg_color))
self._label.configure(fg=self._apply_appearance_mode(self._text_color),
bg=self._apply_appearance_mode(self._fg_color))
self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color))
@ -172,11 +172,11 @@ class CTkLabel(CTkBaseClass):
require_redraw = True
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True)
require_redraw = True
if "text_color" in kwargs:
self._text_color = kwargs.pop("text_color")
self._text_color = self._check_color_type(kwargs.pop("text_color"))
require_redraw = True
if "text" in kwargs:

View File

@ -1,6 +1,6 @@
import tkinter
import sys
from typing import Union, Tuple, Callable
from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager
@ -17,28 +17,28 @@ class CTkOptionMenu(CTkBaseClass):
"""
def __init__(self,
master: any = None,
master: any,
width: int = 140,
height: int = 28,
corner_radius: Union[int, str] = "default_theme",
corner_radius: Optional[Union[int]] = None,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str]] = "default_theme",
button_color: Union[str, Tuple[str, str]] = "default_theme",
button_hover_color: Union[str, Tuple[str, str]] = "default_theme",
text_color: Union[str, Tuple[str, str]] = "default_theme",
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme",
dropdown_fg_color: Union[str, Tuple[str, str]] = "default_theme",
dropdown_hover_color: Union[str, Tuple[str, str]] = "default_theme",
dropdown_text_color: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
button_color: Optional[Union[str, Tuple[str, str]]] = None,
button_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
dropdown_fg_color: Optional[Union[str, Tuple[str, str]]] = None,
dropdown_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
dropdown_text_color: Optional[Union[str, Tuple[str, str]]] = None,
font: Union[tuple, CTkFont] = "default_theme",
dropdown_font: Union[tuple, CTkFont] = "default_theme",
values: list = None,
variable: tkinter.Variable = None,
font: Optional[Union[tuple, CTkFont]] = None,
dropdown_font: Optional[Union[tuple, CTkFont]] = None,
values: Optional[list] = None,
variable: Union[tkinter.Variable, None] = None,
state: str = tkinter.NORMAL,
hover: bool = True,
command: Callable[[str], None] = None,
command: Union[Callable[[str], None], None] = None,
dynamic_resizing: bool = True,
anchor: str = "w",
**kwargs):
@ -47,19 +47,19 @@ class CTkOptionMenu(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color variables
self._fg_color = ThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_color
self._button_color = ThemeManager.theme["color"]["optionmenu_button"] if button_color == "default_theme" else button_color
self._button_hover_color = ThemeManager.theme["color"]["optionmenu_button_hover"] if button_hover_color == "default_theme" else button_hover_color
self._fg_color = ThemeManager.theme["color"]["button"] if fg_color is None else self._check_color_type(fg_color)
self._button_color = ThemeManager.theme["color"]["optionmenu_button"] if button_color is None else self._check_color_type(button_color)
self._button_hover_color = ThemeManager.theme["color"]["optionmenu_button_hover"] if button_hover_color is None else self._check_color_type(button_hover_color)
# shape
self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius is None else corner_radius
# text and font
self._text_color = ThemeManager.theme["color"]["text_button"] if text_color == "default_theme" else text_color
self._text_color_disabled = ThemeManager.theme["color"]["text_button_disabled"] if text_color_disabled == "default_theme" else text_color_disabled
self._text_color = ThemeManager.theme["color"]["text_button"] if text_color is None else self._check_color_type(text_color)
self._text_color_disabled = ThemeManager.theme["color"]["text_button_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled)
# font
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
self._font = CTkFont() if font is None else self._check_font_type(font)
if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font)
@ -194,7 +194,6 @@ class CTkOptionMenu(CTkBaseClass):
self._apply_widget_scaling(self._current_height / 3))
if no_color_updates is False or requires_recoloring or requires_recoloring_2:
self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color))
self._canvas.itemconfig("inner_parts_left",
@ -226,19 +225,19 @@ class CTkOptionMenu(CTkBaseClass):
require_redraw = True
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"))
require_redraw = True
if "button_color" in kwargs:
self._button_color = kwargs.pop("button_color")
self._button_color = self._check_color_type(kwargs.pop("button_color"))
require_redraw = True
if "button_hover_color" in kwargs:
self._button_hover_color = kwargs.pop("button_hover_color")
self._button_hover_color = self._check_color_type(kwargs.pop("button_hover_color"))
require_redraw = True
if "text_color" in kwargs:
self._text_color = kwargs.pop("text_color")
self._text_color = self._check_color_type(kwargs.pop("text_color"))
require_redraw = True
if "dropdown_color" in kwargs:

View File

@ -1,6 +1,6 @@
import tkinter
import math
from typing import Union, Tuple
from typing import Union, Tuple, Optional
from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager
@ -16,18 +16,18 @@ class CTkProgressBar(CTkBaseClass):
"""
def __init__(self,
master: any = None,
width: Union[int, str] = "default_init",
height: Union[int, str] = "default_init",
corner_radius: Union[str, Tuple[str, str]] = "default_theme",
border_width: Union[int, str] = "default_theme",
master: any,
width: Optional[int] = None,
height: Optional[int] = None,
corner_radius: Optional[int] = None,
border_width: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str]] = "default_theme",
border_color: Union[str, Tuple[str, str]] = "default_theme",
progress_color: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Optional[Union[str, Tuple[str, str]]] = None,
progress_color: Optional[Union[str, Tuple[str, str]]] = None,
variable: tkinter.Variable = None,
variable: Union[tkinter.Variable, None] = None,
orientation: str = "horizontal",
mode: str = "determinate",
determinate_speed: float = 1,
@ -35,12 +35,12 @@ class CTkProgressBar(CTkBaseClass):
**kwargs):
# set default dimensions according to orientation
if width == "default_init":
if width is None:
if orientation.lower() == "vertical":
width = 8
else:
width = 200
if height == "default_init":
if height is None:
if orientation.lower() == "vertical":
height = 200
else:
@ -50,9 +50,9 @@ class CTkProgressBar(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color
self._border_color = ThemeManager.theme["color"]["progressbar_border"] if border_color == "default_theme" else border_color
self._fg_color = ThemeManager.theme["color"]["progressbar"] if fg_color == "default_theme" else fg_color
self._progress_color = ThemeManager.theme["color"]["progressbar_progress"] if progress_color == "default_theme" else progress_color
self._border_color = ThemeManager.theme["color"]["progressbar_border"] if border_color is None else self._check_color_type(border_color)
self._fg_color = ThemeManager.theme["color"]["progressbar"] if fg_color is None else self._check_color_type(fg_color)
self._progress_color = ThemeManager.theme["color"]["progressbar_progress"] if progress_color is None else self._check_color_type(progress_color)
# control variable
self._variable = variable
@ -60,8 +60,8 @@ class CTkProgressBar(CTkBaseClass):
self._variable_callback_name = None
# shape
self._corner_radius = ThemeManager.theme["shape"]["progressbar_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._border_width = ThemeManager.theme["shape"]["progressbar_border_width"] if border_width == "default_theme" else border_width
self._corner_radius = ThemeManager.theme["shape"]["progressbar_corner_radius"] if corner_radius is None else corner_radius
self._border_width = ThemeManager.theme["shape"]["progressbar_border_width"] if border_width is None else border_width
self._determinate_value: float = 0.5 # range 0-1
self._determinate_speed = determinate_speed # range 0-1
self._indeterminate_value: float = 0 # range 0-inf
@ -162,15 +162,15 @@ class CTkProgressBar(CTkBaseClass):
require_redraw = True
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"))
require_redraw = True
if "border_color" in kwargs:
self._border_color = kwargs.pop("border_color")
self._border_color = self._check_color_type(kwargs.pop("border_color"))
require_redraw = True
if "progress_color" in kwargs:
self._progress_color = kwargs.pop("progress_color")
self._progress_color = self._check_color_type(kwargs.pop("progress_color"))
require_redraw = True
if "variable" in kwargs:

View File

@ -1,6 +1,6 @@
import tkinter
import sys
from typing import Union, Tuple, Callable
from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager
@ -16,30 +16,30 @@ class CTkRadioButton(CTkBaseClass):
"""
def __init__(self,
master: any = None,
master: any,
width: int = 100,
height: int = 22,
radiobutton_width: int = 22,
radiobutton_height: int = 22,
corner_radius: Union[int, str] = "default_theme",
border_width_unchecked: Union[int, str] = "default_theme",
border_width_checked: Union[int, str] = "default_theme",
corner_radius: Optional[int] = None,
border_width_unchecked: Optional[int] = None,
border_width_checked: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str]] = "default_theme",
hover_color: Union[str, Tuple[str, str]] = "default_theme",
border_color: Union[str, Tuple[str, str]] = "default_theme",
text_color: Union[str, Tuple[str, str]] = "default_theme",
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
hover_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
text: str = "CTkRadioButton",
font: Union[tuple, CTkFont] = "default_theme",
textvariable: tkinter.Variable = None,
variable: tkinter.Variable = None,
font: Optional[Union[tuple, CTkFont]] = None,
textvariable: Union[tkinter.Variable, None] = None,
variable: Union[tkinter.Variable, None] = None,
value: Union[int, str] = 0,
state: str = tkinter.NORMAL,
hover: bool = True,
command: Callable = None,
command: Union[Callable, None] = None,
**kwargs):
# transfer basic functionality (_bg_color, size, __appearance_mode, scaling) to CTkBaseClass
@ -50,23 +50,23 @@ class CTkRadioButton(CTkBaseClass):
self._radiobutton_height = radiobutton_height
# color
self._fg_color = ThemeManager.theme["color"]["button"] if fg_color == "default_theme" else fg_color
self._hover_color = ThemeManager.theme["color"]["button_hover"] if hover_color == "default_theme" else hover_color
self._border_color = ThemeManager.theme["color"]["checkbox_border"] if border_color == "default_theme" else border_color
self._fg_color = ThemeManager.theme["color"]["button"] if fg_color is None else self._check_color_type(fg_color)
self._hover_color = ThemeManager.theme["color"]["button_hover"] if hover_color is None else self._check_color_type(hover_color)
self._border_color = ThemeManager.theme["color"]["checkbox_border"] if border_color is None else self._check_color_type(border_color)
# shape
self._corner_radius = ThemeManager.theme["shape"]["radiobutton_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._border_width_unchecked = ThemeManager.theme["shape"]["radiobutton_border_width_unchecked"] if border_width_unchecked == "default_theme" else border_width_unchecked
self._border_width_checked = ThemeManager.theme["shape"]["radiobutton_border_width_checked"] if border_width_checked == "default_theme" else border_width_checked
self._corner_radius = ThemeManager.theme["shape"]["radiobutton_corner_radius"] if corner_radius is None else corner_radius
self._border_width_unchecked = ThemeManager.theme["shape"]["radiobutton_border_width_unchecked"] if border_width_unchecked is None else border_width_unchecked
self._border_width_checked = ThemeManager.theme["shape"]["radiobutton_border_width_checked"] if border_width_checked is None else border_width_checked
# text
self._text = text
self._text_label: Union[tkinter.Label, None] = None
self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled == "default_theme" else text_color_disabled
self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color)
self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled)
# font
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
self._font = CTkFont() if font is None else self._check_font_type(font)
if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font)
@ -241,19 +241,23 @@ class CTkRadioButton(CTkBaseClass):
require_redraw = True
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"))
require_redraw = True
if "hover_color" in kwargs:
self._hover_color = kwargs.pop("hover_color")
self._hover_color = self._check_color_type(kwargs.pop("hover_color"))
require_redraw = True
if "text_color" in kwargs:
self._text_color = kwargs.pop("text_color")
self._text_color = self._check_color_type(kwargs.pop("text_color"))
require_redraw = True
if "text_color_disabled" in kwargs:
self._text_color_disabled = self._check_color_type(kwargs.pop("text_color_disabled"))
require_redraw = True
if "border_color" in kwargs:
self._border_color = kwargs.pop("border_color")
self._border_color = self._check_color_type(kwargs.pop("border_color"))
require_redraw = True
if "hover" in kwargs:

View File

@ -1,5 +1,5 @@
import sys
from typing import Union, Tuple, Callable
from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager
@ -15,30 +15,30 @@ class CTkScrollbar(CTkBaseClass):
"""
def __init__(self,
master: any = None,
width: Union[int, str] = "default_init",
height: Union[int, str] = "default_init",
corner_radius: Union[int, str] = "default_theme",
border_spacing: Union[int, str] = "default_theme",
master: any,
width: Optional[Union[int, str]] = None,
height: Optional[Union[int, str]] = None,
corner_radius: Optional[int] = None,
border_spacing: Optional[int] = None,
minimum_pixel_length: int = 20,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str], None] = "default_theme",
scrollbar_color: Union[str, Tuple[str, str]] = "default_theme",
scrollbar_hover_color: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
scrollbar_color: Optional[Union[str, Tuple[str, str]]] = None,
scrollbar_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
hover: bool = True,
command: Callable = None,
command: Union[Callable, None] = None,
orientation: str = "vertical",
**kwargs):
# set default dimensions according to orientation
if width == "default_init":
if width is None:
if orientation.lower() == "vertical":
width = 16
else:
width = 200
if height == "default_init":
if height is None:
if orientation.lower() == "horizontal":
height = 16
else:
@ -48,13 +48,13 @@ class CTkScrollbar(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color
self._fg_color = ThemeManager.theme["color"]["frame_high"] if fg_color == "default_theme" else fg_color
self._scrollbar_color = ThemeManager.theme["color"]["scrollbar_button"] if scrollbar_color == "default_theme" else scrollbar_color
self._scrollbar_hover_color = ThemeManager.theme["color"]["scrollbar_button_hover"] if scrollbar_hover_color == "default_theme" else scrollbar_hover_color
self._fg_color = ThemeManager.theme["color"]["frame_high"] if fg_color is None else self._check_color_type(fg_color, transparency=True)
self._scrollbar_color = ThemeManager.theme["color"]["scrollbar_button"] if scrollbar_color is None else self._check_color_type(scrollbar_color)
self._scrollbar_hover_color = ThemeManager.theme["color"]["scrollbar_button_hover"] if scrollbar_hover_color is None else self._check_color_type(scrollbar_hover_color)
# shape
self._corner_radius = ThemeManager.theme["shape"]["scrollbar_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._border_spacing = ThemeManager.theme["shape"]["scrollbar_border_spacing"] if border_spacing == "default_theme" else border_spacing
self._corner_radius = ThemeManager.theme["shape"]["scrollbar_corner_radius"] if corner_radius is None else corner_radius
self._border_spacing = ThemeManager.theme["shape"]["scrollbar_border_spacing"] if border_spacing is None else border_spacing
self._hover = hover
self._hover_state: bool = False
@ -139,7 +139,7 @@ class CTkScrollbar(CTkBaseClass):
fill=self._apply_appearance_mode(self._scrollbar_color),
outline=self._apply_appearance_mode(self._scrollbar_color))
if self._fg_color is None:
if self._fg_color == "transparent":
self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color))
self._canvas.itemconfig("border_parts",
fill=self._apply_appearance_mode(self._bg_color),
@ -154,15 +154,15 @@ class CTkScrollbar(CTkBaseClass):
def configure(self, require_redraw=False, **kwargs):
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True)
require_redraw = True
if "scrollbar_color" in kwargs:
self._scrollbar_color = kwargs.pop("scrollbar_color")
self._scrollbar_color = self._check_color_type(kwargs.pop("scrollbar_color"))
require_redraw = True
if "scrollbar_hover_color" in kwargs:
self._scrollbar_hover_color = kwargs.pop("scrollbar_hover_color")
self._scrollbar_hover_color = self._check_color_type(kwargs.pop("scrollbar_hover_color"))
require_redraw = True
if "hover" in kwargs:

View File

@ -1,5 +1,5 @@
import tkinter
from typing import Union, Tuple, List, Dict, Callable
from typing import Union, Tuple, List, Dict, Callable, Optional, Literal
from .theme.theme_manager import ThemeManager
from .ctk_button import CTkButton
@ -14,50 +14,50 @@ class CTkSegmentedButton(CTkFrame):
"""
def __init__(self,
master: any = None,
master: any,
width: int = 140,
height: int = 28,
corner_radius: Union[int, str] = "default_theme",
border_width: Union[int, str] = 3,
corner_radius: Optional[int] = None,
border_width: int = 3,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str], None] = "default_theme",
selected_color: Union[str, Tuple[str, str]] = "default_theme",
selected_hover_color: Union[str, Tuple[str, str]] = "default_theme",
unselected_color: Union[str, Tuple[str, str]] = "default_theme",
unselected_hover_color: Union[str, Tuple[str, str]] = "default_theme",
text_color: Union[str, Tuple[str, str]] = "default_theme",
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme",
background_corner_colors: Tuple[Union[str, Tuple[str, str]]] = None,
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
selected_color: Optional[Union[str, Tuple[str, str]]] = None,
selected_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
unselected_color: Optional[Union[str, Tuple[str, str]]] = None,
unselected_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
background_corner_colors: Union[Tuple[Union[str, Tuple[str, str]]], None] = None,
font: Union[tuple, CTkFont] = "default_theme",
values: list = None,
variable: tkinter.Variable = None,
font: Optional[Union[tuple, CTkFont]] = None,
values: Optional[list] = None,
variable: Union[tkinter.Variable, None] = None,
dynamic_resizing: bool = True,
command: Callable[[str], None] = None,
command: Union[Callable[[str], None], None] = None,
state: str = "normal",
**kwargs):
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
self._sb_fg_color = ThemeManager.theme["color"]["segmented_button"] if fg_color == "default_theme" else fg_color
self._sb_fg_color = ThemeManager.theme["color"]["segmented_button"] if fg_color is None else self._check_color_type(fg_color)
self._sb_selected_color = ThemeManager.theme["color"]["button"] if selected_color == "default_theme" else selected_color
self._sb_selected_hover_color = ThemeManager.theme["color"]["button_hover"] if selected_hover_color == "default_theme" else selected_hover_color
self._sb_selected_color = ThemeManager.theme["color"]["button"] if selected_color is None else self._check_color_type(selected_color)
self._sb_selected_hover_color = ThemeManager.theme["color"]["button_hover"] if selected_hover_color is None else self._check_color_type(selected_hover_color)
self._sb_unselected_color = ThemeManager.theme["color"]["segmented_button_unselected"] if unselected_color == "default_theme" else unselected_color
self._sb_unselected_hover_color = ThemeManager.theme["color"]["segmented_button_unselected_hover"] if unselected_hover_color == "default_theme" else unselected_hover_color
self._sb_unselected_color = ThemeManager.theme["color"]["segmented_button_unselected"] if unselected_color is None else self._check_color_type(unselected_color)
self._sb_unselected_hover_color = ThemeManager.theme["color"]["segmented_button_unselected_hover"] if unselected_hover_color is None else self._check_color_type(unselected_hover_color)
self._sb_text_color = ThemeManager.theme["color"]["text_button"] if text_color == "default_theme" else text_color
self._sb_text_color_disabled = ThemeManager.theme["color"]["text_button_disabled"] if text_color_disabled == "default_theme" else text_color_disabled
self._sb_text_color = ThemeManager.theme["color"]["text_button"] if text_color is None else self._check_color_type(text_color)
self._sb_text_color_disabled = ThemeManager.theme["color"]["text_button_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled)
self._sb_corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._sb_border_width = ThemeManager.theme["shape"]["button_border_width"] if border_width == "default_theme" else border_width
self._sb_corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius is None else corner_radius
self._sb_border_width = ThemeManager.theme["shape"]["button_border_width"] if border_width is None else border_width
self._background_corner_colors = background_corner_colors # rendering options for DrawEngine
self._command: Callable[[str], None] = command
self._font = (ThemeManager.theme["text"]["font"], ThemeManager.theme["text"]["size"]) if font == "default_theme" else font
self._font = (ThemeManager.theme["text"]["font"], ThemeManager.theme["text"]["size"]) if font is None else font
self._state = state
self._buttons_dict: Dict[str, CTkButton] = {} # mapped from value to button object
@ -84,7 +84,7 @@ class CTkSegmentedButton(CTkFrame):
self._variable_callback_name = self._variable.trace_add("write", self._variable_callback)
self.set(self._variable.get(), from_variable_callback=True)
super().configure(corner_radius=self._sb_corner_radius, fg_color=None)
super().configure(corner_radius=self._sb_corner_radius, fg_color="red")
def destroy(self):
if self._variable is not None: # remove old callback
@ -147,21 +147,22 @@ class CTkSegmentedButton(CTkFrame):
def _create_button(self, index: int, value: str) -> CTkButton:
new_button = CTkButton(self,
height=self._current_height,
width=0,
height=self._current_height,
corner_radius=self._sb_corner_radius,
text=value,
border_width=self._sb_border_width,
border_color=self._sb_fg_color,
fg_color=self._sb_unselected_color,
border_color=self._sb_fg_color,
hover_color=self._sb_unselected_hover_color,
text_color=self._sb_text_color,
text_color_disabled=self._sb_text_color_disabled,
text=value,
font=self._font,
state=self._state,
command=lambda v=value: self.set(v, from_button_callback=True),
background_corner_colors=None,
round_width_to_even_numbers=False) # DrawEngine rendering option (so that theres no gap between buttons)
round_width_to_even_numbers=False,
round_height_to_even_numbers=False) # DrawEngine rendering option (so that theres no gap between buttons)
return new_button
@ -201,40 +202,40 @@ class CTkSegmentedButton(CTkFrame):
self._configure_button_corners_for_index(max_index)
if "fg_color" in kwargs:
self._sb_fg_color = kwargs.pop("fg_color")
self._sb_fg_color = self._check_color_type(kwargs.pop("fg_color"))
for index, button in enumerate(self._buttons_dict.values()):
button.configure(border_color=self._sb_fg_color)
self._configure_button_corners_for_index(index)
if "selected_color" in kwargs:
self._sb_selected_color = kwargs.pop("selected_color")
self._sb_selected_color = self._check_color_type(kwargs.pop("selected_color"))
if self._current_value in self._buttons_dict:
self._buttons_dict[self._current_value].configure(fg_color=self._sb_selected_color)
if "selected_hover_color" in kwargs:
self._sb_selected_hover_color = kwargs.pop("selected_hover_color")
self._sb_selected_hover_color = self._check_color_type(kwargs.pop("selected_hover_color"))
if self._current_value in self._buttons_dict:
self._buttons_dict[self._current_value].configure(hover_color=self._sb_selected_hover_color)
if "unselected_color" in kwargs:
self._sb_unselected_color = kwargs.pop("unselected_color")
self._sb_unselected_color = self._check_color_type(kwargs.pop("unselected_color"))
for value, button in self._buttons_dict.items():
if value != self._current_value:
button.configure(fg_color=self._sb_unselected_color)
if "unselected_hover_color" in kwargs:
self._sb_unselected_hover_color = kwargs.pop("unselected_hover_color")
self._sb_unselected_hover_color = self._check_color_type(kwargs.pop("unselected_hover_color"))
for value, button in self._buttons_dict.items():
if value != self._current_value:
button.configure(hover_color=self._sb_unselected_hover_color)
if "text_color" in kwargs:
self._sb_text_color = kwargs.pop("text_color")
self._sb_text_color = self._check_color_type(kwargs.pop("text_color"))
for button in self._buttons_dict.values():
button.configure(text_color=self._sb_text_color)
if "text_color_disabled" in kwargs:
self._sb_text_color_disabled = kwargs.pop("text_color_disabled")
self._sb_text_color_disabled = self._check_color_type(kwargs.pop("text_color_disabled"))
for button in self._buttons_dict.values():
button.configure(text_color_disabled=self._sb_text_color_disabled)

View File

@ -1,6 +1,6 @@
import tkinter
import sys
from typing import Union, Tuple, Callable
from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager
@ -15,38 +15,38 @@ class CTkSlider(CTkBaseClass):
"""
def __init__(self,
master: any = None,
width: Union[int, str] = "default_init",
height: Union[int, str] = "default_init",
corner_radius: Union[int, str] = "default_theme",
button_corner_radius: Union[int, str] = "default_theme",
border_width: Union[int, str] = "default_theme",
button_length: Union[int, str] = "default_theme",
master: any,
width: Optional[int] = None,
height: Optional[int] = None,
corner_radius: Optional[int] = None,
button_corner_radius: Optional[int] = None,
border_width: Optional[int] = None,
button_length: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str]] = "default_theme",
border_color: Union[str, Tuple[str, str], None] = None,
progress_color: Union[str, Tuple[str, str], None] = "default_theme",
button_color: Union[str, Tuple[str, str]] = "default_theme",
button_hover_color: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str]] = "transparent",
progress_color: Optional[Union[str, Tuple[str, str]]] = None,
button_color: Optional[Union[str, Tuple[str, str]]] = None,
button_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
from_: int = 0,
to: int = 1,
state: str = "normal",
number_of_steps: Union[int, None] = None,
hover: bool = True,
command: Callable[[float], None] = None,
variable: tkinter.Variable = None,
command: Union[Callable[[float], None], None] = None,
variable: Union[tkinter.Variable, None] = None,
orientation: str = "horizontal",
**kwargs):
# set default dimensions according to orientation
if width == "default_init":
if width is None:
if orientation.lower() == "vertical":
width = 16
else:
width = 200
if height == "default_init":
if height is None:
if orientation.lower() == "vertical":
height = 200
else:
@ -56,17 +56,17 @@ class CTkSlider(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color
self._border_color = border_color
self._fg_color = ThemeManager.theme["color"]["slider"] if fg_color == "default_theme" else fg_color
self._progress_color = ThemeManager.theme["color"]["slider_progress"] if progress_color == "default_theme" else progress_color
self._button_color = ThemeManager.theme["color"]["slider_button"] if button_color == "default_theme" else button_color
self._button_hover_color = ThemeManager.theme["color"]["slider_button_hover"] if button_hover_color == "default_theme" else button_hover_color
self._border_color = self._check_color_type(border_color, transparency=True)
self._fg_color = ThemeManager.theme["color"]["slider"] if fg_color is None else self._check_color_type(fg_color)
self._progress_color = ThemeManager.theme["color"]["slider_progress"] if progress_color is None else self._check_color_type(progress_color, transparency=True)
self._button_color = ThemeManager.theme["color"]["slider_button"] if button_color is None else self._check_color_type(button_color)
self._button_hover_color = ThemeManager.theme["color"]["slider_button_hover"] if button_hover_color is None else self._check_color_type(button_hover_color)
# shape
self._corner_radius = ThemeManager.theme["shape"]["slider_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._button_corner_radius = ThemeManager.theme["shape"]["slider_button_corner_radius"] if button_corner_radius == "default_theme" else button_corner_radius
self._border_width = ThemeManager.theme["shape"]["slider_border_width"] if border_width == "default_theme" else border_width
self._button_length = ThemeManager.theme["shape"]["slider_button_length"] if button_length == "default_theme" else button_length
self._corner_radius = ThemeManager.theme["shape"]["slider_corner_radius"] if corner_radius is None else corner_radius
self._button_corner_radius = ThemeManager.theme["shape"]["slider_button_corner_radius"] if button_corner_radius is None else button_corner_radius
self._border_width = ThemeManager.theme["shape"]["slider_border_width"] if border_width is None else border_width
self._button_length = ThemeManager.theme["shape"]["slider_button_length"] if button_length is None else button_length
self._value: float = 0.5 # initial value of slider in percent
self._orientation = orientation
self._hover_state: bool = False
@ -165,7 +165,7 @@ class CTkSlider(CTkBaseClass):
if no_color_updates is False or requires_recoloring:
self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color))
if self._border_color is None:
if self._border_color == "transparent":
self._canvas.itemconfig("border_parts", fill=self._apply_appearance_mode(self._bg_color),
outline=self._apply_appearance_mode(self._bg_color))
else:
@ -175,7 +175,7 @@ class CTkSlider(CTkBaseClass):
self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._fg_color),
outline=self._apply_appearance_mode(self._fg_color))
if self._progress_color is None:
if self._progress_color == "transparent":
self._canvas.itemconfig("progress_parts", fill=self._apply_appearance_mode(self._fg_color),
outline=self._apply_appearance_mode(self._fg_color))
else:
@ -198,23 +198,23 @@ class CTkSlider(CTkBaseClass):
require_redraw = True
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"))
require_redraw = True
if "progress_color" in kwargs:
self._progress_color = kwargs.pop("progress_color")
self._progress_color = self._check_color_type(kwargs.pop("progress_color"), transparency=True)
require_redraw = True
if "button_color" in kwargs:
self._button_color = kwargs.pop("button_color")
self._button_color = self._check_color_type(kwargs.pop("button_color"))
require_redraw = True
if "button_hover_color" in kwargs:
self._button_hover_color = kwargs.pop("button_hover_color")
self._button_hover_color = self._check_color_type(kwargs.pop("button_hover_color"))
require_redraw = True
if "border_color" in kwargs:
self._border_color = kwargs.pop("border_color")
self._border_color = self._check_color_type(kwargs.pop("border_color"), transparency=True)
require_redraw = True
if "border_width" in kwargs:
@ -294,9 +294,9 @@ class CTkSlider(CTkBaseClass):
def _clicked(self, event=None):
if self._state == "normal":
if self._orientation.lower() == "horizontal":
self._value = (event.x / self._current_width) / self._widget_scaling
self._value = self._reverse_widget_scaling(event.x / self._current_width)
else:
self._value = 1 - (event.y / self._current_height) / self._widget_scaling
self._value = 1 - self._reverse_widget_scaling(event.y / self._current_height)
if self._value > 1:
self._value = 1

View File

@ -1,6 +1,6 @@
import tkinter
import sys
from typing import Union, Tuple, Callable
from typing import Union, Tuple, Callable, Optional
from .core_rendering.ctk_canvas import CTkCanvas
from .theme.theme_manager import ThemeManager
@ -16,32 +16,32 @@ class CTkSwitch(CTkBaseClass):
"""
def __init__(self,
master: any = None,
master: any,
width: int = 100,
height: int = 24,
switch_width: int = 36,
switch_height: int = 18,
corner_radius: Union[int, str] = "default_theme",
border_width: Union[int, str] = "default_theme",
button_length: Union[int, str] = "default_theme",
corner_radius: Optional[int] = None,
border_width: Optional[int] = None,
button_length: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str]] = "default_theme",
border_color: Union[str, Tuple[str, str], None] = None,
progress_color: Union[str, Tuple[str, str]] = "default_theme",
button_color: Union[str, Tuple[str, str]] = "default_theme",
button_hover_color: Union[str, Tuple[str, str]] = "default_theme",
text_color: Union[str, Tuple[str, str]] = "default_theme",
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Union[str, Tuple[str, str]] = "transparent",
progress_color: Optional[Union[str, Tuple[str, str]]] = None,
button_color: Optional[Union[str, Tuple[str, str]]] = None,
button_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
text: str = "CTkSwitch",
font: Union[tuple, CTkFont] = "default_theme",
textvariable: tkinter.Variable = None,
font: Optional[Union[tuple, CTkFont]] = None,
textvariable: Union[tkinter.Variable, None] = None,
onvalue: Union[int, str] = 1,
offvalue: Union[int, str] = 0,
variable: tkinter.Variable = None,
variable: Union[tkinter.Variable, None] = None,
hover: bool = True,
command: Callable = None,
command: Union[Callable, None] = None,
state: str = tkinter.NORMAL,
**kwargs):
@ -53,28 +53,27 @@ class CTkSwitch(CTkBaseClass):
self._switch_height = switch_height
# color
self._border_color = border_color
self._fg_color = ThemeManager.theme["color"]["switch"] if fg_color == "default_theme" else fg_color
self._progress_color = ThemeManager.theme["color"]["switch_progress"] if progress_color == "default_theme" else progress_color
self._button_color = ThemeManager.theme["color"]["switch_button"] if button_color == "default_theme" else button_color
self._button_hover_color = ThemeManager.theme["color"]["switch_button_hover"] if button_hover_color == "default_theme" else button_hover_color
self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled == "default_theme" else text_color_disabled
self._border_color = self._check_color_type(border_color, transparency=True)
self._fg_color = ThemeManager.theme["color"]["switch"] if fg_color is None else self._check_color_type(fg_color)
self._progress_color = ThemeManager.theme["color"]["switch_progress"] if progress_color is None else self._check_color_type(progress_color, transparency=True)
self._button_color = ThemeManager.theme["color"]["switch_button"] if button_color is None else self._check_color_type(button_color)
self._button_hover_color = ThemeManager.theme["color"]["switch_button_hover"] if button_hover_color is None else self._check_color_type(button_hover_color)
self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color)
self._text_color_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled is None else self._check_color_type(text_color_disabled)
# text
self._text = text
self._text_label = None
# font
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
self._font = CTkFont() if font is None else self._check_font_type(font)
if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font)
# shape
self._corner_radius = ThemeManager.theme["shape"]["switch_corner_radius"] if corner_radius == "default_theme" else corner_radius
# self.button_corner_radius = ThemeManager.theme["shape"]["switch_button_corner_radius"] if button_corner_radius == "default_theme" else button_corner_radius
self._border_width = ThemeManager.theme["shape"]["switch_border_width"] if border_width == "default_theme" else border_width
self._button_length = ThemeManager.theme["shape"]["switch_button_length"] if button_length == "default_theme" else button_length
self._corner_radius = ThemeManager.theme["shape"]["switch_corner_radius"] if corner_radius is None else corner_radius
self._border_width = ThemeManager.theme["shape"]["switch_border_width"] if border_width is None else border_width
self._button_length = ThemeManager.theme["shape"]["switch_button_length"] if button_length is None else button_length
self._hover_state: bool = False
self._check_state: bool = False # True if switch is activated
self._hover = hover
@ -84,7 +83,7 @@ class CTkSwitch(CTkBaseClass):
# callback and control variables
self._command = command
self._variable: tkinter.Variable = variable
self._variable = variable
self._variable_callback_blocked = False
self._variable_callback_name = None
self._textvariable = textvariable
@ -216,7 +215,7 @@ class CTkSwitch(CTkBaseClass):
self._bg_canvas.configure(bg=self._apply_appearance_mode(self._bg_color))
self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color))
if self._border_color is None:
if self._border_color == "transparent":
self._canvas.itemconfig("border_parts", fill=self._apply_appearance_mode(self._bg_color),
outline=self._apply_appearance_mode(self._bg_color))
else:
@ -226,7 +225,7 @@ class CTkSwitch(CTkBaseClass):
self._canvas.itemconfig("inner_parts", fill=self._apply_appearance_mode(self._fg_color),
outline=self._apply_appearance_mode(self._fg_color))
if self._progress_color is None:
if self._progress_color == "transparent":
self._canvas.itemconfig("progress_parts", fill=self._apply_appearance_mode(self._fg_color),
outline=self._apply_appearance_mode(self._fg_color))
else:
@ -285,27 +284,23 @@ class CTkSwitch(CTkBaseClass):
require_redraw = True
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"))
require_redraw = True
if "progress_color" in kwargs:
new_progress_color = kwargs.pop("progress_color")
if new_progress_color is None:
self._progress_color = self._fg_color
else:
self._progress_color = new_progress_color
self._progress_color = self._check_color_type(kwargs.pop("progress_color"), transparency=True)
require_redraw = True
if "button_color" in kwargs:
self._button_color = kwargs.pop("button_color")
self._button_color = self._check_color_type(kwargs.pop("button_color"))
require_redraw = True
if "button_hover_color" in kwargs:
self._button_hover_color = kwargs.pop("button_hover_color")
self._button_hover_color = self._check_color_type(kwargs.pop("button_hover_color"))
require_redraw = True
if "border_color" in kwargs:
self._border_color = kwargs.pop("border_color")
self._border_color = self._check_color_type(kwargs.pop("border_color"), transparency=True)
require_redraw = True
if "hover" in kwargs:

View File

@ -1,4 +1,4 @@
from typing import Union, Tuple, Dict, List, Callable
from typing import Union, Tuple, Dict, List, Callable, Optional
from .theme.theme_manager import ThemeManager
from .ctk_frame import CTkFrame
@ -14,32 +14,32 @@ class CTkTabview(CTkBaseClass):
For detailed information check out the documentation.
"""
_top_spacing = 10 # px on top of the buttons
_top_button_overhang = 8 # px
_button_height = 26
_segmented_button_border_width = 3
_top_spacing: int = 10 # px on top of the buttons
_top_button_overhang: int = 8 # px
_button_height: int = 26
_segmented_button_border_width: int = 3
def __init__(self,
master: any = None,
master: any,
width: int = 300,
height: int = 250,
corner_radius: Union[int, str] = "default_theme",
border_width: Union[int, str] = "default_theme",
corner_radius: Optional[int] = None,
border_width: Optional[int] = None,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str], None] = "default_theme",
border_color: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Optional[Union[str, Tuple[str, str]]] = None,
segmented_button_fg_color: Union[str, Tuple[str, str], None] = "default_theme",
segmented_button_selected_color: Union[str, Tuple[str, str]] = "default_theme",
segmented_button_selected_hover_color: Union[str, Tuple[str, str]] = "default_theme",
segmented_button_unselected_color: Union[str, Tuple[str, str]] = "default_theme",
segmented_button_unselected_hover_color: Union[str, Tuple[str, str]] = "default_theme",
segmented_button_fg_color: Optional[Union[str, Tuple[str, str]]] = None,
segmented_button_selected_color: Optional[Union[str, Tuple[str, str]]] = None,
segmented_button_selected_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
segmented_button_unselected_color: Optional[Union[str, Tuple[str, str]]] = None,
segmented_button_unselected_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Union[str, Tuple[str, str]] = "default_theme",
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme",
text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
command: Callable = None,
command: Union[Callable, None] = None,
state: str = "normal",
**kwargs):
@ -47,10 +47,10 @@ class CTkTabview(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
# color
self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color == "default_theme" else border_color
self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color is None else self._check_color_type(border_color)
# determine fg_color of frame
if fg_color == "default_theme":
if fg_color is None:
if isinstance(self.master, (CTkFrame, CTkTabview)):
if self.master.cget("fg_color") == ThemeManager.theme["color"]["frame_low"]:
self._fg_color = ThemeManager.theme["color"]["frame_high"]
@ -59,11 +59,11 @@ class CTkTabview(CTkBaseClass):
else:
self._fg_color = ThemeManager.theme["color"]["frame_low"]
else:
self._fg_color = fg_color
self._fg_color = self._check_color_type(fg_color, transparency=True)
# shape
self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width == "default_theme" else border_width
self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius is None else corner_radius
self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width is None else border_width
self._canvas = CTkCanvas(master=self,
bg=self._apply_appearance_mode(self._bg_color),
@ -83,7 +83,7 @@ class CTkTabview(CTkBaseClass):
text_color=text_color,
text_color_disabled=text_color_disabled,
corner_radius=corner_radius,
border_width=self._apply_widget_scaling(self._segmented_button_border_width),
border_width=self._segmented_button_border_width,
command=self._segmented_button_callback,
state=state)
self._configure_segmented_button_background_corners()
@ -124,6 +124,7 @@ class CTkTabview(CTkBaseClass):
self._canvas.configure(width=self._apply_widget_scaling(self._desired_width),
height=self._apply_widget_scaling(self._desired_height - self._top_spacing - self._top_button_overhang))
self._configure_grid()
self._draw(no_color_updates=True)
def _set_dimensions(self, width=None, height=None):
@ -194,7 +195,7 @@ class CTkTabview(CTkBaseClass):
self._apply_widget_scaling(self._border_width))
if no_color_updates is False or requires_recoloring:
if self._fg_color is None:
if self._fg_color == "transparent":
self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._bg_color),
outline=self._apply_appearance_mode(self._bg_color))
@ -217,10 +218,10 @@ class CTkTabview(CTkBaseClass):
require_redraw = True
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True)
require_redraw = True
if "border_color" in kwargs:
self._border_color = kwargs.pop("border_color")
self._border_color = self._check_color_type(kwargs.pop("border_color"))
require_redraw = True
if "segmented_button_fg_color" in kwargs:
self._segmented_button.configure(fg_color=kwargs.pop("segmented_button_fg_color"))

View File

@ -1,5 +1,5 @@
import tkinter
from typing import Union, Tuple
from typing import Union, Tuple, Optional
from .core_rendering.ctk_canvas import CTkCanvas
from .ctk_scrollbar import CTkScrollbar
@ -33,21 +33,21 @@ class CTkTextbox(CTkBaseClass):
"xscrollcommand", "yscrollcommand"}
def __init__(self,
master: any = None,
master: any,
width: int = 200,
height: int = 200,
corner_radius: Union[int, str] = "default_theme",
border_width: Union[int, str] = "default_theme",
corner_radius: Optional[int] = None,
border_width: Optional[int] = None,
border_spacing: int = 3,
bg_color: Union[str, Tuple[str, str], None] = None,
fg_color: Union[str, Tuple[str, str], None] = "default_theme",
border_color: Union[str, Tuple[str, str]] = "default_theme",
text_color: Union[str, str] = "default_theme",
scrollbar_color: Union[str, Tuple[str, str]] = "default_theme",
scrollbar_hover_color: Union[str, Tuple[str, str]] = "default_theme",
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, str]] = None,
scrollbar_color: Optional[Union[str, Tuple[str, str]]] = None,
scrollbar_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
font: Union[tuple, CTkFont] = "default_theme",
font: Optional[Union[tuple, CTkFont]] = None,
activate_scrollbars: bool = True,
**kwargs):
@ -55,19 +55,19 @@ class CTkTextbox(CTkBaseClass):
super().__init__(master=master, bg_color=bg_color, width=width, height=height)
# color
self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color == "default_theme" else fg_color
self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color == "default_theme" else border_color
self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
self._scrollbar_color = ThemeManager.theme["color"]["scrollbar_button"] if scrollbar_color == "default_theme" else scrollbar_color
self._scrollbar_hover_color = ThemeManager.theme["color"]["scrollbar_button_hover"] if scrollbar_hover_color == "default_theme" else scrollbar_hover_color
self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color is None else self._check_color_type(fg_color, transparency=True)
self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color is None else self._check_color_type(border_color)
self._text_color = ThemeManager.theme["color"]["text"] if text_color is None else self._check_color_type(text_color)
self._scrollbar_color = ThemeManager.theme["color"]["scrollbar_button"] if scrollbar_color is None else self._check_color_type(scrollbar_color)
self._scrollbar_hover_color = ThemeManager.theme["color"]["scrollbar_button_hover"] if scrollbar_hover_color is None else self._check_color_type(scrollbar_hover_color)
# shape
self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius
self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width == "default_theme" else border_width
self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius is None else corner_radius
self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width is None else border_width
self._border_spacing = border_spacing
# font
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
self._font = CTkFont() if font is None else self._check_font_type(font)
if isinstance(self._font, CTkFont):
self._font.add_size_configure_callback(self._update_font)
@ -221,7 +221,7 @@ class CTkTextbox(CTkBaseClass):
self._apply_widget_scaling(self._border_width))
if no_color_updates is False or requires_recoloring:
if self._fg_color is None:
if self._fg_color == "transparent":
self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._bg_color),
outline=self._apply_appearance_mode(self._bg_color))
@ -254,7 +254,7 @@ class CTkTextbox(CTkBaseClass):
def configure(self, require_redraw=False, **kwargs):
if "fg_color" in kwargs:
self._fg_color = kwargs.pop("fg_color")
self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True)
require_redraw = True
# check if CTk widgets are children of the frame and change their _bg_color to new frame fg_color
@ -263,13 +263,23 @@ class CTkTextbox(CTkBaseClass):
child.configure(bg_color=self._fg_color)
if "border_color" in kwargs:
self._border_color = kwargs.pop("border_color")
self._border_color = self._check_color_type(kwargs.pop("border_color"))
require_redraw = True
if "text_color" in kwargs:
self._text_color = kwargs.pop("text_color")
self._text_color = self._check_color_type(kwargs.pop("text_color"))
require_redraw = True
if "scrollbar_color" in kwargs:
self._scrollbar_color = self._check_color_type(kwargs.pop("scrollbar_color"))
self._x_scrollbar.configure(scrollbar_color=self._scrollbar_color)
self._y_scrollbar.configure(scrollbar_color=self._scrollbar_color)
if "scrollbar_hover_color" in kwargs:
self._scrollbar_hover_color = self._check_color_type(kwargs.pop("scrollbar_hover_color"))
self._x_scrollbar.configure(scrollbar_hover_color=self._scrollbar_hover_color)
self._y_scrollbar.configure(scrollbar_hover_color=self._scrollbar_hover_color)
if "corner_radius" in kwargs:
self._corner_radius = kwargs.pop("corner_radius")
self._create_grid_for_text_and_scrollbars(re_grid_textbox=True, re_grid_x_scrollbar=True, re_grid_y_scrollbar=True)

View File

@ -21,8 +21,8 @@ class CTkFont(Font):
"""
def __init__(self,
family: str = "default_theme",
size: int = "default_theme",
family: str = "default",
size: int = "default",
weight: str = "normal",
slant: str = "roman",
underline: bool = False,
@ -31,10 +31,10 @@ class CTkFont(Font):
self._size_configure_callback_list: List[Callable] = []
self._family = family
self._size = ThemeManager.theme["text"]["size"] if size == "default_theme" else size
self._size = ThemeManager.theme["text"]["size"] if size == "default" else size
self._tuple_style_string = f"{weight} {slant} {'underline' if underline else ''} {'overstrike' if overstrike else ''}"
super().__init__(family=ThemeManager.theme["text"]["font"] if family == "default_theme" else family,
super().__init__(family=ThemeManager.theme["text"]["font"] if family == "default" else family,
size=-abs(self._size),
weight=weight,
slant=slant,

View File

@ -1,4 +1,3 @@
import tkinter
from typing import Union, Tuple
import copy
import re
@ -9,7 +8,6 @@ except ImportError:
from .scaling_tracker import ScalingTracker
from ..font.ctk_font import CTkFont
from ..image.ctk_image import CTkImage
class CTkScalingBaseClass():

View File

@ -47,7 +47,7 @@ class App(customtkinter.CTk):
self.entry = customtkinter.CTkEntry(self, placeholder_text="CTkEntry")
self.entry.grid(row=3, column=1, columnspan=2, padx=(20, 0), pady=(20, 20), sticky="nsew")
self.main_button_1 = customtkinter.CTkButton(master=self, fg_color=None, border_width=2)
self.main_button_1 = customtkinter.CTkButton(master=self, fg_color="transparent", border_width=2)
self.main_button_1.grid(row=3, column=3, padx=(20, 20), pady=(20, 20), sticky="nsew")
# create textbox
@ -101,7 +101,7 @@ class App(customtkinter.CTk):
self.switch_2.grid(row=4, column=0, pady=(10, 20), padx=20, sticky="n")
# create slider and progressbar frame
self.slider_progressbar_frame = customtkinter.CTkFrame(self, fg_color=None)
self.slider_progressbar_frame = customtkinter.CTkFrame(self, fg_color="transparent")
self.slider_progressbar_frame.grid(row=1, column=1, columnspan=2, padx=(20, 0), pady=(20, 0), sticky="nsew")
self.slider_progressbar_frame.grid_columnconfigure(0, weight=1)
self.slider_progressbar_frame.grid_rowconfigure(4, weight=1)