mirror of
https://github.com/TomSchimansky/CustomTkinter.git
synced 2023-08-10 21:13:13 +03:00
added CTkImage, compound support for label
This commit is contained in:
parent
7374e7a3bc
commit
62b330ddba
@ -6,8 +6,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
ToDo:
|
ToDo:
|
||||||
- complete other theme files
|
- complete other theme files
|
||||||
- auto-scaling of images
|
|
||||||
- image tuple for light/dark mode
|
|
||||||
- change font attribute in wiki
|
- change font attribute in wiki
|
||||||
- add new button attributes to wiki
|
- add new button attributes to wiki
|
||||||
- cursor configuring
|
- cursor configuring
|
||||||
|
@ -6,6 +6,7 @@ from .theme.theme_manager import ThemeManager
|
|||||||
from .core_rendering.draw_engine import DrawEngine
|
from .core_rendering.draw_engine import DrawEngine
|
||||||
from .core_widget_classes.widget_base_class import CTkBaseClass
|
from .core_widget_classes.widget_base_class import CTkBaseClass
|
||||||
from .font.ctk_font import CTkFont
|
from .font.ctk_font import CTkFont
|
||||||
|
from .image.ctk_image import CTkImage
|
||||||
|
|
||||||
from customtkinter.utility.utility_functions import pop_from_dict_by_set, check_kwargs_empty
|
from customtkinter.utility.utility_functions import pop_from_dict_by_set, check_kwargs_empty
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ class CTkLabel(CTkBaseClass):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# attributes that are passed to and managed by the tkinter entry only:
|
# attributes that are passed to and managed by the tkinter entry only:
|
||||||
_valid_tk_label_attributes = {"compound", "cursor", "image", "justify", "padx", "pady",
|
_valid_tk_label_attributes = {"cursor", "justify", "padx", "pady",
|
||||||
"textvariable", "state", "takefocus", "underline", "wraplength"}
|
"textvariable", "state", "takefocus", "underline", "wraplength"}
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
@ -32,6 +33,8 @@ class CTkLabel(CTkBaseClass):
|
|||||||
|
|
||||||
text: str = "CTkLabel",
|
text: str = "CTkLabel",
|
||||||
font: Union[tuple, CTkFont] = "default_theme",
|
font: Union[tuple, CTkFont] = "default_theme",
|
||||||
|
image: Union[tkinter.PhotoImage, CTkImage] = None,
|
||||||
|
compound: str = "center",
|
||||||
anchor: str = "center", # label anchor: center, n, e, s, w
|
anchor: str = "center", # label anchor: center, n, e, s, w
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
|
||||||
@ -49,6 +52,12 @@ class CTkLabel(CTkBaseClass):
|
|||||||
self._anchor = anchor
|
self._anchor = anchor
|
||||||
self._text = text
|
self._text = text
|
||||||
|
|
||||||
|
# image
|
||||||
|
self._image = image
|
||||||
|
self._compound = compound
|
||||||
|
if isinstance(self._image, CTkImage):
|
||||||
|
self._image.add_configure_callback(self._update_image)
|
||||||
|
|
||||||
# font
|
# font
|
||||||
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
|
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
|
||||||
if isinstance(self._font, CTkFont):
|
if isinstance(self._font, CTkFont):
|
||||||
@ -65,33 +74,35 @@ class CTkLabel(CTkBaseClass):
|
|||||||
self._canvas.grid(row=0, column=0, sticky="nswe")
|
self._canvas.grid(row=0, column=0, sticky="nswe")
|
||||||
self._draw_engine = DrawEngine(self._canvas)
|
self._draw_engine = DrawEngine(self._canvas)
|
||||||
|
|
||||||
self._text_label = tkinter.Label(master=self,
|
self._label = tkinter.Label(master=self,
|
||||||
highlightthickness=0,
|
highlightthickness=0,
|
||||||
padx=0,
|
padx=0,
|
||||||
pady=0,
|
pady=0,
|
||||||
borderwidth=1,
|
borderwidth=0,
|
||||||
anchor=self._anchor,
|
anchor=self._anchor,
|
||||||
text=self._text,
|
compound=self._compound,
|
||||||
font=self._apply_font_scaling(self._font))
|
text=self._text,
|
||||||
self._text_label.configure(**pop_from_dict_by_set(kwargs, self._valid_tk_label_attributes))
|
font=self._apply_font_scaling(self._font))
|
||||||
|
self._label.configure(**pop_from_dict_by_set(kwargs, self._valid_tk_label_attributes))
|
||||||
|
|
||||||
text_label_grid_sticky = self._anchor if self._anchor != "center" else ""
|
text_label_grid_sticky = self._anchor if self._anchor != "center" else ""
|
||||||
self._text_label.grid(row=0, column=0, sticky=text_label_grid_sticky,
|
self._label.grid(row=0, column=0, sticky=text_label_grid_sticky,
|
||||||
padx=self._apply_widget_scaling(min(self._corner_radius, round(self._current_height/2))))
|
padx=self._apply_widget_scaling(min(self._corner_radius, round(self._current_height/2))))
|
||||||
|
|
||||||
check_kwargs_empty(kwargs, raise_error=True)
|
check_kwargs_empty(kwargs, raise_error=True)
|
||||||
|
|
||||||
|
self._update_image()
|
||||||
self._draw()
|
self._draw()
|
||||||
|
|
||||||
def _set_scaling(self, *args, **kwargs):
|
def _set_scaling(self, *args, **kwargs):
|
||||||
super()._set_scaling(*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._text_label.configure(font=self._apply_font_scaling(self._font))
|
self._label.configure(font=self._apply_font_scaling(self._font))
|
||||||
|
|
||||||
text_label_grid_sticky = self._anchor if self._anchor != "center" else ""
|
text_label_grid_sticky = self._anchor if self._anchor != "center" else ""
|
||||||
self._text_label.grid(row=0, column=0, sticky=text_label_grid_sticky,
|
self._label.grid(row=0, column=0, sticky=text_label_grid_sticky,
|
||||||
padx=self._apply_widget_scaling(min(self._corner_radius, round(self._current_height/2))))
|
padx=self._apply_widget_scaling(min(self._corner_radius, round(self._current_height/2))))
|
||||||
|
|
||||||
self._draw(no_color_updates=True)
|
self._draw(no_color_updates=True)
|
||||||
|
|
||||||
@ -104,13 +115,20 @@ class CTkLabel(CTkBaseClass):
|
|||||||
|
|
||||||
def _update_font(self):
|
def _update_font(self):
|
||||||
""" pass font to tkinter widgets with applied font scaling and update grid with workaround """
|
""" pass font to tkinter widgets with applied font scaling and update grid with workaround """
|
||||||
self._text_label.configure(font=self._apply_font_scaling(self._font))
|
self._label.configure(font=self._apply_font_scaling(self._font))
|
||||||
|
|
||||||
# Workaround to force grid to be resized when text changes size.
|
# Workaround to force grid to be resized when text changes size.
|
||||||
# Otherwise grid will lag and only resizes if other mouse action occurs.
|
# Otherwise grid will lag and only resizes if other mouse action occurs.
|
||||||
self._canvas.grid_forget()
|
self._canvas.grid_forget()
|
||||||
self._canvas.grid(row=0, column=0, sticky="nswe")
|
self._canvas.grid(row=0, column=0, sticky="nswe")
|
||||||
|
|
||||||
|
def _update_image(self):
|
||||||
|
if isinstance(self._image, CTkImage):
|
||||||
|
self._label.configure(image=self._image.create_scaled_photo_image(self._get_widget_scaling(),
|
||||||
|
self._get_appearance_mode()))
|
||||||
|
elif self._image is not None:
|
||||||
|
self._label.configure(image=self._image)
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
if isinstance(self._font, CTkFont):
|
if isinstance(self._font, CTkFont):
|
||||||
self._font.remove_size_configure_callback(self._update_font)
|
self._font.remove_size_configure_callback(self._update_font)
|
||||||
@ -130,28 +148,35 @@ class CTkLabel(CTkBaseClass):
|
|||||||
fill=self._apply_appearance_mode(self._fg_color),
|
fill=self._apply_appearance_mode(self._fg_color),
|
||||||
outline=self._apply_appearance_mode(self._fg_color))
|
outline=self._apply_appearance_mode(self._fg_color))
|
||||||
|
|
||||||
self._text_label.configure(fg=self._apply_appearance_mode(self._text_color),
|
self._label.configure(fg=self._apply_appearance_mode(self._text_color),
|
||||||
bg=self._apply_appearance_mode(self._fg_color))
|
bg=self._apply_appearance_mode(self._fg_color))
|
||||||
else:
|
else:
|
||||||
self._canvas.itemconfig("inner_parts",
|
self._canvas.itemconfig("inner_parts",
|
||||||
fill=self._apply_appearance_mode(self._bg_color),
|
fill=self._apply_appearance_mode(self._bg_color),
|
||||||
outline=self._apply_appearance_mode(self._bg_color))
|
outline=self._apply_appearance_mode(self._bg_color))
|
||||||
|
|
||||||
self._text_label.configure(fg=self._apply_appearance_mode(self._text_color),
|
self._label.configure(fg=self._apply_appearance_mode(self._text_color),
|
||||||
bg=self._apply_appearance_mode(self._bg_color))
|
bg=self._apply_appearance_mode(self._bg_color))
|
||||||
|
|
||||||
self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color))
|
self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color))
|
||||||
|
|
||||||
|
if self._image is not None:
|
||||||
|
self._update_image()
|
||||||
|
|
||||||
def configure(self, require_redraw=False, **kwargs):
|
def configure(self, require_redraw=False, **kwargs):
|
||||||
if "anchor" in kwargs:
|
if "anchor" in kwargs:
|
||||||
self._anchor = kwargs.pop("anchor")
|
self._anchor = kwargs.pop("anchor")
|
||||||
text_label_grid_sticky = self._anchor if self._anchor != "center" else ""
|
text_label_grid_sticky = self._anchor if self._anchor != "center" else ""
|
||||||
self._text_label.grid(row=0, column=0, sticky=text_label_grid_sticky,
|
self._label.grid(row=0, column=0, sticky=text_label_grid_sticky,
|
||||||
padx=self._apply_widget_scaling(min(self._corner_radius, round(self._current_height/2))))
|
padx=self._apply_widget_scaling(min(self._corner_radius, round(self._current_height/2))))
|
||||||
|
|
||||||
|
if "compound" in kwargs:
|
||||||
|
self._compound = kwargs.pop("compound")
|
||||||
|
self._label.configure(compound=self._compound)
|
||||||
|
|
||||||
if "text" in kwargs:
|
if "text" in kwargs:
|
||||||
self._text = kwargs.pop("text")
|
self._text = kwargs.pop("text")
|
||||||
self._text_label.configure(text=self._text)
|
self._label.configure(text=self._text)
|
||||||
|
|
||||||
if "font" in kwargs:
|
if "font" in kwargs:
|
||||||
if isinstance(self._font, CTkFont):
|
if isinstance(self._font, CTkFont):
|
||||||
@ -159,9 +184,16 @@ class CTkLabel(CTkBaseClass):
|
|||||||
self._font = self._check_font_type(kwargs.pop("font"))
|
self._font = self._check_font_type(kwargs.pop("font"))
|
||||||
if isinstance(self._font, CTkFont):
|
if isinstance(self._font, CTkFont):
|
||||||
self._font.add_size_configure_callback(self._update_font)
|
self._font.add_size_configure_callback(self._update_font)
|
||||||
|
|
||||||
self._update_font()
|
self._update_font()
|
||||||
|
|
||||||
|
if "image" in kwargs:
|
||||||
|
if isinstance(self._image, CTkImage):
|
||||||
|
self._image.remove_configure_callback(self._update_image)
|
||||||
|
self._image = kwargs.pop("image")
|
||||||
|
if isinstance(self._image, CTkImage):
|
||||||
|
self._image.add_configure_callback(self._update_image)
|
||||||
|
self._update_image()
|
||||||
|
|
||||||
if "fg_color" in kwargs:
|
if "fg_color" in kwargs:
|
||||||
self._fg_color = kwargs.pop("fg_color")
|
self._fg_color = kwargs.pop("fg_color")
|
||||||
require_redraw = True
|
require_redraw = True
|
||||||
@ -173,11 +205,11 @@ class CTkLabel(CTkBaseClass):
|
|||||||
if "corner_radius" in kwargs:
|
if "corner_radius" in kwargs:
|
||||||
self._corner_radius = kwargs.pop("corner_radius")
|
self._corner_radius = kwargs.pop("corner_radius")
|
||||||
text_label_grid_sticky = self._anchor if self._anchor != "center" else ""
|
text_label_grid_sticky = self._anchor if self._anchor != "center" else ""
|
||||||
self._text_label.grid(row=0, column=0, sticky=text_label_grid_sticky,
|
self._label.grid(row=0, column=0, sticky=text_label_grid_sticky,
|
||||||
padx=self._apply_widget_scaling(min(self._corner_radius, round(self._current_height/2))))
|
padx=self._apply_widget_scaling(min(self._corner_radius, round(self._current_height/2))))
|
||||||
require_redraw = True
|
require_redraw = True
|
||||||
|
|
||||||
self._text_label.configure(**pop_from_dict_by_set(kwargs, self._valid_tk_label_attributes)) # configure tkinter.Label
|
self._label.configure(**pop_from_dict_by_set(kwargs, self._valid_tk_label_attributes)) # configure tkinter.Label
|
||||||
super().configure(require_redraw=require_redraw, **kwargs) # configure CTkBaseClass
|
super().configure(require_redraw=require_redraw, **kwargs) # configure CTkBaseClass
|
||||||
|
|
||||||
def cget(self, attribute_name: str) -> any:
|
def cget(self, attribute_name: str) -> any:
|
||||||
@ -193,31 +225,35 @@ class CTkLabel(CTkBaseClass):
|
|||||||
return self._text
|
return self._text
|
||||||
elif attribute_name == "font":
|
elif attribute_name == "font":
|
||||||
return self._font
|
return self._font
|
||||||
|
elif attribute_name == "image":
|
||||||
|
return self._image
|
||||||
|
elif attribute_name == "compound":
|
||||||
|
return self._compound
|
||||||
elif attribute_name == "anchor":
|
elif attribute_name == "anchor":
|
||||||
return self._anchor
|
return self._anchor
|
||||||
|
|
||||||
elif attribute_name in self._valid_tk_label_attributes:
|
elif attribute_name in self._valid_tk_label_attributes:
|
||||||
return self._text_label.cget(attribute_name) # cget of tkinter.Label
|
return self._label.cget(attribute_name) # cget of tkinter.Label
|
||||||
else:
|
else:
|
||||||
return super().cget(attribute_name) # cget of CTkBaseClass
|
return super().cget(attribute_name) # cget of CTkBaseClass
|
||||||
|
|
||||||
def bind(self, sequence: str = None, command: Callable = None, add: str = None) -> str:
|
def bind(self, sequence: str = None, command: Callable = None, add: str = None) -> str:
|
||||||
""" called on the tkinter.Label and tkinter.Canvas """
|
""" called on the tkinter.Label and tkinter.Canvas """
|
||||||
canvas_bind_return = self._canvas.bind(sequence, command, add)
|
canvas_bind_return = self._canvas.bind(sequence, command, add)
|
||||||
label_bind_return = self._text_label.bind(sequence, command, add)
|
label_bind_return = self._label.bind(sequence, command, add)
|
||||||
return canvas_bind_return + " + " + label_bind_return
|
return canvas_bind_return + " + " + label_bind_return
|
||||||
|
|
||||||
def unbind(self, sequence: str, funcid: str = None):
|
def unbind(self, sequence: str, funcid: str = None):
|
||||||
""" called on the tkinter.Label and tkinter.Canvas """
|
""" called on the tkinter.Label and tkinter.Canvas """
|
||||||
canvas_bind_return, label_bind_return = funcid.split(" + ")
|
canvas_bind_return, label_bind_return = funcid.split(" + ")
|
||||||
self._canvas.unbind(sequence, canvas_bind_return)
|
self._canvas.unbind(sequence, canvas_bind_return)
|
||||||
self._text_label.unbind(sequence, label_bind_return)
|
self._label.unbind(sequence, label_bind_return)
|
||||||
|
|
||||||
def focus(self):
|
def focus(self):
|
||||||
return self._text_label.focus()
|
return self._label.focus()
|
||||||
|
|
||||||
def focus_set(self):
|
def focus_set(self):
|
||||||
return self._text_label.focus_set()
|
return self._label.focus_set()
|
||||||
|
|
||||||
def focus_force(self):
|
def focus_force(self):
|
||||||
return self._text_label.focus_force()
|
return self._label.focus_force()
|
||||||
|
@ -27,7 +27,6 @@ class CTkImage:
|
|||||||
self._check_pil_import()
|
self._check_pil_import()
|
||||||
|
|
||||||
self._light_image = light_image
|
self._light_image = light_image
|
||||||
print(self._light_image)
|
|
||||||
self._dark_image = dark_image
|
self._dark_image = dark_image
|
||||||
self._check_images()
|
self._check_images()
|
||||||
self._size = size
|
self._size = size
|
||||||
@ -109,7 +108,6 @@ class CTkImage:
|
|||||||
|
|
||||||
def create_scaled_photo_image(self, widget_scaling: float, appearance_mode: str) -> ImageTk.PhotoImage:
|
def create_scaled_photo_image(self, widget_scaling: float, appearance_mode: str) -> ImageTk.PhotoImage:
|
||||||
scaled_size = self._get_scaled_size(widget_scaling)
|
scaled_size = self._get_scaled_size(widget_scaling)
|
||||||
print(scaled_size)
|
|
||||||
|
|
||||||
if appearance_mode == "light" and self._light_image is not None:
|
if appearance_mode == "light" and self._light_image is not None:
|
||||||
return self._get_scaled_light_photo_image(scaled_size)
|
return self._get_scaled_light_photo_image(scaled_size)
|
||||||
|
@ -2,21 +2,34 @@ import customtkinter
|
|||||||
from PIL import Image, ImageTk
|
from PIL import Image, ImageTk
|
||||||
import os
|
import os
|
||||||
|
|
||||||
PATH = os.path.dirname(os.path.realpath(__file__))
|
# load images
|
||||||
|
file_path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
image_1 = customtkinter.CTkImage(light_image=Image.open(file_path + "/test_images/add_folder_dark.png"),
|
||||||
|
dark_image=Image.open(file_path + "/test_images/add_folder_light.png"),
|
||||||
|
size=(30, 30))
|
||||||
|
image_1.configure(dark_image=Image.open(file_path + "/test_images/add_folder_light.png"))
|
||||||
|
image_2 = customtkinter.CTkImage(light_image=Image.open(file_path + "/test_images/bg_gradient.jpg"),
|
||||||
|
size=(30, 50))
|
||||||
|
|
||||||
app = customtkinter.CTk()
|
app = customtkinter.CTk()
|
||||||
|
|
||||||
switch_1 = customtkinter.CTkSwitch(app, text="darkmode", command=lambda: customtkinter.set_appearance_mode("dark" if switch_1.get() == 1 else "light"))
|
mode_switch = customtkinter.CTkSwitch(app, text="darkmode",
|
||||||
switch_1.pack(padx=20, pady=20)
|
command=lambda: customtkinter.set_appearance_mode("dark" if mode_switch.get() == 1 else "light"))
|
||||||
|
mode_switch.pack(padx=20, pady=20)
|
||||||
|
|
||||||
image_1 = customtkinter.CTkImage(light_image=Image.open(PATH + "/test_images/add_folder_dark.png"),
|
scaling_button = customtkinter.CTkSegmentedButton(app, values=[0.8, 0.9, 1.0, 1.1, 1.2, 1.5, 2.0],
|
||||||
dark_image=Image.open(PATH + "/test_images/add_folder_light.png"),
|
command=lambda v: customtkinter.set_widget_scaling(v))
|
||||||
size=(30, 50))
|
scaling_button.pack(padx=20, pady=20)
|
||||||
image_1.configure(dark_image=Image.open(PATH + "/test_images/add_folder_light.png"))
|
|
||||||
|
|
||||||
button_1 = customtkinter.CTkButton(app, image=image_1)
|
button_1 = customtkinter.CTkButton(app, image=image_1)
|
||||||
button_1.pack(padx=20, pady=20)
|
button_1.pack(padx=20, pady=20)
|
||||||
|
|
||||||
|
label_1 = customtkinter.CTkLabel(app, text="", image=image_2, compound="right", fg_color="green", width=0)
|
||||||
|
label_1.pack(padx=20, pady=20)
|
||||||
|
label_1.configure(image=image_1)
|
||||||
|
label_2 = customtkinter.CTkLabel(app, image=ImageTk.PhotoImage(Image.open(file_path + "/test_images/bg_gradient.jpg").resize((100, 100))),
|
||||||
|
text="", compound="right", fg_color="green", width=0)
|
||||||
|
label_2.pack(padx=20, pady=20)
|
||||||
|
|
||||||
app.mainloop()
|
app.mainloop()
|
||||||
|
|
||||||
|
BIN
examples/test_images/add_folder_dark.png
Normal file
BIN
examples/test_images/add_folder_dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.9 KiB |
BIN
examples/test_images/add_folder_light.png
Normal file
BIN
examples/test_images/add_folder_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
Loading…
Reference in New Issue
Block a user