mirror of
https://github.com/TomSchimansky/CustomTkinter.git
synced 2023-08-10 21:13:13 +03:00
finished CTkFont support for button, label, checkbox, created test_font.py
This commit is contained in:
parent
1ae794272b
commit
42fb7f2186
@ -5,10 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
ToDo:
|
ToDo:
|
||||||
-
|
- enforce font size in pixel and enforce CTkFont class
|
||||||
- remove bg and background support for CTk and CTkToplevel (to be done)
|
|
||||||
- enforce font size in pixel
|
|
||||||
- enforce font to be tuple
|
|
||||||
- complete other theme files
|
- complete other theme files
|
||||||
- auto scaling of images
|
- auto scaling of images
|
||||||
|
|
||||||
@ -28,6 +25,7 @@ ToDo:
|
|||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- Removed setter and getter functions like set_text in CTkButton
|
- Removed setter and getter functions like set_text in CTkButton
|
||||||
|
- Removed bg and background attribute from CTk and CTkToplevel, always use fg_color
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ from .windows.ctk_toplevel import CTkToplevel
|
|||||||
from .windows.ctk_input_dialog import CTkInputDialog
|
from .windows.ctk_input_dialog import CTkInputDialog
|
||||||
|
|
||||||
# util classes
|
# util classes
|
||||||
from .utility.ctk_font import CTkFont
|
from .utility.ctk_font import CTkFont as _CTkFont
|
||||||
|
|
||||||
|
|
||||||
def set_appearance_mode(mode_string: str):
|
def set_appearance_mode(mode_string: str):
|
||||||
|
@ -1,15 +1,25 @@
|
|||||||
from tkinter.font import Font
|
from tkinter.font import Font
|
||||||
import copy
|
import copy
|
||||||
import sys
|
from typing import List, Callable, Tuple
|
||||||
|
|
||||||
from ..scaling_tracker import ScalingTracker
|
|
||||||
from ..theme_manager import ThemeManager
|
from ..theme_manager import ThemeManager
|
||||||
|
|
||||||
|
|
||||||
class CTkFont(Font):
|
class CTkFont(Font):
|
||||||
"""
|
"""
|
||||||
Font object with size in pixel independent of scaling.
|
Font object with size in pixel, independent of scaling.
|
||||||
|
To get scaled tuple representation use create_scaled_tuple() method.
|
||||||
|
|
||||||
|
family The font family name as a string.
|
||||||
|
size The font height as an integer in pixel.
|
||||||
|
weight 'bold' for boldface, 'normal' for regular weight.
|
||||||
|
slant 'italic' for italic, 'roman' for unslanted.
|
||||||
|
underline 1 for underlined text, 0 for normal.
|
||||||
|
overstrike 1 for overstruck text, 0 for normal.
|
||||||
|
|
||||||
|
Tkinter Font: https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/fonts.html
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
family: str = "default_theme",
|
family: str = "default_theme",
|
||||||
size: int = "default_theme",
|
size: int = "default_theme",
|
||||||
@ -18,34 +28,30 @@ class CTkFont(Font):
|
|||||||
underline: bool = False,
|
underline: bool = False,
|
||||||
overstrike: bool = False):
|
overstrike: bool = False):
|
||||||
|
|
||||||
# unscaled font size in px
|
self._size_configure_callback_list: List[Callable] = []
|
||||||
self._size = ThemeManager.theme["text"]["size"] if size == "default_theme" else size
|
|
||||||
|
|
||||||
if self._size < 0:
|
self._family = family
|
||||||
sys.stderr.write(f"Warning: size {self._size} of CTkFont don't has to be negative, it's measured in pixel by default\n")
|
self._size = ThemeManager.theme["text"]["size"] if size == "default_theme" 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_theme" else family,
|
||||||
size=self._size,
|
size=-abs(self._size),
|
||||||
weight=weight,
|
weight=weight,
|
||||||
slant=slant,
|
slant=slant,
|
||||||
underline=underline,
|
underline=underline,
|
||||||
overstrike=overstrike)
|
overstrike=overstrike)
|
||||||
|
|
||||||
def _set_scaling(self, new_widget_scaling, new_spacing_scaling, new_window_scaling):
|
def add_size_configure_callback(self, callback: Callable):
|
||||||
self._widget_scaling = new_widget_scaling
|
""" add function, that gets called when font got configured """
|
||||||
super().configure(size=round(self._apply_widget_scaling(self._size)))
|
self._size_configure_callback_list.append(callback)
|
||||||
|
|
||||||
def _apply_widget_scaling(self, value: int) -> int:
|
def remove_size_configure_callback(self, callback: Callable):
|
||||||
if isinstance(value, int):
|
""" remove function, that gets called when font got configured """
|
||||||
return round(value * self._widget_scaling)
|
self._size_configure_callback_list.remove(callback)
|
||||||
else:
|
|
||||||
raise ValueError(f"CTkFont can not scale size of type {type(value)}, only int allowed")
|
|
||||||
|
|
||||||
def _reverse_widget_scaling(self, value: int) -> int:
|
def create_scaled_tuple(self, font_scaling: float) -> Tuple[str, int, str]:
|
||||||
if isinstance(value, int):
|
""" return scaled tuple representation of font in the form (family: str, size: int, style: str)"""
|
||||||
return round(value / self._widget_scaling)
|
return self._family, round(self._size * font_scaling), self._tuple_style_string
|
||||||
else:
|
|
||||||
raise ValueError(f"CTkFont can not scale size of type {type(value)}, only int allowed")
|
|
||||||
|
|
||||||
def config(self, *args, **kwargs):
|
def config(self, *args, **kwargs):
|
||||||
raise AttributeError("'config' is not implemented for CTk widgets. For consistency, always use 'configure' instead.")
|
raise AttributeError("'config' is not implemented for CTk widgets. For consistency, always use 'configure' instead.")
|
||||||
@ -53,42 +59,22 @@ class CTkFont(Font):
|
|||||||
def configure(self, **kwargs):
|
def configure(self, **kwargs):
|
||||||
if "size" in kwargs:
|
if "size" in kwargs:
|
||||||
self._size = kwargs.pop("size")
|
self._size = kwargs.pop("size")
|
||||||
super().configure(size=self._apply_widget_scaling(self._size))
|
super().configure(size=-abs(self._size))
|
||||||
|
|
||||||
super().configure(**kwargs)
|
super().configure(**kwargs)
|
||||||
|
|
||||||
def cget(self, attribute_name) -> any:
|
# update style string for create_scaled_tuple() method
|
||||||
|
self._tuple_style_string = f"{super().cget('weight')} {super().cget('slant')} {'underline' if super().cget('underline') else ''} {'overstrike' if super().cget('overstrike') else ''}"
|
||||||
|
|
||||||
|
# call all functions registered with add_size_configure_callback()
|
||||||
|
for callback in self._size_configure_callback_list:
|
||||||
|
callback()
|
||||||
|
|
||||||
|
def cget(self, attribute_name: str) -> any:
|
||||||
if attribute_name == "size":
|
if attribute_name == "size":
|
||||||
return self._size
|
return self._size
|
||||||
else:
|
else:
|
||||||
super().cget(attribute_name)
|
return super().cget(attribute_name)
|
||||||
|
|
||||||
def copy(self) -> "CTkFont":
|
def copy(self) -> "CTkFont":
|
||||||
return copy.deepcopy(self)
|
return copy.deepcopy(self)
|
||||||
|
|
||||||
def measure(self, text, displayof=None) -> int:
|
|
||||||
""" measure width of text in px independent of scaling """
|
|
||||||
return self._reverse_widget_scaling(super().measure(text, displayof=displayof))
|
|
||||||
|
|
||||||
def metrics(self, *options: any, **kw: any) -> dict:
|
|
||||||
""" metrics of font, all values independent of scaling """
|
|
||||||
metrics_dict = super().metrics(*options, **kw)
|
|
||||||
|
|
||||||
if "ascent" in metrics_dict:
|
|
||||||
metrics_dict["ascent"] = self._reverse_widget_scaling(metrics_dict["ascent"])
|
|
||||||
if "descent" in metrics_dict:
|
|
||||||
metrics_dict["descent"] = self._reverse_widget_scaling(metrics_dict["descent"])
|
|
||||||
if "linespace" in metrics_dict:
|
|
||||||
metrics_dict["linespace"] = self._reverse_widget_scaling(metrics_dict["linespace"])
|
|
||||||
|
|
||||||
return metrics_dict
|
|
||||||
|
|
||||||
def actual(self, option: any = None, displayof: any = None) -> dict:
|
|
||||||
""" get back a dictionary of the font's actual attributes, which may differ from the ones you requested, size independent of scaling """
|
|
||||||
actual_dict = super().actual(option, displayof)
|
|
||||||
|
|
||||||
if "size" in actual_dict:
|
|
||||||
actual_dict["size"] = self._reverse_widget_scaling(actual_dict["size"])
|
|
||||||
|
|
||||||
return actual_dict
|
|
||||||
|
|
||||||
|
@ -63,12 +63,16 @@ class CTkButton(CTkBaseClass):
|
|||||||
|
|
||||||
self._corner_radius = min(self._corner_radius, round(self._current_height/2))
|
self._corner_radius = min(self._corner_radius, round(self._current_height/2))
|
||||||
|
|
||||||
# text, font, image
|
# text, image
|
||||||
self._image = image
|
self._image = image
|
||||||
self._image_label: Union[tkinter.Label, None] = None
|
self._image_label: Union[tkinter.Label, None] = None
|
||||||
self._text = text
|
self._text = text
|
||||||
self._text_label: Union[tkinter.Label, None] = None
|
self._text_label: Union[tkinter.Label, None] = None
|
||||||
self._font = CTkFont() if font == "default_theme" else self._check_font_type_and_values(font)
|
|
||||||
|
# font
|
||||||
|
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
|
||||||
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.add_size_configure_callback(self._update_font)
|
||||||
|
|
||||||
# callback and hover functionality
|
# callback and hover functionality
|
||||||
self._command = command
|
self._command = command
|
||||||
@ -120,6 +124,21 @@ class CTkButton(CTkBaseClass):
|
|||||||
height=self._apply_widget_scaling(self._desired_height))
|
height=self._apply_widget_scaling(self._desired_height))
|
||||||
self._draw()
|
self._draw()
|
||||||
|
|
||||||
|
def _update_font(self):
|
||||||
|
""" pass font to tkinter widgets with applied font scaling and update grid with workaround """
|
||||||
|
if self._text_label is not None:
|
||||||
|
self._text_label.configure(font=self._apply_font_scaling(self._font))
|
||||||
|
|
||||||
|
# Workaround to force grid to be resized when text changes size.
|
||||||
|
# Otherwise grid will lag and only resizes if other mouse action occurs.
|
||||||
|
self._canvas.grid_forget()
|
||||||
|
self._canvas.grid(row=0, column=0, rowspan=2, columnspan=2, sticky="nsew")
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.remove_size_configure_callback(self._update_font)
|
||||||
|
super().destroy()
|
||||||
|
|
||||||
def _draw(self, no_color_updates=False):
|
def _draw(self, no_color_updates=False):
|
||||||
if self._background_corner_colors is not None:
|
if self._background_corner_colors is not None:
|
||||||
self._draw_engine.draw_background_corners(self._apply_widget_scaling(self._current_width),
|
self._draw_engine.draw_background_corners(self._apply_widget_scaling(self._current_width),
|
||||||
@ -269,7 +288,12 @@ class CTkButton(CTkBaseClass):
|
|||||||
self._text_label.configure(text=self._text)
|
self._text_label.configure(text=self._text)
|
||||||
|
|
||||||
if "font" in kwargs:
|
if "font" in kwargs:
|
||||||
self._font = kwargs.pop("font")
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.remove_size_configure_callback(self._update_font)
|
||||||
|
self._font = self._check_font_type(kwargs.pop("font"))
|
||||||
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.add_size_configure_callback(self._update_font)
|
||||||
|
|
||||||
if self._text_label is not None:
|
if self._text_label is not None:
|
||||||
self._text_label.configure(font=self._apply_font_scaling(self._font))
|
self._text_label.configure(font=self._apply_font_scaling(self._font))
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ from ..theme_manager import ThemeManager
|
|||||||
from ..settings import Settings
|
from ..settings import Settings
|
||||||
from ..draw_engine import DrawEngine
|
from ..draw_engine import DrawEngine
|
||||||
from .widget_base_class import CTkBaseClass
|
from .widget_base_class import CTkBaseClass
|
||||||
|
from ..utility.ctk_font import CTkFont
|
||||||
|
|
||||||
|
|
||||||
class CTkCheckBox(CTkBaseClass):
|
class CTkCheckBox(CTkBaseClass):
|
||||||
@ -33,7 +34,7 @@ class CTkCheckBox(CTkBaseClass):
|
|||||||
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme",
|
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme",
|
||||||
|
|
||||||
text: str = "CTkCheckBox",
|
text: str = "CTkCheckBox",
|
||||||
font: any = "default_theme",
|
font: Union[tuple, CTkFont] = "default_theme",
|
||||||
textvariable: tkinter.Variable = None,
|
textvariable: tkinter.Variable = None,
|
||||||
state: str = tkinter.NORMAL,
|
state: str = tkinter.NORMAL,
|
||||||
hover: bool = True,
|
hover: bool = True,
|
||||||
@ -65,7 +66,11 @@ class CTkCheckBox(CTkBaseClass):
|
|||||||
self._text_label: Union[tkinter.Label, None] = None
|
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 = 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_disabled = ThemeManager.theme["color"]["text_disabled"] if text_color_disabled == "default_theme" else text_color_disabled
|
||||||
self._font = (ThemeManager.theme["text"]["font"], ThemeManager.theme["text"]["size"]) if font == "default_theme" else font
|
|
||||||
|
# font
|
||||||
|
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
|
||||||
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.add_size_configure_callback(self._update_font)
|
||||||
|
|
||||||
# callback and hover functionality
|
# callback and hover functionality
|
||||||
self._command = command
|
self._command = command
|
||||||
@ -145,10 +150,23 @@ class CTkCheckBox(CTkBaseClass):
|
|||||||
self._bg_canvas.configure(width=self._apply_widget_scaling(self._desired_width),
|
self._bg_canvas.configure(width=self._apply_widget_scaling(self._desired_width),
|
||||||
height=self._apply_widget_scaling(self._desired_height))
|
height=self._apply_widget_scaling(self._desired_height))
|
||||||
|
|
||||||
|
def _update_font(self):
|
||||||
|
""" pass font to tkinter widgets with applied font scaling and update grid with workaround """
|
||||||
|
if self._text_label is not None:
|
||||||
|
self._text_label.configure(font=self._apply_font_scaling(self._font))
|
||||||
|
|
||||||
|
# Workaround to force grid to be resized when text changes size.
|
||||||
|
# Otherwise grid will lag and only resizes if other mouse action occurs.
|
||||||
|
self._bg_canvas.grid_forget()
|
||||||
|
self._bg_canvas.grid(row=0, column=0, sticky="nswe")
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
if self._variable is not None:
|
if self._variable is not None:
|
||||||
self._variable.trace_remove("write", self._variable_callback_name)
|
self._variable.trace_remove("write", self._variable_callback_name)
|
||||||
|
|
||||||
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.remove_size_configure_callback(self._update_font)
|
||||||
|
|
||||||
super().destroy()
|
super().destroy()
|
||||||
|
|
||||||
def _draw(self, no_color_updates=False):
|
def _draw(self, no_color_updates=False):
|
||||||
@ -212,9 +230,13 @@ class CTkCheckBox(CTkBaseClass):
|
|||||||
self._text_label.configure(text=self._text)
|
self._text_label.configure(text=self._text)
|
||||||
|
|
||||||
if "font" in kwargs:
|
if "font" in kwargs:
|
||||||
self._font = kwargs.pop("font")
|
if isinstance(self._font, CTkFont):
|
||||||
if self._text_label is not None:
|
self._font.remove_size_configure_callback(self._update_font)
|
||||||
self._text_label.configure(font=self._apply_font_scaling(self._font))
|
self._font = self._check_font_type(kwargs.pop("font"))
|
||||||
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.add_size_configure_callback(self._update_font)
|
||||||
|
|
||||||
|
self._update_font()
|
||||||
|
|
||||||
if "state" in kwargs:
|
if "state" in kwargs:
|
||||||
self._state = kwargs.pop("state")
|
self._state = kwargs.pop("state")
|
||||||
|
@ -5,6 +5,7 @@ from .ctk_canvas import CTkCanvas
|
|||||||
from ..theme_manager import ThemeManager
|
from ..theme_manager import ThemeManager
|
||||||
from ..draw_engine import DrawEngine
|
from ..draw_engine import DrawEngine
|
||||||
from .widget_base_class import CTkBaseClass
|
from .widget_base_class import CTkBaseClass
|
||||||
|
from ..utility.ctk_font import CTkFont
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ class CTkLabel(CTkBaseClass):
|
|||||||
text_color: Union[str, Tuple[str, str]] = "default_theme",
|
text_color: Union[str, Tuple[str, str]] = "default_theme",
|
||||||
|
|
||||||
text: str = "CTkLabel",
|
text: str = "CTkLabel",
|
||||||
font: any = "default_theme",
|
font: Union[tuple, CTkFont] = "default_theme",
|
||||||
anchor: str = "center", # label anchor: center, n, e, s, w
|
anchor: str = "center", # label anchor: center, n, e, s, w
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
|
||||||
@ -47,7 +48,11 @@ class CTkLabel(CTkBaseClass):
|
|||||||
# text
|
# text
|
||||||
self._anchor = anchor
|
self._anchor = anchor
|
||||||
self._text = text
|
self._text = text
|
||||||
self._font = (ThemeManager.theme["text"]["font"], ThemeManager.theme["text"]["size"]) if font == "default_theme" else font
|
|
||||||
|
# font
|
||||||
|
self._font = CTkFont() if font == "default_theme" else self._check_font_type(font)
|
||||||
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.add_size_configure_callback(self._update_font)
|
||||||
|
|
||||||
# configure grid system (1x1)
|
# configure grid system (1x1)
|
||||||
self.grid_rowconfigure(0, weight=1)
|
self.grid_rowconfigure(0, weight=1)
|
||||||
@ -97,6 +102,20 @@ class CTkLabel(CTkBaseClass):
|
|||||||
height=self._apply_widget_scaling(self._desired_height))
|
height=self._apply_widget_scaling(self._desired_height))
|
||||||
self._draw()
|
self._draw()
|
||||||
|
|
||||||
|
def _update_font(self):
|
||||||
|
""" 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))
|
||||||
|
|
||||||
|
# Workaround to force grid to be resized when text changes size.
|
||||||
|
# Otherwise grid will lag and only resizes if other mouse action occurs.
|
||||||
|
self._canvas.grid_forget()
|
||||||
|
self._canvas.grid(row=0, column=0, sticky="nswe")
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.remove_size_configure_callback(self._update_font)
|
||||||
|
super().destroy()
|
||||||
|
|
||||||
def _draw(self, no_color_updates=False):
|
def _draw(self, no_color_updates=False):
|
||||||
requires_recoloring = self._draw_engine.draw_rounded_rect_with_border(self._apply_widget_scaling(self._current_width),
|
requires_recoloring = self._draw_engine.draw_rounded_rect_with_border(self._apply_widget_scaling(self._current_width),
|
||||||
self._apply_widget_scaling(self._current_height),
|
self._apply_widget_scaling(self._current_height),
|
||||||
@ -133,8 +152,13 @@ class CTkLabel(CTkBaseClass):
|
|||||||
self._text_label.configure(text=self._text)
|
self._text_label.configure(text=self._text)
|
||||||
|
|
||||||
if "font" in kwargs:
|
if "font" in kwargs:
|
||||||
self._font = kwargs.pop("font")
|
if isinstance(self._font, CTkFont):
|
||||||
self._text_label.configure(font=self._apply_font_scaling(self._font))
|
self._font.remove_size_configure_callback(self._update_font)
|
||||||
|
self._font = self._check_font_type(kwargs.pop("font"))
|
||||||
|
if isinstance(self._font, CTkFont):
|
||||||
|
self._font.add_size_configure_callback(self._update_font)
|
||||||
|
|
||||||
|
self._update_font()
|
||||||
|
|
||||||
if "fg_color" in kwargs:
|
if "fg_color" in kwargs:
|
||||||
self._fg_color = kwargs.pop("fg_color")
|
self._fg_color = kwargs.pop("fg_color")
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import sys
|
||||||
import tkinter
|
import tkinter
|
||||||
import tkinter.ttk as ttk
|
import tkinter.ttk as ttk
|
||||||
import copy
|
import copy
|
||||||
@ -118,7 +119,7 @@ class CTkBaseClass(tkinter.Frame):
|
|||||||
super().configure(**pop_from_dict_by_set(kwargs, self._valid_tk_frame_attributes)) # configure tkinter.Frame
|
super().configure(**pop_from_dict_by_set(kwargs, self._valid_tk_frame_attributes)) # configure tkinter.Frame
|
||||||
|
|
||||||
# if there are still items in the kwargs dict, raise ValueError
|
# if there are still items in the kwargs dict, raise ValueError
|
||||||
self._check_kwargs_empty(kwargs, raise_error=True)
|
check_kwargs_empty(kwargs, raise_error=True)
|
||||||
|
|
||||||
if require_redraw:
|
if require_redraw:
|
||||||
self._draw()
|
self._draw()
|
||||||
@ -139,10 +140,23 @@ class CTkBaseClass(tkinter.Frame):
|
|||||||
raise ValueError(f"'{attribute_name}' is not a supported argument. Look at the documentation for supported arguments.")
|
raise ValueError(f"'{attribute_name}' is not a supported argument. Look at the documentation for supported arguments.")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _check_font_type_and_values(font: any):
|
def _check_font_type(font: any):
|
||||||
if not isinstance(font, CTkFont):
|
if isinstance(font, CTkFont):
|
||||||
raise ValueError(f"\nFor consistency, Customtkinter requires the font argument {font} to be an instance of CTkFont.\n" +
|
return font
|
||||||
f"\nUsage example: font=customtkinter.CTkFont(family='name', size='size in px')\n(other arguments in the documentation)\n")
|
|
||||||
|
elif type(font) == tuple and len(font) == 1:
|
||||||
|
sys.stderr.write(f"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) <= 3:
|
||||||
|
return font
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Wrong font type {type(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 _update_dimensions_event(self, event):
|
def _update_dimensions_event(self, event):
|
||||||
# only redraw if dimensions changed (for performance), independent of scaling
|
# only redraw if dimensions changed (for performance), independent of scaling
|
||||||
@ -219,15 +233,22 @@ class CTkBaseClass(tkinter.Frame):
|
|||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def _apply_font_scaling(self, font: Union[tuple, CTkFont]) -> Union[tuple, CTkFont]:
|
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 type(font) == tuple:
|
||||||
font_list = list(font)
|
if len(font) == 1:
|
||||||
if len(font_list) >= 2 and type(font_list[1]) == int:
|
return font
|
||||||
font_list[1] = int(font_list[1] * self._widget_scaling)
|
elif len(font) == 2:
|
||||||
return tuple(font_list)
|
return font[0], round(font[1] * self._widget_scaling)
|
||||||
|
elif len(font) == 3:
|
||||||
|
return font[0], 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):
|
elif isinstance(font, CTkFont):
|
||||||
return font
|
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")
|
||||||
|
|
||||||
def _apply_argument_scaling(self, kwargs: dict) -> dict:
|
def _apply_argument_scaling(self, kwargs: dict) -> dict:
|
||||||
scaled_kwargs = copy.copy(kwargs)
|
scaled_kwargs = copy.copy(kwargs)
|
||||||
|
@ -82,10 +82,15 @@ class CTk(tkinter.Tk):
|
|||||||
|
|
||||||
def _update_dimensions_event(self, event=None):
|
def _update_dimensions_event(self, event=None):
|
||||||
if not self._block_update_dimensions_event:
|
if not self._block_update_dimensions_event:
|
||||||
self.update_idletasks()
|
|
||||||
|
# removed this because of python stackoverflow error with many label widgets
|
||||||
|
# self.update_idletasks()
|
||||||
detected_width = self.winfo_width() # detect current window size
|
detected_width = self.winfo_width() # detect current window size
|
||||||
detected_height = self.winfo_height()
|
detected_height = self.winfo_height()
|
||||||
|
|
||||||
|
# detected_width = event.width
|
||||||
|
# detected_height = event.height
|
||||||
|
|
||||||
if self._current_width != round(detected_width / self._window_scaling) or self._current_height != round(detected_height / self._window_scaling):
|
if self._current_width != round(detected_width / self._window_scaling) or self._current_height != round(detected_height / self._window_scaling):
|
||||||
self._current_width = round(detected_width / self._window_scaling) # adjust current size according to new size given by event
|
self._current_width = round(detected_width / self._window_scaling) # adjust current size according to new size given by event
|
||||||
self._current_height = round(detected_height / self._window_scaling) # _current_width and _current_height are independent of the scale
|
self._current_height = round(detected_height / self._window_scaling) # _current_width and _current_height are independent of the scale
|
||||||
|
@ -138,7 +138,7 @@ class App(customtkinter.CTk):
|
|||||||
self.seg_button_1.configure(values=["CTkSegmentedButton", "Value 2", "Value 3"])
|
self.seg_button_1.configure(values=["CTkSegmentedButton", "Value 2", "Value 3"])
|
||||||
self.seg_button_1.set("Value 2")
|
self.seg_button_1.set("Value 2")
|
||||||
|
|
||||||
self.attributes("-fullscreen", True)
|
# self.attributes("-fullscreen", True)
|
||||||
|
|
||||||
def open_input_dialog(self):
|
def open_input_dialog(self):
|
||||||
dialog = customtkinter.CTkInputDialog(master=self, text="Type in a number:", title="CTkInputDialog")
|
dialog = customtkinter.CTkInputDialog(master=self, text="Type in a number:", title="CTkInputDialog")
|
||||||
|
63
test/manual_integration_tests/test_font.py
Normal file
63
test/manual_integration_tests/test_font.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import customtkinter
|
||||||
|
|
||||||
|
|
||||||
|
app = customtkinter.CTk()
|
||||||
|
app.geometry("1200x1000")
|
||||||
|
app.grid_rowconfigure(0, weight=1)
|
||||||
|
app.grid_columnconfigure((0, 1), weight=1)
|
||||||
|
|
||||||
|
frame_1 = customtkinter.CTkFrame(app)
|
||||||
|
frame_1.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
|
||||||
|
frame_2 = customtkinter.CTkFrame(app)
|
||||||
|
frame_2.grid(row=0, column=1, sticky="nsew", padx=10, pady=10)
|
||||||
|
|
||||||
|
def set_scaling(scaling):
|
||||||
|
customtkinter.set_widget_scaling(scaling)
|
||||||
|
customtkinter.set_spacing_scaling(scaling)
|
||||||
|
|
||||||
|
scaling_button = customtkinter._CTkSegmentedButton(frame_1, values=[0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.5, 2.0], command=set_scaling)
|
||||||
|
scaling_button.pack(pady=(2, 10))
|
||||||
|
|
||||||
|
b = customtkinter.CTkButton(frame_1, text="single name", font=("Times", ))
|
||||||
|
b.pack(pady=2)
|
||||||
|
b = customtkinter.CTkButton(frame_1, text="name with size", font=("Times", 18))
|
||||||
|
b.pack(pady=2)
|
||||||
|
b = customtkinter.CTkButton(frame_1, text="name with negative size", font=("Times", -18))
|
||||||
|
b.pack(pady=2)
|
||||||
|
b = customtkinter.CTkButton(frame_1, text="extra keywords", font=("Times", -18, "bold italic underline overstrike"))
|
||||||
|
b.pack(pady=2)
|
||||||
|
|
||||||
|
b = customtkinter.CTkButton(frame_1, text="object default")
|
||||||
|
b.pack(pady=(10, 2))
|
||||||
|
b = customtkinter.CTkButton(frame_1, text="object single name", font=customtkinter._CTkFont("Times"))
|
||||||
|
b.pack(pady=2)
|
||||||
|
b = customtkinter.CTkButton(frame_1, text="object with name and size", font=customtkinter._CTkFont("Times", 18))
|
||||||
|
b.pack(pady=2)
|
||||||
|
b = customtkinter.CTkButton(frame_1, text="object with name and negative size", font=customtkinter._CTkFont("Times", -18))
|
||||||
|
b.pack(pady=2)
|
||||||
|
b = customtkinter.CTkButton(frame_1, text="object with extra keywords",
|
||||||
|
font=customtkinter._CTkFont("Times", -18, weight="bold", slant="italic", underline=True, overstrike=True))
|
||||||
|
b.pack(pady=2)
|
||||||
|
|
||||||
|
b1 = customtkinter.CTkButton(frame_1, text="object default modified")
|
||||||
|
b1.pack(pady=(10, 2))
|
||||||
|
b1.cget("font").configure(size=9)
|
||||||
|
print(b1.cget("font").cget("size"), b1.cget("font").cget("family"))
|
||||||
|
|
||||||
|
b2 = customtkinter.CTkButton(frame_1, text="object default overridden")
|
||||||
|
b2.pack(pady=10)
|
||||||
|
b2.configure(font=customtkinter._CTkFont(family="Times"))
|
||||||
|
|
||||||
|
label_font = customtkinter._CTkFont(size=5)
|
||||||
|
for i in range(30):
|
||||||
|
l = customtkinter.CTkLabel(frame_2, font=label_font, height=0)
|
||||||
|
l.grid(row=i, column=0)
|
||||||
|
b = customtkinter.CTkButton(frame_2, font=label_font, height=5)
|
||||||
|
b.grid(row=i, column=1, pady=2)
|
||||||
|
c = customtkinter.CTkCheckBox(frame_2, font=label_font)
|
||||||
|
c.grid(row=i, column=2, pady=2)
|
||||||
|
frame_2.grid_columnconfigure((0, 1, 2), weight=1)
|
||||||
|
|
||||||
|
app.after(1500, lambda: label_font.configure(size=10))
|
||||||
|
# app.after(1500, lambda: l.configure(text="dshgfldjskhfjdslafhdjsgkkjdaslö"))
|
||||||
|
app.mainloop()
|
@ -23,7 +23,7 @@ b1.pack(pady=20)
|
|||||||
b2 = customtkinter.CTkButton(master=tabview_1.tab("tab 2"), text="button tab 2")
|
b2 = customtkinter.CTkButton(master=tabview_1.tab("tab 2"), text="button tab 2")
|
||||||
b2.pack()
|
b2.pack()
|
||||||
|
|
||||||
tabview_1.tab("tab 2").configure(fg_color="red")
|
# tabview_1.tab("tab 2").configure(fg_color="red")
|
||||||
tabview_1.configure(state="normal")
|
tabview_1.configure(state="normal")
|
||||||
# tabview_1.delete("tab 1")
|
# tabview_1.delete("tab 1")
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user