Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
359226e468 | |||
dc751e46d3 | |||
79d5da439b | |||
fac2fa5e68 | |||
2de1b94575 | |||
a79502dc03 | |||
8a537076ce | |||
1396a7e484 | |||
5bbd72b5dc | |||
84bfc776b0 | |||
7f5ac69259 | |||
90157252d0 | |||
392586eaa1 | |||
f3710de173 | |||
9f8b54563d | |||
28228316eb | |||
61adb1da07 | |||
042fac7242 | |||
a49dde63b3 | |||
f11d727879 |
@ -1,4 +1,5 @@
|
||||
include customtkinter/assets/*
|
||||
include customtkinter/assets/fonts/*
|
||||
include customtkinter/assets/fonts/Roboto/*
|
||||
include customtkinter/assets/themes/*
|
||||
include customtkinter/assets/icons/*
|
||||
include customtkinter/assets/themes/*
|
||||
|
@ -12,7 +12,6 @@
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
__version__ = "5.0.2"
|
||||
__version__ = "5.0.4"
|
||||
|
||||
import os
|
||||
import sys
|
||||
@ -78,4 +78,4 @@ def set_window_scaling(scaling_value: float):
|
||||
|
||||
def deactivate_automatic_dpi_awareness():
|
||||
""" deactivate DPI awareness of current process (windll.shcore.SetProcessDpiAwareness(0)) """
|
||||
ScalingTracker.deactivate_automatic_dpi_awareness = False
|
||||
ScalingTracker.deactivate_automatic_dpi_awareness = True
|
||||
|
BIN
customtkinter/assets/icons/CustomTkinter_icon_Windows.ico
Normal file
After Width: | Height: | Size: 13 KiB |
@ -40,6 +40,14 @@ class CTk(tkinter.Tk, CTkAppearanceModeBaseClass, CTkScalingBaseClass):
|
||||
CTkScalingBaseClass.__init__(self, scaling_type="window")
|
||||
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_height = 500
|
||||
self._min_width: int = 0
|
||||
|
@ -38,6 +38,14 @@ class CTkToplevel(tkinter.Toplevel, CTkAppearanceModeBaseClass, CTkScalingBaseCl
|
||||
CTkScalingBaseClass.__init__(self, scaling_type="window")
|
||||
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_height = 200
|
||||
self._min_width: int = 0
|
||||
|
@ -1,4 +1,5 @@
|
||||
import sys
|
||||
import warnings
|
||||
import tkinter
|
||||
import tkinter.ttk as ttk
|
||||
from typing import Union, Callable, Tuple
|
||||
@ -158,7 +159,7 @@ class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClas
|
||||
return font
|
||||
|
||||
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"]
|
||||
|
||||
elif type(font) == tuple and 2 <= len(font) <= 6:
|
||||
@ -178,8 +179,8 @@ class CTkBaseClass(tkinter.Frame, CTkAppearanceModeBaseClass, CTkScalingBaseClas
|
||||
elif isinstance(image, CTkImage):
|
||||
return image
|
||||
else:
|
||||
sys.stderr.write(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")
|
||||
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")
|
||||
return image
|
||||
|
||||
def _update_dimensions_event(self, event):
|
||||
|
@ -40,7 +40,7 @@ class CTkButton(CTkBaseClass):
|
||||
text: str = "CTkButton",
|
||||
font: Optional[Union[tuple, CTkFont]] = None,
|
||||
textvariable: Union[tkinter.Variable, None] = None,
|
||||
image: Union[tkinter.PhotoImage, CTkImage, None] = None,
|
||||
image: Union[CTkImage, None] = None,
|
||||
state: str = "normal",
|
||||
hover: bool = True,
|
||||
command: Union[Callable[[], None], None] = None,
|
||||
@ -107,13 +107,31 @@ class CTkButton(CTkBaseClass):
|
||||
|
||||
def _create_bindings(self, sequence: Optional[str] = None):
|
||||
""" set necessary bindings for functionality of widget, will overwrite other bindings """
|
||||
|
||||
if sequence is None or sequence == "<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>":
|
||||
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>":
|
||||
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):
|
||||
super()._set_scaling(*args, **kwargs)
|
||||
|
||||
@ -395,7 +413,7 @@ class CTkButton(CTkBaseClass):
|
||||
self._image = self._check_image_type(kwargs.pop("image"))
|
||||
if isinstance(self._image, CTkImage):
|
||||
self._image.add_configure_callback(self._update_image)
|
||||
require_redraw = True
|
||||
self._update_image()
|
||||
|
||||
if "state" in kwargs:
|
||||
self._state = kwargs.pop("state")
|
||||
@ -541,7 +559,11 @@ class CTkButton(CTkBaseClass):
|
||||
if not (add == "+" or add is True):
|
||||
raise ValueError("'add' argument can only be '+' or True to preserve internal callbacks")
|
||||
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):
|
||||
""" 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" +
|
||||
" tkinter and its not clear whether the internal callbacks will be unbinded or not")
|
||||
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
|
||||
|
||||
def focus(self):
|
||||
|
@ -110,10 +110,11 @@ class CTkComboBox(CTkBaseClass):
|
||||
self._entry.configure(textvariable=self._variable)
|
||||
|
||||
# insert default value
|
||||
if len(self._values) > 0:
|
||||
self._entry.insert(0, self._values[0])
|
||||
else:
|
||||
self._entry.insert(0, "CTkComboBox")
|
||||
if self._variable is None:
|
||||
if len(self._values) > 0:
|
||||
self._entry.insert(0, self._values[0])
|
||||
else:
|
||||
self._entry.insert(0, "CTkComboBox")
|
||||
|
||||
def _create_bindings(self, sequence: Optional[str] = None):
|
||||
""" 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),
|
||||
fg=self._apply_appearance_mode(self._text_color),
|
||||
readonlybackground=self._apply_appearance_mode(self._fg_color),
|
||||
disabledbackground=self._apply_appearance_mode(self._fg_color),
|
||||
disabledforeground=self._apply_appearance_mode(self._text_color_disabled),
|
||||
highlightcolor=self._apply_appearance_mode(self._fg_color),
|
||||
|
@ -32,7 +32,7 @@ class CTkLabel(CTkBaseClass):
|
||||
|
||||
text: str = "CTkLabel",
|
||||
font: Optional[Union[tuple, CTkFont]] = None,
|
||||
image: Union[tkinter.PhotoImage, CTkImage, None] = None,
|
||||
image: Union[CTkImage, None] = None,
|
||||
compound: str = "center",
|
||||
anchor: str = "center", # label anchor: center, n, e, s, w
|
||||
wraplength: int = 0,
|
||||
|
@ -243,8 +243,8 @@ class CTkOptionMenu(CTkBaseClass):
|
||||
self._text_color = self._check_color_type(kwargs.pop("text_color"))
|
||||
require_redraw = True
|
||||
|
||||
if "dropdown_color" in kwargs:
|
||||
self._dropdown_menu.configure(fg_color=kwargs.pop("dropdown_color"))
|
||||
if "dropdown_fg_color" in kwargs:
|
||||
self._dropdown_menu.configure(fg_color=kwargs.pop("dropdown_fg_color"))
|
||||
|
||||
if "dropdown_hover_color" in kwargs:
|
||||
self._dropdown_menu.configure(hover_color=kwargs.pop("dropdown_hover_color"))
|
||||
|
@ -119,7 +119,7 @@ class CTkSwitch(CTkBaseClass):
|
||||
|
||||
if self._variable is not None and self._variable != "":
|
||||
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._set_cursor()
|
||||
|
@ -1,5 +1,3 @@
|
||||
import tkinter
|
||||
|
||||
import customtkinter
|
||||
import os
|
||||
from PIL import Image
|
||||
|
@ -1,4 +1,3 @@
|
||||
import tkinter
|
||||
import customtkinter
|
||||
|
||||
customtkinter.set_appearance_mode("dark") # Modes: "System" (standard), "Dark", "Light"
|
||||
@ -8,7 +7,6 @@ app = customtkinter.CTk()
|
||||
app.geometry("400x780")
|
||||
app.title("CustomTkinter simple_example.py")
|
||||
|
||||
|
||||
def button_callback():
|
||||
print("Button click", combobox_1.get())
|
||||
|
||||
@ -20,7 +18,7 @@ def slider_callback(value):
|
||||
frame_1 = customtkinter.CTkFrame(master=app)
|
||||
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)
|
||||
|
||||
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.pack(pady=10, padx=10)
|
||||
optionmenu_1.set("CTkComboBox")
|
||||
combobox_1.set("CTkComboBox")
|
||||
|
||||
checkbox_1 = customtkinter.CTkCheckBox(master=frame_1)
|
||||
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.pack(pady=10, padx=10)
|
||||
|
@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
||||
github_url = "https://github.com/TomSchimansky/CustomTkinter"
|
||||
|
||||
[tool.tbump.version]
|
||||
current = "5.0.2"
|
||||
current = "5.0.4"
|
||||
|
||||
# Example of a semver regexp.
|
||||
# Make sure this matches current_version before
|
||||
|
@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
name = customtkinter
|
||||
version = 5.0.2
|
||||
version = 5.0.4
|
||||
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_content_type = text/markdown
|
||||
|
After Width: | Height: | Size: 198 KiB |
Before Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 4.8 KiB |
BIN
test/manual_integration_tests/test_images/add_user_dark.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
test/manual_integration_tests/test_images/add_user_light.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 10 KiB |
BIN
test/manual_integration_tests/test_images/chat_dark.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
test/manual_integration_tests/test_images/chat_light.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
test/manual_integration_tests/test_images/home_dark.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
test/manual_integration_tests/test_images/home_light.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
test/manual_integration_tests/test_images/image_icon_light.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
test/manual_integration_tests/test_images/large_test_image.png
Normal file
After Width: | Height: | Size: 3.3 MiB |
Before Width: | Height: | Size: 18 KiB |