mirror of
https://github.com/TomSchimansky/CustomTkinter.git
synced 2023-08-10 21:13:13 +03:00
finished basic tabview mechanics
This commit is contained in:
parent
7abdf21021
commit
6ba384eb0b
@ -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:
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
Loading…
Reference in New Issue
Block a user