20 Commits

Author SHA1 Message Date
359226e468 Bump to 5.0.4 2023-01-21 13:43:54 +01:00
dc751e46d3 add example images 2023-01-21 13:43:18 +01:00
79d5da439b fix readonly background for combobox #983 2023-01-10 15:03:45 +01:00
fac2fa5e68 Merge remote-tracking branch 'origin/master' 2023-01-07 18:37:22 +01:00
2de1b94575 fixed dropdown_fg_color attribute in configure of CTkOptionMenu 2023-01-07 18:37:00 +01:00
a79502dc03 replaced sys.stderr with warnings.warn #932 2023-01-07 01:21:28 +01:00
8a537076ce added icon on Windows for CTkToplevel, fixed #960 2023-01-07 01:16:15 +01:00
1396a7e484 fixed #925 2022-12-25 21:03:33 +01:00
5bbd72b5dc fixed #941 2022-12-25 20:54:40 +01:00
84bfc776b0 Merge remote-tracking branch 'origin/master' 2022-12-10 13:40:29 +01:00
7f5ac69259 Bump to 5.0.3 2022-12-10 13:40:06 +01:00
90157252d0 added icons folder to MANIFEST.in 2022-12-10 13:39:33 +01:00
392586eaa1 removed macOS icon change 2022-12-10 13:38:27 +01:00
f3710de173 changed windows icon 2022-12-10 13:29:35 +01:00
9f8b54563d add icons 2022-12-10 13:17:55 +01:00
28228316eb fix image configure for button #807 2022-12-08 19:33:39 +01:00
61adb1da07 fix readme 2022-12-08 10:35:11 +01:00
042fac7242 fix image type hints #795 2022-12-08 10:34:41 +01:00
a49dde63b3 fix switch #801 2022-12-07 22:15:31 +01:00
f11d727879 fix combobox #800 2022-12-07 22:10:35 +01:00
29 changed files with 70 additions and 28 deletions

View File

@ -1,4 +1,5 @@
include customtkinter/assets/* include customtkinter/assets/*
include customtkinter/assets/fonts/* include customtkinter/assets/fonts/*
include customtkinter/assets/fonts/Roboto/* include customtkinter/assets/fonts/Roboto/*
include customtkinter/assets/themes/* include customtkinter/assets/icons/*
include customtkinter/assets/themes/*

View File

@ -12,7 +12,6 @@
![Downloads](https://static.pepy.tech/personalized-badge/customtkinter?period=total&units=international_system&left_color=grey&right_color=green&left_text=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) ![PyPI - License](https://img.shields.io/pypi/l/customtkinter)
![](https://tokei.rs/b1/github/tomschimansky/customtkinter) ![](https://tokei.rs/b1/github/tomschimansky/customtkinter)
![Total lines](https://img.shields.io/tokei/lines/github.com/tomschimansky/customtkinter?color=green&label=total%20lines)
</div> </div>

View File

@ -1,4 +1,4 @@
__version__ = "5.0.2" __version__ = "5.0.4"
import os import os
import sys import sys
@ -78,4 +78,4 @@ def set_window_scaling(scaling_value: float):
def deactivate_automatic_dpi_awareness(): def deactivate_automatic_dpi_awareness():
""" deactivate DPI awareness of current process (windll.shcore.SetProcessDpiAwareness(0)) """ """ deactivate DPI awareness of current process (windll.shcore.SetProcessDpiAwareness(0)) """
ScalingTracker.deactivate_automatic_dpi_awareness = False ScalingTracker.deactivate_automatic_dpi_awareness = True

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -40,6 +40,14 @@ class CTk(tkinter.Tk, CTkAppearanceModeBaseClass, CTkScalingBaseClass):
CTkScalingBaseClass.__init__(self, scaling_type="window") CTkScalingBaseClass.__init__(self, scaling_type="window")
check_kwargs_empty(kwargs, raise_error=True) check_kwargs_empty(kwargs, raise_error=True)
try:
# Set Windows titlebar icon
if sys.platform.startswith("win"):
customtkinter_directory = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
self.after(200, lambda: self.iconbitmap(os.path.join(customtkinter_directory, "assets", "icons", "CustomTkinter_icon_Windows.ico")))
except Exception:
pass
self._current_width = 600 # initial window size, independent of scaling self._current_width = 600 # initial window size, independent of scaling
self._current_height = 500 self._current_height = 500
self._min_width: int = 0 self._min_width: int = 0

View File

@ -38,6 +38,14 @@ class CTkToplevel(tkinter.Toplevel, CTkAppearanceModeBaseClass, CTkScalingBaseCl
CTkScalingBaseClass.__init__(self, scaling_type="window") CTkScalingBaseClass.__init__(self, scaling_type="window")
check_kwargs_empty(kwargs, raise_error=True) check_kwargs_empty(kwargs, raise_error=True)
try:
# Set Windows titlebar icon
if sys.platform.startswith("win"):
customtkinter_directory = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
self.after(200, lambda: self.iconbitmap(os.path.join(customtkinter_directory, "assets", "icons", "CustomTkinter_icon_Windows.ico")))
except Exception:
pass
self._current_width = 200 # initial window size, always without scaling self._current_width = 200 # initial window size, always without scaling
self._current_height = 200 self._current_height = 200
self._min_width: int = 0 self._min_width: int = 0

View File

@ -1,4 +1,5 @@
import sys import sys
import warnings
import tkinter import tkinter
import tkinter.ttk as ttk import tkinter.ttk as ttk
from typing import Union, Callable, Tuple from typing import Union, Callable, Tuple
@ -158,7 +159,7 @@ class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClas
return font return font
elif type(font) == tuple and len(font) == 1: elif type(font) == tuple and len(font) == 1:
sys.stderr.write(f"{type(self).__name__} Warning: font {font} given without size, will be extended with default text size of current theme\n") warnings.warn(f"{type(self).__name__} Warning: font {font} given without size, will be extended with default text size of current theme\n")
return font[0], ThemeManager.theme["text"]["size"] return font[0], ThemeManager.theme["text"]["size"]
elif type(font) == tuple and 2 <= len(font) <= 6: elif type(font) == tuple and 2 <= len(font) <= 6:
@ -178,8 +179,8 @@ class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClas
elif isinstance(image, CTkImage): elif isinstance(image, CTkImage):
return image return image
else: else:
sys.stderr.write(f"{type(self).__name__} Warning: Given image is not CTkImage but {type(image)}. " + warnings.warn(f"{type(self).__name__} Warning: Given image is not CTkImage but {type(image)}. " +
f"Image can not be scaled on HighDPI displays, use CTkImage instead.\n") f"Image can not be scaled on HighDPI displays, use CTkImage instead.\n")
return image return image
def _update_dimensions_event(self, event): def _update_dimensions_event(self, event):

View File

@ -40,7 +40,7 @@ class CTkButton(CTkBaseClass):
text: str = "CTkButton", text: str = "CTkButton",
font: Optional[Union[tuple, CTkFont]] = None, font: Optional[Union[tuple, CTkFont]] = None,
textvariable: Union[tkinter.Variable, None] = None, textvariable: Union[tkinter.Variable, None] = None,
image: Union[tkinter.PhotoImage, CTkImage, None] = None, image: Union[CTkImage, None] = None,
state: str = "normal", state: str = "normal",
hover: bool = True, hover: bool = True,
command: Union[Callable[[], None], None] = None, command: Union[Callable[[], None], None] = None,
@ -107,13 +107,31 @@ class CTkButton(CTkBaseClass):
def _create_bindings(self, sequence: Optional[str] = None): def _create_bindings(self, sequence: Optional[str] = None):
""" set necessary bindings for functionality of widget, will overwrite other bindings """ """ set necessary bindings for functionality of widget, will overwrite other bindings """
if sequence is None or sequence == "<Enter>": if sequence is None or sequence == "<Enter>":
self._canvas.bind("<Enter>", self._on_enter) self._canvas.bind("<Enter>", self._on_enter)
if self._text_label is not None:
self._text_label.bind("<Enter>", self._on_enter)
if self._image_label is not None:
self._image_label.bind("<Enter>", self._on_enter)
if sequence is None or sequence == "<Leave>": if sequence is None or sequence == "<Leave>":
self._canvas.bind("<Leave>", self._on_leave) self._canvas.bind("<Leave>", self._on_leave)
if self._text_label is not None:
self._text_label.bind("<Leave>", self._on_leave)
if self._image_label is not None:
self._image_label.bind("<Leave>", self._on_leave)
if sequence is None or sequence == "<Button-1>": if sequence is None or sequence == "<Button-1>":
self._canvas.bind("<Button-1>", self._clicked) self._canvas.bind("<Button-1>", self._clicked)
if self._text_label is not None:
self._text_label.bind("<Button-1>", self._clicked)
if self._image_label is not None:
self._image_label.bind("<Button-1>", self._clicked)
def _set_scaling(self, *args, **kwargs): def _set_scaling(self, *args, **kwargs):
super()._set_scaling(*args, **kwargs) super()._set_scaling(*args, **kwargs)
@ -395,7 +413,7 @@ class CTkButton(CTkBaseClass):
self._image = self._check_image_type(kwargs.pop("image")) self._image = self._check_image_type(kwargs.pop("image"))
if isinstance(self._image, CTkImage): if isinstance(self._image, CTkImage):
self._image.add_configure_callback(self._update_image) self._image.add_configure_callback(self._update_image)
require_redraw = True self._update_image()
if "state" in kwargs: if "state" in kwargs:
self._state = kwargs.pop("state") self._state = kwargs.pop("state")
@ -541,7 +559,11 @@ class CTkButton(CTkBaseClass):
if not (add == "+" or add is True): if not (add == "+" or add is True):
raise ValueError("'add' argument can only be '+' or True to preserve internal callbacks") raise ValueError("'add' argument can only be '+' or True to preserve internal callbacks")
self._canvas.bind(sequence, command, add=True) self._canvas.bind(sequence, command, add=True)
self._text_label.bind(sequence, command, add=True)
if self._text_label is not None:
self._text_label.bind(sequence, command, add=True)
if self._image_label is not None:
self._image_label.bind(sequence, command, add=True)
def unbind(self, sequence: str = None, funcid: str = None): def unbind(self, sequence: str = None, funcid: str = None):
""" called on the tkinter.Label and tkinter.Canvas """ """ called on the tkinter.Label and tkinter.Canvas """
@ -549,7 +571,12 @@ class CTkButton(CTkBaseClass):
raise ValueError("'funcid' argument can only be None, because there is a bug in" + raise ValueError("'funcid' argument can only be None, because there is a bug in" +
" tkinter and its not clear whether the internal callbacks will be unbinded or not") " tkinter and its not clear whether the internal callbacks will be unbinded or not")
self._canvas.unbind(sequence, None) self._canvas.unbind(sequence, None)
self._text_label.unbind(sequence, None)
if self._text_label is not None:
self._text_label.unbind(sequence, None)
if self._image_label is not None:
self._image_label.unbind(sequence, None)
self._create_bindings(sequence=sequence) # restore internal callbacks for sequence self._create_bindings(sequence=sequence) # restore internal callbacks for sequence
def focus(self): def focus(self):

View File

@ -110,10 +110,11 @@ class CTkComboBox(CTkBaseClass):
self._entry.configure(textvariable=self._variable) self._entry.configure(textvariable=self._variable)
# insert default value # insert default value
if len(self._values) > 0: if self._variable is None:
self._entry.insert(0, self._values[0]) if len(self._values) > 0:
else: self._entry.insert(0, self._values[0])
self._entry.insert(0, "CTkComboBox") else:
self._entry.insert(0, "CTkComboBox")
def _create_bindings(self, sequence: Optional[str] = None): def _create_bindings(self, sequence: Optional[str] = None):
""" set necessary bindings for functionality of widget, will overwrite other bindings """ """ set necessary bindings for functionality of widget, will overwrite other bindings """
@ -200,6 +201,7 @@ class CTkComboBox(CTkBaseClass):
self._entry.configure(bg=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), fg=self._apply_appearance_mode(self._text_color),
readonlybackground=self._apply_appearance_mode(self._fg_color),
disabledbackground=self._apply_appearance_mode(self._fg_color), disabledbackground=self._apply_appearance_mode(self._fg_color),
disabledforeground=self._apply_appearance_mode(self._text_color_disabled), disabledforeground=self._apply_appearance_mode(self._text_color_disabled),
highlightcolor=self._apply_appearance_mode(self._fg_color), highlightcolor=self._apply_appearance_mode(self._fg_color),

View File

@ -32,7 +32,7 @@ class CTkLabel(CTkBaseClass):
text: str = "CTkLabel", text: str = "CTkLabel",
font: Optional[Union[tuple, CTkFont]] = None, font: Optional[Union[tuple, CTkFont]] = None,
image: Union[tkinter.PhotoImage, CTkImage, None] = None, image: Union[CTkImage, None] = None,
compound: str = "center", compound: str = "center",
anchor: str = "center", # label anchor: center, n, e, s, w anchor: str = "center", # label anchor: center, n, e, s, w
wraplength: int = 0, wraplength: int = 0,

View File

@ -243,8 +243,8 @@ class CTkOptionMenu(CTkBaseClass):
self._text_color = self._check_color_type(kwargs.pop("text_color")) self._text_color = self._check_color_type(kwargs.pop("text_color"))
require_redraw = True require_redraw = True
if "dropdown_color" in kwargs: if "dropdown_fg_color" in kwargs:
self._dropdown_menu.configure(fg_color=kwargs.pop("dropdown_color")) self._dropdown_menu.configure(fg_color=kwargs.pop("dropdown_fg_color"))
if "dropdown_hover_color" in kwargs: if "dropdown_hover_color" in kwargs:
self._dropdown_menu.configure(hover_color=kwargs.pop("dropdown_hover_color")) self._dropdown_menu.configure(hover_color=kwargs.pop("dropdown_hover_color"))

View File

@ -119,7 +119,7 @@ class CTkSwitch(CTkBaseClass):
if self._variable is not None and self._variable != "": if self._variable is not None and self._variable != "":
self._variable_callback_name = self._variable.trace_add("write", self._variable_callback) self._variable_callback_name = self._variable.trace_add("write", self._variable_callback)
self.c_heck_state = True if self._variable.get() == self._onvalue else False self._check_state = True if self._variable.get() == self._onvalue else False
self._create_bindings() self._create_bindings()
self._set_cursor() self._set_cursor()

View File

@ -1,5 +1,3 @@
import tkinter
import customtkinter import customtkinter
import os import os
from PIL import Image from PIL import Image

View File

@ -1,4 +1,3 @@
import tkinter
import customtkinter import customtkinter
customtkinter.set_appearance_mode("dark") # Modes: "System" (standard), "Dark", "Light" customtkinter.set_appearance_mode("dark") # Modes: "System" (standard), "Dark", "Light"
@ -8,7 +7,6 @@ app = customtkinter.CTk()
app.geometry("400x780") app.geometry("400x780")
app.title("CustomTkinter simple_example.py") app.title("CustomTkinter simple_example.py")
def button_callback(): def button_callback():
print("Button click", combobox_1.get()) print("Button click", combobox_1.get())
@ -20,7 +18,7 @@ def slider_callback(value):
frame_1 = customtkinter.CTkFrame(master=app) frame_1 = customtkinter.CTkFrame(master=app)
frame_1.pack(pady=20, padx=60, fill="both", expand=True) frame_1.pack(pady=20, padx=60, fill="both", expand=True)
label_1 = customtkinter.CTkLabel(master=frame_1, justify=tkinter.LEFT) label_1 = customtkinter.CTkLabel(master=frame_1, justify=customtkinter.LEFT)
label_1.pack(pady=10, padx=10) label_1.pack(pady=10, padx=10)
progressbar_1 = customtkinter.CTkProgressBar(master=frame_1) progressbar_1 = customtkinter.CTkProgressBar(master=frame_1)
@ -42,12 +40,12 @@ optionmenu_1.set("CTkOptionMenu")
combobox_1 = customtkinter.CTkComboBox(frame_1, values=["Option 1", "Option 2", "Option 42 long long long..."]) combobox_1 = customtkinter.CTkComboBox(frame_1, values=["Option 1", "Option 2", "Option 42 long long long..."])
combobox_1.pack(pady=10, padx=10) combobox_1.pack(pady=10, padx=10)
optionmenu_1.set("CTkComboBox") combobox_1.set("CTkComboBox")
checkbox_1 = customtkinter.CTkCheckBox(master=frame_1) checkbox_1 = customtkinter.CTkCheckBox(master=frame_1)
checkbox_1.pack(pady=10, padx=10) checkbox_1.pack(pady=10, padx=10)
radiobutton_var = tkinter.IntVar(value=1) radiobutton_var = customtkinter.IntVar(value=1)
radiobutton_1 = customtkinter.CTkRadioButton(master=frame_1, variable=radiobutton_var, value=1) radiobutton_1 = customtkinter.CTkRadioButton(master=frame_1, variable=radiobutton_var, value=1)
radiobutton_1.pack(pady=10, padx=10) radiobutton_1.pack(pady=10, padx=10)

View File

@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
github_url = "https://github.com/TomSchimansky/CustomTkinter" github_url = "https://github.com/TomSchimansky/CustomTkinter"
[tool.tbump.version] [tool.tbump.version]
current = "5.0.2" current = "5.0.4"
# Example of a semver regexp. # Example of a semver regexp.
# Make sure this matches current_version before # Make sure this matches current_version before

View File

@ -1,6 +1,6 @@
[metadata] [metadata]
name = customtkinter name = customtkinter
version = 5.0.2 version = 5.0.4
description = Create modern looking GUIs with Python description = Create modern looking GUIs with Python
long_description = A modern and customizable python UI-library based on Tkinter: https://github.com/TomSchimansky/CustomTkinter long_description = A modern and customizable python UI-library based on Tkinter: https://github.com/TomSchimansky/CustomTkinter
long_description_content_type = text/markdown long_description_content_type = text/markdown

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB