diff --git a/customtkinter/__init__.py b/customtkinter/__init__.py index f760bd6..f656647 100644 --- a/customtkinter/__init__.py +++ b/customtkinter/__init__.py @@ -64,6 +64,7 @@ from .widgets.ctk_optionmenu import CTkOptionMenu from .widgets.ctk_combobox import CTkComboBox from .widgets.ctk_scrollbar import CTkScrollbar from .widgets.ctk_textbox import CTkTextbox +from .widgets.ctk_scrollbar_textbox import CTkScrolledTextbox # import windows from .windows.ctk_tk import CTk diff --git a/customtkinter/assets/themes/blue.json b/customtkinter/assets/themes/blue.json index 82de860..ba7404a 100644 --- a/customtkinter/assets/themes/blue.json +++ b/customtkinter/assets/themes/blue.json @@ -9,7 +9,7 @@ "entry": ["#F9F9FA", "#343638"], "entry_border": ["#979DA2", "#565B5E"], "entry_placeholder_text": ["gray52", "gray62"], - "frame_border": ["#979DA2", "#1F2122"], + "frame_border": ["#979DA2", "#565B5E"], "frame_low": ["#D1D5D8", "#2A2D2E"], "frame_high": ["#C0C2C5", "#343638"], "label": [null, null], diff --git a/customtkinter/widgets/ctk_scrollbar_textbox.py b/customtkinter/widgets/ctk_scrollbar_textbox.py new file mode 100644 index 0000000..02c4a2f --- /dev/null +++ b/customtkinter/widgets/ctk_scrollbar_textbox.py @@ -0,0 +1,452 @@ +import time +import tkinter +from typing import Union, Tuple + +from .ctk_canvas import CTkCanvas +from .ctk_scrollbar import CTkScrollbar +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 + + +class CTkScrolledTextbox(CTkBaseClass): + """ + Textbox with x and y scrollbars, rounded corners, and all text features of tkinter.Text widget. + Scrollbars only appear when they are needed. Text is wrapped on line end by default, + set wrap='none' to disable automatic line wrapping. + For detailed information check out the documentation. + + Detailed methods and parameters of the underlaying tkinter.Text widget can be found here: + https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/text.html + (most of them are implemented here too) + """ + + _scrollbar_update_time = 200 # interval in ms, to check if scrollbars are needed + _scrollbars_activated = True + + # attributes that are passed to and managed by the tkinter textbox only: + _valid_tk_text_attributes = {"autoseparators", "cursor", "exportselection", + "insertborderwidth", "insertofftime", "insertontime", "insertwidth", + "maxundo", "padx", "pady", "selectborderwidth", "spacing1", + "spacing2", "spacing3", "state", "tabs", "takefocus", "undo", "wrap", + "xscrollcommand", "yscrollcommand"} + + def __init__(self, *args, + width: int = 200, + height: int = 200, + corner_radius: Union[int, str] = "default_theme", + border_width: Union[int, str] = "default_theme", + + bg_color: Union[str, Tuple[str, str], None] = None, + fg_color: Union[str, Tuple[str, str], None] = "default_theme", + border_color: Union[str, Tuple[str, str]] = "default_theme", + text_color: Union[str, str] = "default_theme", + scrollbar_color: Union[str, Tuple[str, str]] = "default_theme", + scrollbar_hover_color: Union[str, Tuple[str, str]] = "default_theme", + + font: any = "default_theme", + **kwargs): + + # transfer basic functionality (_bg_color, size, _appearance_mode, scaling) to CTkBaseClass + if "master" in kwargs: + super().__init__(*args, bg_color=bg_color, width=width, height=height, master=kwargs.pop("master")) + else: + super().__init__(*args, bg_color=bg_color, width=width, height=height) + + # color + self._fg_color = ThemeManager.theme["color"]["entry"] if fg_color == "default_theme" else fg_color + self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color == "default_theme" else border_color + self._text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color + self._scrollbar_color = ThemeManager.theme["color"]["scrollbar_button"] if scrollbar_color == "default_theme" else scrollbar_color + self._scrollbar_hover_color = ThemeManager.theme["color"]["scrollbar_button_hover"] if scrollbar_hover_color == "default_theme" else scrollbar_hover_color + + # shape + self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius + self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width == "default_theme" else border_width + + # text + self._font = (ThemeManager.theme["text"]["font"], ThemeManager.theme["text"]["size"]) if font == "default_theme" else font + + self._canvas = CTkCanvas(master=self, + highlightthickness=0, + width=self._apply_widget_scaling(self._current_width), + height=self._apply_widget_scaling(self._current_height)) + self._canvas.grid(row=0, column=0, padx=0, pady=0, rowspan=2, columnspan=2, sticky="nsew") + self._canvas.configure(bg=ThemeManager.single_color(self._bg_color, self._appearance_mode)) + self._draw_engine = DrawEngine(self._canvas) + + self._textbox = tkinter.Text(self, + fg=ThemeManager.single_color(self._text_color, self._appearance_mode), + width=0, + height=0, + font=self._apply_font_scaling(self._font), + highlightthickness=0, + relief="flat", + insertbackground=ThemeManager.single_color(self._text_color, self._appearance_mode), + 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) + + self._y_scrollbar = CTkScrollbar(self, + width=8, + border_spacing=0, + fg_color=self._fg_color, + scrollbar_color=self._scrollbar_color, + scrollbar_hover_color=self._scrollbar_hover_color, + orientation="vertical", + command=self._textbox.yview) + self._textbox.configure(yscrollcommand=self._y_scrollbar.set) + self._y_scrollbar.grid(row=0, column=1, rowspan=1, columnspan=1, sticky="ns", + padx=(self._apply_widget_scaling(3), self._apply_widget_scaling(3 + self._border_width)), + pady=(self._apply_widget_scaling(self._corner_radius + self._border_width), 0)) + + self._x_scrollbar = CTkScrollbar(self, + height=8, + border_spacing=0, + fg_color=self._fg_color, + scrollbar_color=self._scrollbar_color, + scrollbar_hover_color=self._scrollbar_hover_color, + orientation="horizontal", + command=self._textbox.xview) + self._textbox.configure(xscrollcommand=self._x_scrollbar.set) + self._x_scrollbar.grid(row=1, column=0, rowspan=1, columnspan=1, sticky="ew", + pady=(self._apply_widget_scaling(3), self._apply_widget_scaling(3 + self._border_width)), + padx=(self._apply_widget_scaling(self._corner_radius + self._border_width), 0)) + + self._hide_x_scrollbar = True + self._hide_y_scrollbar = True + self._manage_grid_commands(re_grid_textbox=True, re_grid_x_scrollbar=True, re_grid_y_scrollbar=True) + + self.after(500, self._check_if_scrollbars_needed) + + super().bind('', self._update_dimensions_event) + self._draw() + + def _manage_grid_commands(self, re_grid_textbox=False, re_grid_x_scrollbar=False, re_grid_y_scrollbar=False): + + # configure 2x2 grid + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=0, minsize=self._apply_widget_scaling(max(self._corner_radius, self._border_width))) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=0, minsize=self._apply_widget_scaling(max(self._corner_radius, self._border_width))) + + if re_grid_textbox: + self._textbox.grid(row=0, column=0, rowspan=1, columnspan=1, sticky="nsew", + padx=(self._apply_widget_scaling(max(self._corner_radius, self._border_width)), 0), + pady=(self._apply_widget_scaling(max(self._corner_radius, self._border_width)), 0)) + + if re_grid_x_scrollbar: + if not self._hide_x_scrollbar: + self._x_scrollbar.grid(row=1, column=0, rowspan=1, columnspan=1, sticky="ew", + pady=(3, 3 + self._border_width), + padx=(max(self._corner_radius, self._border_width), 0)) # scrollbar grid method without scaling + else: + self._x_scrollbar.grid_forget() + + if re_grid_y_scrollbar: + if not self._hide_y_scrollbar: + self._y_scrollbar.grid(row=0, column=1, rowspan=1, columnspan=1, sticky="ns", + padx=(3, 3 + self._border_width), + pady=(max(self._corner_radius, self._border_width), 0)) # scrollbar grid method without scaling + else: + self._y_scrollbar.grid_forget() + + def _check_if_scrollbars_needed(self, event=None): + """ Method hides or places the scrollbars if they are needed on key release event of tkinter.text widget """ + + if self._textbox.xview() != (0.0, 1.0) and not self._x_scrollbar.winfo_ismapped(): # x scrollbar needed + self._hide_x_scrollbar = False + self._manage_grid_commands(re_grid_x_scrollbar=True) + elif self._textbox.xview() == (0.0, 1.0) and self._x_scrollbar.winfo_ismapped(): # x scrollbar not needed + self._hide_x_scrollbar = True + self._manage_grid_commands(re_grid_x_scrollbar=True) + + if self._textbox.yview() != (0.0, 1.0) and not self._y_scrollbar.winfo_ismapped(): # y scrollbar needed + self._hide_y_scrollbar = False + self._manage_grid_commands(re_grid_y_scrollbar=True) + elif self._textbox.yview() == (0.0, 1.0) and self._y_scrollbar.winfo_ismapped(): # y scrollbar not needed + self._hide_y_scrollbar = True + self._manage_grid_commands(re_grid_y_scrollbar=True) + + if self._textbox.winfo_exists(): + self.after(200, self._check_if_scrollbars_needed) + + def _set_scaling(self, *args, **kwargs): + super()._set_scaling(*args, **kwargs) + + self._textbox.configure(font=self._apply_font_scaling(self._font)) + self._canvas.configure(width=self._apply_widget_scaling(self._desired_width), + height=self._apply_widget_scaling(self._desired_height)) + self._manage_grid_commands(re_grid_textbox=False, re_grid_x_scrollbar=True, re_grid_y_scrollbar=True) + self._draw() + + def _set_dimensions(self, width=None, height=None): + super()._set_dimensions(width, height) + + self._canvas.configure(width=self._apply_widget_scaling(self._desired_width), + height=self._apply_widget_scaling(self._desired_height)) + self._draw() + + def _draw(self, no_color_updates=False): + + 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._corner_radius), + self._apply_widget_scaling(self._border_width)) + + if no_color_updates is False or requires_recoloring: + if self._fg_color is None: + self._canvas.itemconfig("inner_parts", + fill=ThemeManager.single_color(self._bg_color, self._appearance_mode), + outline=ThemeManager.single_color(self._bg_color, self._appearance_mode)) + self._textbox.configure(fg=ThemeManager.single_color(self._text_color, self._appearance_mode), + bg=ThemeManager.single_color(self._bg_color, self._appearance_mode), + insertbackground=ThemeManager.single_color(self._text_color, self._appearance_mode)) + self._x_scrollbar.configure(fg_color=self._bg_color, scrollbar_color=self._scrollbar_color, + scrollbar_hover_color=self._scrollbar_hover_color) + self._y_scrollbar.configure(fg_color=self._bg_color, scrollbar_color=self._scrollbar_color, + scrollbar_hover_color=self._scrollbar_hover_color) + else: + self._canvas.itemconfig("inner_parts", + fill=ThemeManager.single_color(self._fg_color, self._appearance_mode), + outline=ThemeManager.single_color(self._fg_color, self._appearance_mode)) + self._textbox.configure(fg=ThemeManager.single_color(self._text_color, self._appearance_mode), + bg=ThemeManager.single_color(self._fg_color, self._appearance_mode), + insertbackground=ThemeManager.single_color(self._text_color, self._appearance_mode)) + self._x_scrollbar.configure(fg_color=self._fg_color, scrollbar_color=self._scrollbar_color, + scrollbar_hover_color=self._scrollbar_hover_color) + self._y_scrollbar.configure(fg_color=self._fg_color, scrollbar_color=self._scrollbar_color, + scrollbar_hover_color=self._scrollbar_hover_color) + + self._canvas.itemconfig("border_parts", + fill=ThemeManager.single_color(self._border_color, self._appearance_mode), + outline=ThemeManager.single_color(self._border_color, self._appearance_mode)) + self._canvas.configure(bg=ThemeManager.single_color(self._bg_color, self._appearance_mode)) + + self._canvas.tag_lower("inner_parts") + self._canvas.tag_lower("border_parts") + + def configure(self, require_redraw=False, **kwargs): + if "fg_color" in kwargs: + self._fg_color = kwargs.pop("fg_color") + require_redraw = True + + # check if CTk widgets are children of the frame and change their _bg_color to new frame fg_color + for child in self.winfo_children(): + if isinstance(child, CTkBaseClass) and hasattr(child, "_fg_color"): + child.configure(bg_color=self._fg_color) + + if "border_color" in kwargs: + self._border_color = kwargs.pop("border_color") + require_redraw = True + + if "text_color" in kwargs: + self._text_color = kwargs.pop("text_color") + require_redraw = True + + if "corner_radius" in kwargs: + self._corner_radius = kwargs.pop("corner_radius") + self._manage_grid_commands(re_grid_textbox=True, re_grid_x_scrollbar=True, re_grid_y_scrollbar=True) + require_redraw = True + + if "border_width" in kwargs: + self._border_width = kwargs.pop("border_width") + self._manage_grid_commands(re_grid_textbox=True, re_grid_x_scrollbar=True, re_grid_y_scrollbar=True) + require_redraw = True + + if "width" in kwargs: + self._set_dimensions(width=kwargs.pop("width")) + + if "height" in kwargs: + self._set_dimensions(height=kwargs.pop("height")) + + if "font" in kwargs: + self._font = kwargs.pop("font") + self._textbox.configure(font=self._apply_font_scaling(self._font)) + + self._textbox.configure(**pop_from_dict_by_set(kwargs, self._valid_tk_text_attributes)) + super().configure(require_redraw=require_redraw, **kwargs) + + def cget(self, attribute_name: str) -> any: + if attribute_name == "corner_radius": + return self._corner_radius + elif attribute_name == "border_width": + return self._border_width + + elif attribute_name == "fg_color": + return self._fg_color + elif attribute_name == "border_color": + return self._border_color + elif attribute_name == "text_color": + return self._text_color + + elif attribute_name == "font": + return self._font + + else: + return super().cget(attribute_name) + + def bind(self, sequence=None, command=None, add=None): + """ called on the tkinter.Text """ + + # if sequence is , allow only to add the binding to keep the _textbox_modified_event() being called + if sequence == "": + return self._textbox.bind(sequence, command, add="+") + else: + return self._textbox.bind(sequence, command, add) + + def unbind(self, sequence, funcid=None): + """ called on the tkinter.Text """ + return self._textbox.unbind(sequence, funcid) + + def insert(self, index, text, tags=None): + self._check_if_scrollbars_needed() + return self._textbox.insert(index, text, tags) + + def get(self, index1, index2=None): + return self._textbox.get(index1, index2) + + def bbox(self, index): + return self._textbox.bbox(index) + + def compare(self, index, op, index2): + return self._textbox.compare(index, op, index2) + + def dlineinfo(self, index): + return self._textbox.dlineinfo(index) + + def edit_modified(self, arg=None): + return self._textbox.edit_modified(arg) + + def edit_redo(self): + self._check_if_scrollbars_needed() + return self._textbox.edit_redo() + + def edit_reset(self): + return self._textbox.edit_reset() + + def edit_separator(self): + return self._textbox.edit_separator() + + def edit_undo(self): + self._check_if_scrollbars_needed() + return self._textbox.edit_undo() + + def image_create(self, index, **kwargs): + raise AttributeError("embedding images is forbidden, because would be incompatible with scaling") + + def image_cget(self, index, option): + raise AttributeError("embedding images is forbidden, because would be incompatible with scaling") + + def image_configure(self, index): + raise AttributeError("embedding images is forbidden, because would be incompatible with scaling") + + def image_names(self): + raise AttributeError("embedding images is forbidden, because would be incompatible with scaling") + + def index(self, i): + return self._textbox.index(i) + + def mark_gravity(self, mark, gravity=None): + return self._textbox.mark_gravity(mark, gravity) + + def mark_names(self): + return self._textbox.mark_names() + + def mark_next(self, index): + return self._textbox.mark_next(index) + + def mark_previous(self, index): + return self._textbox.mark_previous(index) + + def mark_set(self, mark, index): + return self._textbox.mark_set(mark, index) + + def mark_unset(self, mark): + return self._textbox.mark_unset(mark) + + def scan_dragto(self, x, y): + return self._textbox.scan_dragto(x, y) + + def scan_mark(self, x, y): + return self._textbox.scan_mark(x, y) + + def search(self, pattern, index, *args, **kwargs): + return self._textbox.search(pattern, index, *args, **kwargs) + + def see(self, index): + return self._textbox.see(index) + + def tag_add(self, tagName, index1, index2=None): + return self._textbox.tag_add(tagName, index1, index2) + + def tag_bind(self, tagName, sequence, func, add=None): + return self._textbox.tag_bind(tagName, sequence, func, add) + + def tag_cget(self, tagName, option): + return self._textbox.tag_cget(tagName, option) + + def tag_config(self, tagName, **kwargs): + if "font" in kwargs: + raise AttributeError("'font' option forbidden, because would be incompatible with scaling") + return self._textbox.tag_config(tagName, **kwargs) + + def tag_delete(self, *tagName): + return self._textbox.tag_delete(*tagName) + + def tag_lower(self, tagName, belowThis=None): + return self._textbox.tag_lower(tagName, belowThis) + + def tag_names(self, index=None): + return self._textbox.tag_names(index) + + def tag_nextrange(self, tagName, index1, index2=None): + return self._textbox.tag_nextrange(tagName, index1, index2) + + def tag_prevrange(self, tagName, index1, index2=None): + return self._textbox.tag_prevrange(tagName, index1, index2) + + def tag_raise(self, tagName, aboveThis=None): + return self._textbox.tag_raise(tagName, aboveThis) + + def tag_ranges(self, tagName): + return self._textbox.tag_ranges(tagName) + + def tag_remove(self, tagName, index1, index2=None): + return self._textbox.tag_remove(tagName, index1, index2) + + def tag_unbind(self, tagName, sequence, funcid=None): + return self._textbox.tag_unbind(tagName, sequence, funcid) + + def window_cget(self, index, option): + raise AttributeError("embedding widgets is forbidden, would probably cause all kinds of problems ;)") + + def window_configure(self, index, option): + raise AttributeError("embedding widgets is forbidden, would probably cause all kinds of problems ;)") + + def window_create(self, index, **kwargs): + raise AttributeError("embedding widgets is forbidden, would probably cause all kinds of problems ;)") + + def window_names(self): + raise AttributeError("embedding widgets is forbidden, would probably cause all kinds of problems ;)") + + def xview(self, *args): + return self._textbox.xview(*args) + + def xview_moveto(self, fraction): + return self._textbox.xview_moveto(fraction) + + def xview_scroll(self, n, what): + return self._textbox.xview_scroll(n, what) + + def yview(self, *args): + return self._textbox.yview(*args) + + def yview_moveto(self, fraction): + return self._textbox.yview_moveto(fraction) + + def yview_scroll(self, n, what): + return self._textbox.yview_scroll(n, what) diff --git a/customtkinter/widgets/ctk_textbox.py b/customtkinter/widgets/ctk_textbox.py index ef4e5cc..d22228e 100644 --- a/customtkinter/widgets/ctk_textbox.py +++ b/customtkinter/widgets/ctk_textbox.py @@ -13,6 +13,10 @@ class CTkTextbox(CTkBaseClass): """ Textbox with rounded corners, and all text features of tkinter.Text widget. For detailed information check out the documentation. + + Detailed methods and parameters of the underlaying tkinter.Text widget can be found here: + https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/text.html + (most of them are implemented here too) """ # attributes that are passed to and managed by the tkinter textbox only: @@ -25,8 +29,8 @@ class CTkTextbox(CTkBaseClass): def __init__(self, *args, width: int = 200, height: int = 200, - corner_radius: Union[str, str] = "default_theme", - border_width: Union[str, str] = "default_theme", + corner_radius: Union[int, str] = "default_theme", + border_width: Union[int, str] = "default_theme", bg_color: Union[str, Tuple[str, str], None] = None, fg_color: Union[str, Tuple[str, str], None] = "default_theme", @@ -66,8 +70,6 @@ class CTkTextbox(CTkBaseClass): self._canvas.configure(bg=ThemeManager.single_color(self._bg_color, self._appearance_mode)) self._draw_engine = DrawEngine(self._canvas) - for arg in ["highlightthickness", "fg", "bg", "font", "width", "height"]: - kwargs.pop(arg, None) self._textbox = tkinter.Text(self, fg=ThemeManager.single_color(self._text_color, self._appearance_mode), width=0, diff --git a/customtkinter/widgets/widget_base_class.py b/customtkinter/widgets/widget_base_class.py index f167013..f7c5865 100644 --- a/customtkinter/widgets/widget_base_class.py +++ b/customtkinter/widgets/widget_base_class.py @@ -106,15 +106,27 @@ class CTkBaseClass(tkinter.Frame): def place(self, **kwargs): self._last_geometry_manager_call = {"function": super().place, "kwargs": kwargs} - super().place(**self._apply_argument_scaling(kwargs)) + return super().place(**self._apply_argument_scaling(kwargs)) + + def place_forget(self): + self._last_geometry_manager_call = None + return super().place_forget() def pack(self, **kwargs): self._last_geometry_manager_call = {"function": super().pack, "kwargs": kwargs} - super().pack(**self._apply_argument_scaling(kwargs)) + return super().pack(**self._apply_argument_scaling(kwargs)) + + def pack_forget(self): + self._last_geometry_manager_call = None + return super().pack_forget() def grid(self, **kwargs): self._last_geometry_manager_call = {"function": super().grid, "kwargs": kwargs} - super().grid(**self._apply_argument_scaling(kwargs)) + return super().grid(**self._apply_argument_scaling(kwargs)) + + def grid_forget(self): + self._last_geometry_manager_call = None + return super().grid_forget() def _apply_argument_scaling(self, kwargs: dict) -> dict: scaled_kwargs = copy.copy(kwargs) diff --git a/test/manual_integration_tests/complex_example_new.py b/test/manual_integration_tests/complex_example_new.py index 3b293bc..d360a6d 100644 --- a/test/manual_integration_tests/complex_example_new.py +++ b/test/manual_integration_tests/complex_example_new.py @@ -52,7 +52,7 @@ class App(customtkinter.CTk): self.main_button_1 = customtkinter.CTkButton(self, fg_color=None, border_width=2) self.main_button_1.grid(row=3, column=3, padx=(10, 20), pady=(10, 20), sticky="nsew") - self.textbox = customtkinter.CTkTextbox(self) + self.textbox = customtkinter.CTkScrolledTextbox(self) self.textbox.grid(row=0, column=1, padx=(20, 10), pady=(20, 10), sticky="nsew") # create radiobutton frame @@ -121,14 +121,14 @@ class App(customtkinter.CTk): self.scaling_optionemenu.set("100%") self.optionmenu_1.set("CTkOptionmenu") self.combobox_1.set("CTkComboBox") - self.textbox.insert("1.0", "CTkTextbox\n\nLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.") self.slider_1.configure(command=self.progressbar_2.set) self.slider_2.configure(command=self.progressbar_3.set) self.progressbar_1.configure(mode="indeterminnate") self.progressbar_1.start() - r = self.logo_label.bind("", lambda e: print("click")) - print(r, type(r)) + self.textbox.insert("1.0", "CTkTextbox\n\n" + "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.\n\n" * 20) + self.textbox.configure(border_width=5, corner_radius=20, wrap="none") + self.radiobutton_frame.configure(border_width=3) def open_input_dialog(self): dialog = customtkinter.CTkInputDialog(master=self, text="Type in a number:", title="CTkInputDialog") @@ -144,7 +144,6 @@ class App(customtkinter.CTk): def sidebar_button_callback(self): print("sidebar_button click") - self.entry.delete(0, tkinter.END) def on_closing(self, event=0): self.destroy() diff --git a/test/manual_integration_tests/test_scrollbar.py b/test/manual_integration_tests/test_scrollbar.py deleted file mode 100644 index d579911..0000000 --- a/test/manual_integration_tests/test_scrollbar.py +++ /dev/null @@ -1,54 +0,0 @@ -import tkinter -import customtkinter - -# test with scaling -# customtkinter.set_widget_scaling(2) -# customtkinter.set_window_scaling(2) -# customtkinter.set_spacing_scaling(2) - -customtkinter.set_appearance_mode("dark") - -app = customtkinter.CTk() -app.title("test_scrollbar.py") -app.grid_rowconfigure(0, weight=1) -app.grid_columnconfigure((0, 2), weight=1) - -tk_textbox = tkinter.Text(app, highlightthickness=0, padx=5, pady=5) -tk_textbox.grid(row=0, column=0, sticky="nsew") -ctk_textbox_scrollbar = customtkinter.CTkScrollbar(app, command=tk_textbox.yview) -ctk_textbox_scrollbar.grid(row=0, column=1, padx=0, sticky="ns") -tk_textbox.configure(yscrollcommand=ctk_textbox_scrollbar.set) - -frame_1 = customtkinter.CTkFrame(app) -frame_1.grid(row=0, column=2, padx=10, pady=10, sticky="nsew") -frame_1.grid_rowconfigure((0, 1), weight=1) -frame_1.grid_columnconfigure((0, ), weight=1) -tk_textbox_1 = tkinter.Text(frame_1, highlightthickness=0, padx=5, pady=5) -tk_textbox_1.grid(row=0, column=0, sticky="nsew", padx=(5, 0), pady=5) -ctk_textbox_scrollbar_1 = customtkinter.CTkScrollbar(frame_1, command=tk_textbox_1.yview) -ctk_textbox_scrollbar_1.grid(row=0, column=1, sticky="ns", padx=(0, 5), pady=5) -tk_textbox_1.configure(yscrollcommand=ctk_textbox_scrollbar_1.set) -ctk_textbox_scrollbar_1.configure(scrollbar_color="red", scrollbar_hover_color="darkred", - border_spacing=0, width=12, fg_color="green", corner_radius=4) - -frame_2 = customtkinter.CTkFrame(frame_1) -frame_2.grid(row=1, column=0, columnspan=2, padx=20, pady=20, sticky="nsew") -frame_2.grid_rowconfigure((0, ), weight=1) -frame_2.grid_columnconfigure((0, ), weight=1) -tk_textbox_2 = tkinter.Text(frame_2, highlightthickness=0, padx=5, pady=5, wrap="none") -tk_textbox_2.grid(row=0, column=0, sticky="nsew", padx=(5, 0), pady=5) -ctk_textbox_scrollbar_2 = customtkinter.CTkScrollbar(frame_2, command=tk_textbox_2.yview) -ctk_textbox_scrollbar_2.grid(row=0, column=1, sticky="ns", padx=(0, 5), pady=5) -ctk_textbox_scrollbar_2_horizontal = customtkinter.CTkScrollbar(frame_2, command=tk_textbox_2.xview, orientation="horizontal") -ctk_textbox_scrollbar_2_horizontal.grid(row=1, column=0, sticky="ew", padx=(5, 0), pady=(0, 5)) -tk_textbox_2.configure(yscrollcommand=ctk_textbox_scrollbar_2.set, xscrollcommand=ctk_textbox_scrollbar_2_horizontal.set) - -tk_textbox.configure(font=(customtkinter.ThemeManager.theme["text"]["font"], customtkinter.ThemeManager.theme["text"]["size"])) -tk_textbox_1.configure(font=(customtkinter.ThemeManager.theme["text"]["font"], customtkinter.ThemeManager.theme["text"]["size"])) -tk_textbox_2.configure(font=(customtkinter.ThemeManager.theme["text"]["font"], customtkinter.ThemeManager.theme["text"]["size"])) - -tk_textbox.insert("insert", "\n".join([str(i) for i in range(100)])) -tk_textbox_1.insert("insert", "\n".join([str(i) for i in range(1000)])) -tk_textbox_2.insert("insert", "\n".join([str(i) + " - "*30 for i in range(10000)])) - -app.mainloop() diff --git a/test/manual_integration_tests/test_textbox.py b/test/manual_integration_tests/test_textbox.py index f9a5bd0..b3ce372 100644 --- a/test/manual_integration_tests/test_textbox.py +++ b/test/manual_integration_tests/test_textbox.py @@ -1,54 +1,28 @@ -import tkinter import customtkinter -# test with scaling -# customtkinter.set_widget_scaling(2) -# customtkinter.set_window_scaling(2) -# customtkinter.set_spacing_scaling(2) +#customtkinter.set_widget_scaling(2) +#customtkinter.set_window_scaling(2) +#customtkinter.set_spacing_scaling(2) customtkinter.set_appearance_mode("dark") app = customtkinter.CTk() app.title("test_scrollbar.py") app.grid_rowconfigure(0, weight=1) -app.grid_columnconfigure((0, 2), weight=1) +app.grid_columnconfigure((0, 1), weight=1) -tk_textbox = customtkinter.CTkTextbox(app, highlightthickness=0, padx=5, pady=5) -tk_textbox.grid(row=0, column=0, sticky="nsew") -ctk_textbox_scrollbar = customtkinter.CTkScrollbar(app, command=tk_textbox.yview) -ctk_textbox_scrollbar.grid(row=0, column=1, padx=0, sticky="ns") -tk_textbox.configure(yscrollcommand=ctk_textbox_scrollbar.set) +textbox_1 = customtkinter.CTkScrolledTextbox(app, fg_color=None, corner_radius=0) +textbox_1.grid(row=0, column=0, sticky="nsew") +textbox_1.insert("0.0", "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.\n\n" * 20) -frame_1 = customtkinter.CTkFrame(app) -frame_1.grid(row=0, column=2, padx=10, pady=10, sticky="nsew") +frame_1 = customtkinter.CTkFrame(app, corner_radius=0) +frame_1.grid(row=0, column=1, sticky="nsew") frame_1.grid_rowconfigure((0, 1), weight=1) -frame_1.grid_columnconfigure((0, ), weight=1) -tk_textbox_1 = customtkinter.CTkTextbox(frame_1, highlightthickness=0, padx=5, pady=5) -tk_textbox_1.grid(row=0, column=0, sticky="nsew", padx=(5, 0), pady=5) -ctk_textbox_scrollbar_1 = customtkinter.CTkScrollbar(frame_1, command=tk_textbox_1.yview) -ctk_textbox_scrollbar_1.grid(row=0, column=1, sticky="ns", padx=(0, 5), pady=5) -tk_textbox_1.configure(yscrollcommand=ctk_textbox_scrollbar_1.set) -ctk_textbox_scrollbar_1.configure(scrollbar_color="red", scrollbar_hover_color="darkred", - border_spacing=0, width=12, fg_color="green", corner_radius=4) +frame_1.grid_columnconfigure(0, weight=1) -frame_2 = customtkinter.CTkFrame(frame_1) -frame_2.grid(row=1, column=0, columnspan=2, padx=20, pady=20, sticky="nsew") -frame_2.grid_rowconfigure((0, ), weight=1) -frame_2.grid_columnconfigure((0, ), weight=1) -tk_textbox_2 = customtkinter.CTkTextbox(frame_2, highlightthickness=0, padx=5, pady=5, wrap="none") -tk_textbox_2.grid(row=0, column=0, sticky="nsew", padx=(5, 0), pady=5) -ctk_textbox_scrollbar_2 = customtkinter.CTkScrollbar(frame_2, command=tk_textbox_2.yview) -ctk_textbox_scrollbar_2.grid(row=0, column=1, sticky="ns", padx=(0, 5), pady=5) -ctk_textbox_scrollbar_2_horizontal = customtkinter.CTkScrollbar(frame_2, command=tk_textbox_2.xview, orientation="horizontal") -ctk_textbox_scrollbar_2_horizontal.grid(row=1, column=0, sticky="ew", padx=(5, 0), pady=(0, 5)) -tk_textbox_2.configure(yscrollcommand=ctk_textbox_scrollbar_2.set, xscrollcommand=ctk_textbox_scrollbar_2_horizontal.set) +textbox_2 = customtkinter.CTkScrolledTextbox(frame_1, wrap="none") +textbox_2.grid(row=0, column=0, sticky="nsew", padx=20, pady=20) +textbox_2.insert("0.0", "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.\n\n" * 20) -tk_textbox.configure(font=(customtkinter.ThemeManager.theme["text"]["font"], customtkinter.ThemeManager.theme["text"]["size"])) -tk_textbox_1.configure(font=(customtkinter.ThemeManager.theme["text"]["font"], customtkinter.ThemeManager.theme["text"]["size"])) -tk_textbox_2.configure(font=(customtkinter.ThemeManager.theme["text"]["font"], customtkinter.ThemeManager.theme["text"]["size"])) - -tk_textbox.insert("insert", "\n".join([str(i) for i in range(100)])) -tk_textbox_1.insert("insert", "\n".join([str(i) for i in range(1000)])) -tk_textbox_2.insert("insert", "\n".join([str(i) + " - "*30 for i in range(10000)])) app.mainloop()