finished basic tabview mechanics

This commit is contained in:
Tom Schimansky 2022-10-14 01:15:35 +02:00
parent 7abdf21021
commit 6ba384eb0b
4 changed files with 122 additions and 34 deletions

View File

@ -61,7 +61,7 @@ class DrawEngine:
else: else:
return user_corner_radius return user_corner_radius
def draw_background_corners(self, width: Union[float, int], height: Union[float, int]): def draw_background_corners(self, width: Union[float, int], height: Union[float, int], ):
if self._round_width_to_even_numbers: if self._round_width_to_even_numbers:
width = math.floor(width / 2) * 2 # round (floor) _current_width and _current_height and restrict them to even values only width = math.floor(width / 2) * 2 # round (floor) _current_width and _current_height and restrict them to even values only
if self._round_height_to_even_numbers: if self._round_height_to_even_numbers:

View File

@ -325,10 +325,6 @@ class CTkSegmentedButton(CTkFrame):
return super().cget(attribute_name) return super().cget(attribute_name)
def set(self, value: str, from_variable_callback: bool = False, from_button_callback: bool = False): def set(self, value: str, from_variable_callback: bool = False, from_button_callback: bool = False):
if from_button_callback:
if self._command is not None:
self._command(self._current_value)
if value == self._current_value: if value == self._current_value:
return return
elif value in self._buttons_dict: elif value in self._buttons_dict:
@ -348,6 +344,10 @@ class CTkSegmentedButton(CTkFrame):
self._variable.set(value) self._variable.set(value)
self._variable_callback_blocked = False self._variable_callback_blocked = False
if from_button_callback:
if self._command is not None:
self._command(self._current_value)
def get(self) -> str: def get(self) -> str:
return self._current_value return self._current_value
@ -376,8 +376,16 @@ class CTkSegmentedButton(CTkFrame):
index_to_remove = self._get_index_by_value(value) index_to_remove = self._get_index_by_value(value)
self._value_list.pop(index_to_remove) self._value_list.pop(index_to_remove)
if index_to_remove <= len(self._buttons_dict) - 1: # removed index was outer right element
self._configure_button_corners_for_index(index_to_remove) if index_to_remove == len(self._buttons_dict) and len(self._buttons_dict) > 0:
self._configure_button_corners_for_index(index_to_remove - 1)
# removed index was outer left element
if index_to_remove == 0 and len(self._buttons_dict) > 0:
self._configure_button_corners_for_index(0)
#if index_to_remove <= len(self._buttons_dict) - 1:
# self._configure_button_corners_for_index(index_to_remove)
self._create_button_grid() self._create_button_grid()
else: else:

View File

@ -1,4 +1,4 @@
from typing import Union, Tuple, Dict, List from typing import Union, Tuple, Dict, List, Callable
from ..theme_manager import ThemeManager from ..theme_manager import ThemeManager
from .ctk_frame import CTkFrame from .ctk_frame import CTkFrame
@ -16,7 +16,7 @@ class CTkTabview(CTkBaseClass):
_top_spacing = 10 # px on top of the buttons _top_spacing = 10 # px on top of the buttons
_top_button_overhang = 8 # px _top_button_overhang = 8 # px
_button_height = 10 _button_height = 26
def __init__(self, def __init__(self,
master: any = None, master: any = None,
@ -38,6 +38,8 @@ class CTkTabview(CTkBaseClass):
text_color: Union[str, Tuple[str, str]] = "default_theme", text_color: Union[str, Tuple[str, str]] = "default_theme",
text_color_disabled: Union[str, Tuple[str, str]] = "default_theme", text_color_disabled: Union[str, Tuple[str, str]] = "default_theme",
command: Callable = None,
state: str = "normal",
**kwargs): **kwargs):
# transfer some functionality to CTkFrame # transfer some functionality to CTkFrame
@ -80,7 +82,9 @@ class CTkTabview(CTkBaseClass):
text_color=text_color, text_color=text_color,
text_color_disabled=text_color_disabled, text_color_disabled=text_color_disabled,
corner_radius=corner_radius, corner_radius=corner_radius,
border_width=self._apply_widget_scaling(3)) border_width=self._apply_widget_scaling(3),
command=self._segmented_button_callback,
state=state)
self._configure_segmented_button_background_corners() self._configure_segmented_button_background_corners()
self._configure_grid() self._configure_grid()
self._set_grid_canvas() self._set_grid_canvas()
@ -89,8 +93,18 @@ class CTkTabview(CTkBaseClass):
self._name_list: List[str] = [] # list of unique tab names in order of tabs self._name_list: List[str] = [] # list of unique tab names in order of tabs
self._current_name: str = "" self._current_name: str = ""
self._command = command
super().bind('<Configure>', self._update_dimensions_event) super().bind('<Configure>', self._update_dimensions_event)
def _segmented_button_callback(self, selected_name):
self._current_name = selected_name
self._grid_forget_all_tabs()
self._set_grid_tab_by_name(self._current_name)
if self._command is not None:
self._command()
def winfo_children(self) -> List[any]: def winfo_children(self) -> List[any]:
""" """
winfo_children of CTkTabview without canvas and segmented button widgets, winfo_children of CTkTabview without canvas and segmented button widgets,
@ -130,13 +144,15 @@ class CTkTabview(CTkBaseClass):
def _configure_tab_background_corners_by_name(self, name: str): def _configure_tab_background_corners_by_name(self, name: str):
""" needs to be called for changes in fg_color, bg_color, border_width """ """ needs to be called for changes in fg_color, bg_color, border_width """
if self._border_width == 0: # if self._border_width == 0:
if self._fg_color is not None: # if self._fg_color is not None:
self._tab_dict[name].configure(background_corner_colors=(self._fg_color, self._fg_color, self._bg_color, self._bg_color)) # self._tab_dict[name].configure(background_corner_colors=(self._fg_color, self._fg_color, self._bg_color, self._bg_color))
else: # else:
self._tab_dict[name].configure(background_corner_colors=(self._bg_color, self._bg_color, self._bg_color, self._bg_color)) # self._tab_dict[name].configure(background_corner_colors=(self._bg_color, self._bg_color, self._bg_color, self._bg_color))
else: # else:
self._tab_dict[name].configure(background_corner_colors=None) # self._tab_dict[name].configure(background_corner_colors=None)
self._tab_dict[name].configure(background_corner_colors=None)
def _configure_grid(self): def _configure_grid(self):
""" create 3 x 4 grid system """ """ create 3 x 4 grid system """
@ -157,12 +173,13 @@ class CTkTabview(CTkBaseClass):
def _set_grid_tab_by_name(self, name: str): def _set_grid_tab_by_name(self, name: str):
""" needs to be called for changes in corner_radius, border_width """ """ needs to be called for changes in corner_radius, border_width """
if self._border_width == 0: self._tab_dict[name].grid(row=3, column=0, sticky="nsew",
self._tab_dict[name].grid(row=3, column=0, sticky="nsew") padx=self._apply_widget_scaling(max(self._corner_radius, self._border_width)),
else: pady=self._apply_widget_scaling(max(self._corner_radius, self._border_width)))
self._tab_dict[name].grid(row=3, column=0, sticky="nsew",
padx=self._apply_widget_scaling(max(self._corner_radius, self._border_width)), def _grid_forget_all_tabs(self):
pady=self._apply_widget_scaling(max(self._corner_radius, self._border_width))) for frame in self._tab_dict.values():
frame.grid_forget()
def _create_tab(self) -> CTkFrame: def _create_tab(self) -> CTkFrame:
new_tab = CTkFrame(self, new_tab = CTkFrame(self,
@ -203,7 +220,7 @@ class CTkTabview(CTkBaseClass):
else: else:
raise ValueError(f"CTkTabview has no tab named '{name}'") raise ValueError(f"CTkTabview has no tab named '{name}'")
def insert(self, index: int, name: str): def insert(self, index: int, name: str) -> CTkFrame:
""" creates new tab with given name at position index """ """ creates new tab with given name at position index """
if name not in self._tab_dict: if name not in self._tab_dict:
@ -214,13 +231,63 @@ class CTkTabview(CTkBaseClass):
self._name_list.insert(index, name) self._name_list.insert(index, name)
self._tab_dict[name] = self._create_tab() self._tab_dict[name] = self._create_tab()
self._segmented_button.insert(index, name) self._segmented_button.insert(index, name)
self._configure_tab_background_corners_by_name(name)
# if created tab is only tab select this tab
if len(self._tab_dict) == 1:
self._current_name = name
self._segmented_button.set(self._current_name)
self._grid_forget_all_tabs()
self._set_grid_tab_by_name(self._current_name)
return self._tab_dict[name]
else: else:
raise ValueError(f"CTkTabview already has tab named '{name}'") raise ValueError(f"CTkTabview already has tab named '{name}'")
def add(self, name: str): def add(self, name: str) -> CTkFrame:
""" appends new tab with given name """ """ appends new tab with given name """
self.insert(len(self._tab_dict), name) return self.insert(len(self._tab_dict), name)
def delete(self, name: str): def delete(self, name: str):
""" deletes tab with given name """ """ delete tab by name """
return
if name in self._tab_dict:
self._name_list.remove(name)
self._tab_dict[name].grid_forget()
self._tab_dict.pop(name)
self._segmented_button.delete(name)
# set current_name to '' and remove segmented button if no tab is left
if len(self._name_list) == 0:
self._current_name = ""
self._segmented_button.grid_forget()
# if only one tab left, select this tab
elif len(self._name_list) == 1:
self._current_name = self._name_list[0]
self._segmented_button.set(self._current_name)
self._grid_forget_all_tabs()
self._set_grid_tab_by_name(self._current_name)
# more tabs are left
else:
# if current_name is deleted tab, select first tab at position 0
if self._current_name == name:
self.set(self._name_list[0])
else:
raise ValueError(f"CTkTabview has no tab named '{name}'")
def set(self, name: str):
""" select tab by name """
if name in self._tab_dict:
self._current_name = name
self._segmented_button.set(name)
self._grid_forget_all_tabs()
self._set_grid_tab_by_name(name)
else:
raise ValueError(f"CTkTabview has no tab named '{name}'")
def get(self) -> str:
""" returns name of selected tab, returns empty string if no tab selected """
return self._current_name

View File

@ -2,13 +2,26 @@ import customtkinter
app = customtkinter.CTk() app = customtkinter.CTk()
tabview_1 = customtkinter._CTkTabview(app) tabview_1 = customtkinter._CTkTabview(app, state="disabled")
tabview_1.pack(padx=20, pady=20) tabview_1.pack(padx=20, pady=20)
tabview_1.add("tab 1")
tabview_1.insert(0, "tab 0 g |ß$§ 😀")
app.update() tab_1 = tabview_1.add("tab 2")
tabview_1.insert(0, "tab 1")
tabview_1.add("tab 42")
tabview_1.set("tab 42")
tabview_1.delete("tab 42")
tabview_1.insert(0, "tab 42")
tabview_1.delete("tab 42")
tabview_1.insert(1, "tab 42")
tabview_1.delete("tab 42")
#b1 = customtkinter.CTkButton(master=tab_1, text="button tab 1")
#b1.pack(pady=20)
b2 = customtkinter.CTkButton(master=tabview_1.tab("tab 2"), text="button tab 2")
b2.pack()
tabview_1.tab("tab 2").configure(fg_color="red")
# tabview_1.delete("tab 1")
tabview_1._segmented_button._buttons_dict["tab 0 g |ß$§ 😀"]._text_label.configure(padx=0, pady=0, bd=1)
tabview_1._segmented_button._buttons_dict["tab 0 g |ß$§ 😀"]._text_label.configure(bg="red")
app.mainloop() app.mainloop()