From 1ae794272b5c69aa01904df437381e1a211c9637 Mon Sep 17 00:00:00 2001 From: Tom Schimansky Date: Sun, 16 Oct 2022 20:13:19 +0200 Subject: [PATCH] removed bg and background argument support from CTk and CTkToplevel --- customtkinter/__init__.py | 3 + customtkinter/settings.py | 2 +- customtkinter/utility/__init__.py | 0 customtkinter/utility/ctk_font.py | 94 +++++++++++++++++++ customtkinter/utility/utility_functions.py | 23 +++++ customtkinter/widgets/ctk_button.py | 5 +- customtkinter/widgets/ctk_combobox.py | 2 - customtkinter/widgets/ctk_entry.py | 4 +- customtkinter/widgets/ctk_label.py | 4 +- customtkinter/widgets/ctk_textbox.py | 4 +- customtkinter/widgets/widget_base_class.py | 43 +++------ .../widgets/widget_helper_functions.py | 22 ----- customtkinter/windows/ctk_tk.py | 56 ++++------- customtkinter/windows/ctk_toplevel.py | 57 ++++------- examples/simple_example_standard_tkinter.py | 1 - .../complex_example_new.py | 2 + 16 files changed, 184 insertions(+), 138 deletions(-) create mode 100644 customtkinter/utility/__init__.py create mode 100644 customtkinter/utility/ctk_font.py create mode 100644 customtkinter/utility/utility_functions.py delete mode 100644 customtkinter/widgets/widget_helper_functions.py diff --git a/customtkinter/__init__.py b/customtkinter/__init__.py index 742a9a7..04fb2bf 100644 --- a/customtkinter/__init__.py +++ b/customtkinter/__init__.py @@ -73,6 +73,9 @@ from .windows.ctk_tk import CTk from .windows.ctk_toplevel import CTkToplevel from .windows.ctk_input_dialog import CTkInputDialog +# util classes +from .utility.ctk_font import CTkFont + def set_appearance_mode(mode_string: str): """ possible values: light, dark, system """ diff --git a/customtkinter/settings.py b/customtkinter/settings.py index a93f800..f75e71e 100644 --- a/customtkinter/settings.py +++ b/customtkinter/settings.py @@ -3,4 +3,4 @@ class Settings: cursor_manipulation_enabled = True deactivate_macos_window_header_manipulation = False deactivate_windows_window_header_manipulation = False - use_dropdown_fallback = True + # use_dropdown_fallback = True diff --git a/customtkinter/utility/__init__.py b/customtkinter/utility/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/customtkinter/utility/ctk_font.py b/customtkinter/utility/ctk_font.py new file mode 100644 index 0000000..6d1aa8b --- /dev/null +++ b/customtkinter/utility/ctk_font.py @@ -0,0 +1,94 @@ +from tkinter.font import Font +import copy +import sys + +from ..scaling_tracker import ScalingTracker +from ..theme_manager import ThemeManager + + +class CTkFont(Font): + """ + Font object with size in pixel independent of scaling. + """ + def __init__(self, + family: str = "default_theme", + size: int = "default_theme", + weight: str = "normal", + slant: str = "roman", + underline: bool = False, + overstrike: bool = False): + + # unscaled font size in px + self._size = ThemeManager.theme["text"]["size"] if size == "default_theme" else size + + if self._size < 0: + sys.stderr.write(f"Warning: size {self._size} of CTkFont don't has to be negative, it's measured in pixel by default\n") + + super().__init__(family=ThemeManager.theme["text"]["font"] if family == "default_theme" else family, + size=self._size, + weight=weight, + slant=slant, + underline=underline, + overstrike=overstrike) + + def _set_scaling(self, new_widget_scaling, new_spacing_scaling, new_window_scaling): + self._widget_scaling = new_widget_scaling + super().configure(size=round(self._apply_widget_scaling(self._size))) + + def _apply_widget_scaling(self, value: int) -> int: + if isinstance(value, int): + return round(value * self._widget_scaling) + else: + raise ValueError(f"CTkFont can not scale size of type {type(value)}, only int allowed") + + def _reverse_widget_scaling(self, value: int) -> int: + if isinstance(value, int): + return round(value / self._widget_scaling) + else: + raise ValueError(f"CTkFont can not scale size of type {type(value)}, only int allowed") + + def config(self, *args, **kwargs): + raise AttributeError("'config' is not implemented for CTk widgets. For consistency, always use 'configure' instead.") + + def configure(self, **kwargs): + if "size" in kwargs: + self._size = kwargs.pop("size") + super().configure(size=self._apply_widget_scaling(self._size)) + + super().configure(**kwargs) + + def cget(self, attribute_name) -> any: + if attribute_name == "size": + return self._size + else: + super().cget(attribute_name) + + def copy(self) -> "CTkFont": + 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 + diff --git a/customtkinter/utility/utility_functions.py b/customtkinter/utility/utility_functions.py new file mode 100644 index 0000000..8ae6475 --- /dev/null +++ b/customtkinter/utility/utility_functions.py @@ -0,0 +1,23 @@ + + +def pop_from_dict_by_set(dictionary: dict, valid_keys: set): + """ remove and create new dict with key value pairs of dictionary, where key is in valid_keys """ + new_dictionary = {} + + for key in list(dictionary.keys()): + if key in valid_keys: + new_dictionary[key] = dictionary.pop(key) + + return new_dictionary + + +def check_kwargs_empty(kwargs_dict, raise_error=False) -> bool: + """ returns True if kwargs are empty, False otherwise, raises error if not empty """ + + if len(kwargs_dict) > 0: + if raise_error: + raise ValueError(f"{list(kwargs_dict.keys())} are not supported arguments. Look at the documentation for supported arguments.") + else: + return True + else: + return False diff --git a/customtkinter/widgets/ctk_button.py b/customtkinter/widgets/ctk_button.py index 427ca82..0dae91c 100644 --- a/customtkinter/widgets/ctk_button.py +++ b/customtkinter/widgets/ctk_button.py @@ -7,6 +7,7 @@ from ..theme_manager import ThemeManager from ..settings import Settings from ..draw_engine import DrawEngine from .widget_base_class import CTkBaseClass +from ..utility.ctk_font import CTkFont class CTkButton(CTkBaseClass): @@ -34,7 +35,7 @@ class CTkButton(CTkBaseClass): round_height_to_even_numbers: bool = True, text: str = "CTkButton", - font: any = "default_theme", + font: Union[tuple, CTkFont] = "default_theme", textvariable: tkinter.Variable = None, image: tkinter.PhotoImage = None, state: str = "normal", @@ -67,7 +68,7 @@ class CTkButton(CTkBaseClass): self._image_label: Union[tkinter.Label, None] = None self._text = text self._text_label: Union[tkinter.Label, None] = None - self._font = (ThemeManager.theme["text"]["font"], ThemeManager.theme["text"]["size"]) if font == "default_theme" else font + self._font = CTkFont() if font == "default_theme" else self._check_font_type_and_values(font) # callback and hover functionality self._command = command diff --git a/customtkinter/widgets/ctk_combobox.py b/customtkinter/widgets/ctk_combobox.py index 6ce4604..9f84be0 100644 --- a/customtkinter/widgets/ctk_combobox.py +++ b/customtkinter/widgets/ctk_combobox.py @@ -9,8 +9,6 @@ from ..settings import Settings from ..draw_engine import DrawEngine from .widget_base_class import CTkBaseClass -from .widget_helper_functions import filter_dict_by_set - class CTkComboBox(CTkBaseClass): """ diff --git a/customtkinter/widgets/ctk_entry.py b/customtkinter/widgets/ctk_entry.py index b98d249..b056b88 100644 --- a/customtkinter/widgets/ctk_entry.py +++ b/customtkinter/widgets/ctk_entry.py @@ -6,7 +6,7 @@ from ..theme_manager import ThemeManager from ..draw_engine import DrawEngine from .widget_base_class import CTkBaseClass -from .widget_helper_functions import pop_from_dict_by_set +from customtkinter.utility.utility_functions import pop_from_dict_by_set, check_kwargs_empty class CTkEntry(CTkBaseClass): @@ -95,7 +95,7 @@ class CTkEntry(CTkBaseClass): padx=self._apply_widget_scaling(self._minimum_x_padding), pady=(self._apply_widget_scaling(self._border_width), self._apply_widget_scaling(self._border_width + 1))) - self._check_kwargs_empty(kwargs, raise_error=True) + check_kwargs_empty(kwargs, raise_error=True) self._entry.bind('', self._entry_focus_out) self._entry.bind('', self._entry_focus_in) diff --git a/customtkinter/widgets/ctk_label.py b/customtkinter/widgets/ctk_label.py index 72e6940..4422547 100644 --- a/customtkinter/widgets/ctk_label.py +++ b/customtkinter/widgets/ctk_label.py @@ -6,7 +6,7 @@ from ..theme_manager import ThemeManager from ..draw_engine import DrawEngine from .widget_base_class import CTkBaseClass -from .widget_helper_functions import pop_from_dict_by_set +from customtkinter.utility.utility_functions import pop_from_dict_by_set, check_kwargs_empty class CTkLabel(CTkBaseClass): @@ -74,7 +74,7 @@ class CTkLabel(CTkBaseClass): self._text_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)))) - self._check_kwargs_empty(kwargs, raise_error=True) + check_kwargs_empty(kwargs, raise_error=True) self._draw() diff --git a/customtkinter/widgets/ctk_textbox.py b/customtkinter/widgets/ctk_textbox.py index 1a09083..0e12199 100644 --- a/customtkinter/widgets/ctk_textbox.py +++ b/customtkinter/widgets/ctk_textbox.py @@ -7,7 +7,7 @@ from ..theme_manager import ThemeManager from ..draw_engine import DrawEngine from .widget_base_class import CTkBaseClass -from .widget_helper_functions import pop_from_dict_by_set +from customtkinter.utility.utility_functions import pop_from_dict_by_set, check_kwargs_empty class CTkTextbox(CTkBaseClass): @@ -87,7 +87,7 @@ class CTkTextbox(CTkBaseClass): bg=ThemeManager.single_color(self._fg_color, self._appearance_mode), **pop_from_dict_by_set(kwargs, self._valid_tk_text_attributes)) - self._check_kwargs_empty(kwargs, raise_error=True) + check_kwargs_empty(kwargs, raise_error=True) # scrollbars self._scrollbars_activated = activate_scrollbars diff --git a/customtkinter/widgets/widget_base_class.py b/customtkinter/widgets/widget_base_class.py index 12a0a71..3200529 100644 --- a/customtkinter/widgets/widget_base_class.py +++ b/customtkinter/widgets/widget_base_class.py @@ -1,7 +1,6 @@ import tkinter import tkinter.ttk as ttk import copy -import re from typing import Union, Callable, Tuple try: @@ -15,7 +14,9 @@ from ..appearance_mode_tracker import AppearanceModeTracker from ..scaling_tracker import ScalingTracker from ..theme_manager import ThemeManager -from .widget_helper_functions import pop_from_dict_by_set +from ..utility.ctk_font import CTkFont + +from ..utility.utility_functions import pop_from_dict_by_set, check_kwargs_empty class CTkBaseClass(tkinter.Frame): @@ -36,7 +37,7 @@ class CTkBaseClass(tkinter.Frame): super().__init__(master=master, width=width, height=height, **pop_from_dict_by_set(kwargs, self._valid_tk_frame_attributes)) # check if kwargs is empty, if not raise error for unsupported arguments - self._check_kwargs_empty(kwargs, raise_error=True) + check_kwargs_empty(kwargs, raise_error=True) # dimensions self._current_width = width # _current_width and _current_height in pixel, represent current size of the widget @@ -138,16 +139,10 @@ class CTkBaseClass(tkinter.Frame): raise ValueError(f"'{attribute_name}' is not a supported argument. Look at the documentation for supported arguments.") @staticmethod - def _check_kwargs_empty(kwargs_dict, raise_error=False) -> bool: - """ returns True if kwargs are empty, False otherwise, raises error if not empty """ - - if len(kwargs_dict) > 0: - if raise_error: - raise ValueError(f"{list(kwargs_dict.keys())} are not supported arguments. Look at the documentation for supported arguments.") - else: - return True - else: - return False + def _check_font_type_and_values(font: any): + if not isinstance(font, CTkFont): + raise ValueError(f"\nFor consistency, Customtkinter requires the font argument {font} to be an instance of CTkFont.\n" + + f"\nUsage example: font=customtkinter.CTkFont(family='name', size='size in px')\n(other arguments in the documentation)\n") def _update_dimensions_event(self, event): # only redraw if dimensions changed (for performance), independent of scaling @@ -224,26 +219,14 @@ class CTkBaseClass(tkinter.Frame): else: return value - def _apply_font_scaling(self, font): - if type(font) == tuple or type(font) == list: + def _apply_font_scaling(self, font: Union[tuple, CTkFont]) -> Union[tuple, CTkFont]: + if type(font) == tuple: font_list = list(font) - for i in range(len(font_list)): - if (type(font_list[i]) == int or type(font_list[i]) == float) and font_list[i] < 0: - font_list[i] = int(font_list[i] * self._widget_scaling) + if len(font_list) >= 2 and type(font_list[1]) == int: + font_list[1] = int(font_list[1] * self._widget_scaling) return tuple(font_list) - elif type(font) == str: - for negative_number in re.findall(r" -\d* ", font): - font = font.replace(negative_number, f" {int(int(negative_number) * self._widget_scaling)} ") - return font - - elif isinstance(font, tkinter.font.Font): - new_font_object = copy.copy(font) - if font.cget("size") < 0: - new_font_object.config(size=int(font.cget("size") * self._widget_scaling)) - return new_font_object - - else: + elif isinstance(font, CTkFont): return font def _apply_argument_scaling(self, kwargs: dict) -> dict: diff --git a/customtkinter/widgets/widget_helper_functions.py b/customtkinter/widgets/widget_helper_functions.py deleted file mode 100644 index e2cf7fa..0000000 --- a/customtkinter/widgets/widget_helper_functions.py +++ /dev/null @@ -1,22 +0,0 @@ - - -def filter_dict_by_set(dictionary: dict, valid_keys: set): - """ create new dict with key value pairs of dictionary, where key is in valid_keys """ - new_dictionary = {} - - for key, value in dictionary.items(): - if key in valid_keys: - new_dictionary[key] = value - - return new_dictionary - - -def pop_from_dict_by_set(dictionary: dict, valid_keys: set): - """ remove and create new dict with key value pairs of dictionary, where key is in valid_keys """ - new_dictionary = {} - - for key in list(dictionary.keys()): - if key in valid_keys: - new_dictionary[key] = dictionary.pop(key) - - return new_dictionary diff --git a/customtkinter/windows/ctk_tk.py b/customtkinter/windows/ctk_tk.py index efa7818..ffda428 100644 --- a/customtkinter/windows/ctk_tk.py +++ b/customtkinter/windows/ctk_tk.py @@ -5,7 +5,6 @@ import os import platform import ctypes import re -import time from typing import Union, Tuple from ..appearance_mode_tracker import AppearanceModeTracker @@ -13,6 +12,8 @@ from ..theme_manager import ThemeManager from ..scaling_tracker import ScalingTracker from ..settings import Settings +from ..utility.utility_functions import pop_from_dict_by_set, check_kwargs_empty + class CTk(tkinter.Tk): """ @@ -20,14 +21,21 @@ class CTk(tkinter.Tk): For detailed information check out the documentation. """ - def __init__(self, *args, + _valid_tk_constructor_arguments = {"screenName", "baseName", "className", "useTk", "sync", "use"} + + _valid_tk_configure_arguments = {'bd', 'borderwidth', 'class', 'menu', 'relief', 'screen', + 'use', 'container', 'cursor', 'height', + 'highlightthickness', 'padx', 'pady', 'takefocus', 'visual', 'width'} + + def __init__(self, fg_color: Union[str, Tuple[str, str]] = "default_theme", **kwargs): ScalingTracker.activate_high_dpi_awareness() # make process DPI aware self._enable_macos_dark_title_bar() - super().__init__(*args, **kwargs) + super().__init__(**pop_from_dict_by_set(kwargs, self._valid_tk_constructor_arguments)) + check_kwargs_empty(kwargs, raise_error=True) # add set_appearance_mode method to callback list of AppearanceModeTracker for appearance mode changes AppearanceModeTracker.add(self._set_appearance_mode, self) @@ -47,11 +55,6 @@ class CTk(tkinter.Tk): self._fg_color = ThemeManager.theme["color"]["window_bg_color"] if fg_color == "default_theme" else fg_color - if "bg" in kwargs: - self._fg_color = kwargs.pop("bg") - elif "background" in kwargs: - self._fg_color = kwargs.pop("background") - super().configure(bg=ThemeManager.single_color(self._fg_color, self._appearance_mode)) super().title("CTk") self.geometry(f"{self._current_width}x{self._current_height}") @@ -234,40 +237,19 @@ class CTk(tkinter.Tk): else: return value - def configure(self, *args, **kwargs): - bg_changed = False - - if "bg" in kwargs: - self._fg_color = kwargs["bg"] - bg_changed = True - kwargs["bg"] = ThemeManager.single_color(self._fg_color, self._appearance_mode) - elif "background" in kwargs: - self._fg_color = kwargs["background"] - bg_changed = True - kwargs["background"] = ThemeManager.single_color(self._fg_color, self._appearance_mode) - elif "fg_color" in kwargs: + def configure(self, **kwargs): + if "fg_color" in kwargs: self._fg_color = kwargs.pop("fg_color") - kwargs["bg"] = ThemeManager.single_color(self._fg_color, self._appearance_mode) - bg_changed = True - - elif len(args) > 0 and type(args[0]) == dict: - if "bg" in args[0]: - self._fg_color = args[0]["bg"] - bg_changed = True - args[0]["bg"] = ThemeManager.single_color(self._fg_color, self._appearance_mode) - elif "background" in args[0]: - self._fg_color = args[0]["background"] - bg_changed = True - args[0]["background"] = ThemeManager.single_color(self._fg_color, self._appearance_mode) - - if bg_changed: - from ..widgets.widget_base_class import CTkBaseClass + super().configure(bg=ThemeManager.single_color(self._fg_color, self._appearance_mode)) for child in self.winfo_children(): - if isinstance(child, CTkBaseClass) and hasattr(child, "_fg_color"): + try: child.configure(bg_color=self._fg_color) + except Exception: + pass - super().configure(*args, **kwargs) + super().configure(**pop_from_dict_by_set(kwargs, self._valid_tk_configure_arguments)) + check_kwargs_empty(kwargs) def cget(self, attribute_name: str) -> any: if attribute_name == "fg_color": diff --git a/customtkinter/windows/ctk_toplevel.py b/customtkinter/windows/ctk_toplevel.py index 54bab28..a00a10e 100644 --- a/customtkinter/windows/ctk_toplevel.py +++ b/customtkinter/windows/ctk_toplevel.py @@ -12,6 +12,8 @@ from ..theme_manager import ThemeManager from ..settings import Settings from ..scaling_tracker import ScalingTracker +from ..utility.utility_functions import pop_from_dict_by_set, check_kwargs_empty + class CTkToplevel(tkinter.Toplevel): """ @@ -19,12 +21,21 @@ class CTkToplevel(tkinter.Toplevel): For detailed information check out the documentation. """ + _valid_tk_toplevel_arguments = {"bd", "borderwidth", "class", "container", "cursor", "height", + "highlightbackground", "highlightthickness", "menu", "relief", + "screen", "takefocus", "use", "visual", "width"} + def __init__(self, *args, fg_color: Union[str, Tuple[str, str]] = "default_theme", **kwargs): self._enable_macos_dark_title_bar() - super().__init__(*args, **kwargs) + + super().__init__(*args, **pop_from_dict_by_set(kwargs, self._valid_tk_toplevel_arguments)) + check_kwargs_empty(kwargs, raise_error=True) + + # add set_appearance_mode method to callback list of AppearanceModeTracker for appearance mode changes + AppearanceModeTracker.add(self._set_appearance_mode, self) self._appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark" # add set_scaling method to callback list of ScalingTracker for automatic scaling changes @@ -41,13 +52,6 @@ class CTkToplevel(tkinter.Toplevel): self._fg_color = ThemeManager.theme["color"]["window_bg_color"] if fg_color == "default_theme" else fg_color - if "bg" in kwargs: - self._fg_color = kwargs.pop("bg") - elif "background" in kwargs: - self.fg_color = kwargs.pop("background") - - # add set_appearance_mode method to callback list of AppearanceModeTracker for appearance mode changes - AppearanceModeTracker.add(self._set_appearance_mode, self) super().configure(bg=ThemeManager.single_color(self._fg_color, self._appearance_mode)) super().title("CTkToplevel") @@ -195,40 +199,19 @@ class CTkToplevel(tkinter.Toplevel): self._current_height = height super().maxsize(self._apply_window_scaling(self._max_width), self._apply_window_scaling(self._max_height)) - def configure(self, *args, **kwargs): - bg_changed = False - - if "bg" in kwargs: - self._fg_color = kwargs["bg"] - bg_changed = True - kwargs["bg"] = ThemeManager.single_color(self._fg_color, self._appearance_mode) - elif "background" in kwargs: - self._fg_color = kwargs["background"] - bg_changed = True - kwargs["background"] = ThemeManager.single_color(self._fg_color, self._appearance_mode) - elif "fg_color" in kwargs: + def configure(self, **kwargs): + if "fg_color" in kwargs: self._fg_color = kwargs.pop("fg_color") - kwargs["bg"] = ThemeManager.single_color(self._fg_color, self._appearance_mode) - bg_changed = True - - elif len(args) > 0 and type(args[0]) == dict: - if "bg" in args[0]: - self._fg_color = args[0]["bg"] - bg_changed = True - args[0]["bg"] = ThemeManager.single_color(self._fg_color, self._appearance_mode) - elif "background" in args[0]: - self._fg_color = args[0]["background"] - bg_changed = True - args[0]["background"] = ThemeManager.single_color(self._fg_color, self._appearance_mode) - - if bg_changed: - from ..widgets.widget_base_class import CTkBaseClass + super().configure(bg=ThemeManager.single_color(self._fg_color, self._appearance_mode)) for child in self.winfo_children(): - if isinstance(child, CTkBaseClass) and hasattr(child, "_fg_color"): + try: child.configure(bg_color=self._fg_color) + except Exception: + pass - super().configure(*args, **kwargs) + super().configure(**pop_from_dict_by_set(kwargs, self._valid_tk_toplevel_arguments)) + check_kwargs_empty(kwargs) def cget(self, attribute_name: str) -> any: if attribute_name == "fg_color": diff --git a/examples/simple_example_standard_tkinter.py b/examples/simple_example_standard_tkinter.py index a5078e1..c39ef3e 100644 --- a/examples/simple_example_standard_tkinter.py +++ b/examples/simple_example_standard_tkinter.py @@ -5,7 +5,6 @@ app = tkinter.Tk() app.geometry("400x350") app.title("simple_example_standard_tkinter.py") - def button_function(): print("button pressed") diff --git a/test/manual_integration_tests/complex_example_new.py b/test/manual_integration_tests/complex_example_new.py index ae27408..1085911 100644 --- a/test/manual_integration_tests/complex_example_new.py +++ b/test/manual_integration_tests/complex_example_new.py @@ -138,6 +138,8 @@ class App(customtkinter.CTk): self.seg_button_1.configure(values=["CTkSegmentedButton", "Value 2", "Value 3"]) self.seg_button_1.set("Value 2") + self.attributes("-fullscreen", True) + def open_input_dialog(self): dialog = customtkinter.CTkInputDialog(master=self, text="Type in a number:", title="CTkInputDialog") print("CTkInputDialog:", dialog.get_input())