7 Commits

10 changed files with 147 additions and 56 deletions

View File

@ -10,7 +10,7 @@
![PyPI](https://img.shields.io/pypi/v/customtkinter) ![PyPI](https://img.shields.io/pypi/v/customtkinter)
![PyPI - Downloads](https://img.shields.io/pypi/dm/customtkinter?color=green&label=downloads) ![PyPI - Downloads](https://img.shields.io/pypi/dm/customtkinter?color=green&label=downloads)
![Downloads](https://static.pepy.tech/personalized-badge/customtkinter?period=total&units=international_system&left_color=grey&right_color=green&left_text=downloads) ![Downloads](https://static.pepy.tech/personalized-badge/customtkinter?period=total&units=international_system&left_color=grey&right_color=green&left_text=downloads)
![PyPI - License](https://img.shields.io/pypi/l/customtkinter) ![PyPI - License](https://img.shields.io/badge/license_MIT)
![](https://tokei.rs/b1/github/tomschimansky/customtkinter) ![](https://tokei.rs/b1/github/tomschimansky/customtkinter)
</div> </div>

View File

@ -5,6 +5,7 @@ from .widgets import CTkEntry
from .widgets import CTkButton from .widgets import CTkButton
from .widgets.theme import ThemeManager from .widgets.theme import ThemeManager
from .ctk_toplevel import CTkToplevel from .ctk_toplevel import CTkToplevel
from .widgets.font import CTkFont
class CTkInputDialog(CTkToplevel): class CTkInputDialog(CTkToplevel):
@ -24,6 +25,7 @@ class CTkInputDialog(CTkToplevel):
entry_text_color: Optional[Union[str, Tuple[str, str]]] = None, entry_text_color: Optional[Union[str, Tuple[str, str]]] = None,
title: str = "CTkDialog", title: str = "CTkDialog",
font: Optional[Union[tuple, CTkFont]] = None,
text: str = "CTkDialog"): text: str = "CTkDialog"):
super().__init__(fg_color=fg_color) super().__init__(fg_color=fg_color)
@ -39,9 +41,11 @@ class CTkInputDialog(CTkToplevel):
self._user_input: Union[str, None] = None self._user_input: Union[str, None] = None
self._running: bool = False self._running: bool = False
self._title = title
self._text = text self._text = text
self._font = font
self.title(title) self.title(self._title)
self.lift() # lift window on top self.lift() # lift window on top
self.attributes("-topmost", True) # stay on top self.attributes("-topmost", True) # stay on top
self.protocol("WM_DELETE_WINDOW", self._on_closing) self.protocol("WM_DELETE_WINDOW", self._on_closing)
@ -50,7 +54,6 @@ class CTkInputDialog(CTkToplevel):
self.grab_set() # make other windows not clickable self.grab_set() # make other windows not clickable
def _create_widgets(self): def _create_widgets(self):
self.grid_columnconfigure((0, 1), weight=1) self.grid_columnconfigure((0, 1), weight=1)
self.rowconfigure(0, weight=1) self.rowconfigure(0, weight=1)
@ -59,14 +62,16 @@ class CTkInputDialog(CTkToplevel):
wraplength=300, wraplength=300,
fg_color="transparent", fg_color="transparent",
text_color=self._text_color, text_color=self._text_color,
text=self._text,) text=self._text,
font=self._font)
self._label.grid(row=0, column=0, columnspan=2, padx=20, pady=20, sticky="ew") self._label.grid(row=0, column=0, columnspan=2, padx=20, pady=20, sticky="ew")
self._entry = CTkEntry(master=self, self._entry = CTkEntry(master=self,
width=230, width=230,
fg_color=self._entry_fg_color, fg_color=self._entry_fg_color,
border_color=self._entry_border_color, border_color=self._entry_border_color,
text_color=self._entry_text_color) text_color=self._entry_text_color,
font=self._font)
self._entry.grid(row=1, column=0, columnspan=2, padx=20, pady=(0, 20), sticky="ew") self._entry.grid(row=1, column=0, columnspan=2, padx=20, pady=(0, 20), sticky="ew")
self._ok_button = CTkButton(master=self, self._ok_button = CTkButton(master=self,
@ -76,6 +81,7 @@ class CTkInputDialog(CTkToplevel):
hover_color=self._button_hover_color, hover_color=self._button_hover_color,
text_color=self._button_text_color, text_color=self._button_text_color,
text='Ok', text='Ok',
font=self._font,
command=self._ok_event) command=self._ok_event)
self._ok_button.grid(row=2, column=0, columnspan=1, padx=(20, 10), pady=(0, 20), sticky="ew") self._ok_button.grid(row=2, column=0, columnspan=1, padx=(20, 10), pady=(0, 20), sticky="ew")
@ -86,6 +92,7 @@ class CTkInputDialog(CTkToplevel):
hover_color=self._button_hover_color, hover_color=self._button_hover_color,
text_color=self._button_text_color, text_color=self._button_text_color,
text='Cancel', text='Cancel',
font=self._font,
command=self._cancel_event) command=self._cancel_event)
self._cancel_button.grid(row=2, column=1, columnspan=1, padx=(10, 20), pady=(0, 20), sticky="ew") self._cancel_button.grid(row=2, column=1, columnspan=1, padx=(10, 20), pady=(0, 20), sticky="ew")

View File

@ -1,4 +1,5 @@
import tkinter import tkinter
import tkinterDnD
from distutils.version import StrictVersion as Version from distutils.version import StrictVersion as Version
import sys import sys
import os import os
@ -12,8 +13,10 @@ from .widgets.appearance_mode import CTkAppearanceModeBaseClass
from customtkinter.windows.widgets.utility.utility_functions import pop_from_dict_by_set, check_kwargs_empty from customtkinter.windows.widgets.utility.utility_functions import pop_from_dict_by_set, check_kwargs_empty
TK_CLASS = tkinterDnD.Tk
class CTk(tkinter.Tk, CTkAppearanceModeBaseClass, CTkScalingBaseClass):
class CTk(TK_CLASS, CTkAppearanceModeBaseClass, CTkScalingBaseClass):
""" """
Main app window with dark titlebar on Windows and macOS. Main app window with dark titlebar on Windows and macOS.
For detailed information check out the documentation. For detailed information check out the documentation.
@ -35,7 +38,7 @@ class CTk(tkinter.Tk, CTkAppearanceModeBaseClass, CTkScalingBaseClass):
self._enable_macos_dark_title_bar() self._enable_macos_dark_title_bar()
# call init methods of super classes # call init methods of super classes
tkinter.Tk.__init__(self, **pop_from_dict_by_set(kwargs, self._valid_tk_constructor_arguments)) TK_CLASS.__init__(self, **pop_from_dict_by_set(kwargs, self._valid_tk_constructor_arguments))
CTkAppearanceModeBaseClass.__init__(self) CTkAppearanceModeBaseClass.__init__(self)
CTkScalingBaseClass.__init__(self, scaling_type="window") CTkScalingBaseClass.__init__(self, scaling_type="window")
check_kwargs_empty(kwargs, raise_error=True) check_kwargs_empty(kwargs, raise_error=True)

View File

@ -383,6 +383,9 @@ class CTkSegmentedButton(CTkFrame):
def get(self) -> str: def get(self) -> str:
return self._current_value return self._current_value
def index(self, value: str) -> int:
return self._value_list.index(value)
def insert(self, index: int, value: str): def insert(self, index: int, value: str):
if value not in self._buttons_dict: if value not in self._buttons_dict:
if value != "": if value != "":

View File

@ -199,15 +199,30 @@ class CTkSlider(CTkBaseClass):
outline=self._apply_appearance_mode(self._button_color)) outline=self._apply_appearance_mode(self._button_color))
def configure(self, require_redraw=False, **kwargs): def configure(self, require_redraw=False, **kwargs):
if "state" in kwargs: if "corner_radius" in kwargs:
self._state = kwargs.pop("state") self._corner_radius = kwargs.pop("corner_radius")
self._set_cursor() require_redraw = True
if "button_corner_radius" in kwargs:
self._button_corner_radius = kwargs.pop("button_corner_radius")
require_redraw = True
if "border_width" in kwargs:
self._border_width = kwargs.pop("border_width")
require_redraw = True
if "button_length" in kwargs:
self._button_length = kwargs.pop("button_length")
require_redraw = True require_redraw = True
if "fg_color" in kwargs: if "fg_color" in kwargs:
self._fg_color = self._check_color_type(kwargs.pop("fg_color")) self._fg_color = self._check_color_type(kwargs.pop("fg_color"))
require_redraw = True require_redraw = True
if "border_color" in kwargs:
self._border_color = self._check_color_type(kwargs.pop("border_color"), transparency=True)
require_redraw = True
if "progress_color" in kwargs: if "progress_color" in kwargs:
self._progress_color = self._check_color_type(kwargs.pop("progress_color"), transparency=True) self._progress_color = self._check_color_type(kwargs.pop("progress_color"), transparency=True)
require_redraw = True require_redraw = True
@ -220,20 +235,17 @@ class CTkSlider(CTkBaseClass):
self._button_hover_color = self._check_color_type(kwargs.pop("button_hover_color")) self._button_hover_color = self._check_color_type(kwargs.pop("button_hover_color"))
require_redraw = True require_redraw = True
if "border_color" in kwargs:
self._border_color = self._check_color_type(kwargs.pop("border_color"), transparency=True)
require_redraw = True
if "border_width" in kwargs:
self._border_width = kwargs.pop("border_width")
require_redraw = True
if "from_" in kwargs: if "from_" in kwargs:
self._from_ = kwargs.pop("from_") self._from_ = kwargs.pop("from_")
if "to" in kwargs: if "to" in kwargs:
self._to = kwargs.pop("to") self._to = kwargs.pop("to")
if "state" in kwargs:
self._state = kwargs.pop("state")
self._set_cursor()
require_redraw = True
if "number_of_steps" in kwargs: if "number_of_steps" in kwargs:
self._number_of_steps = kwargs.pop("number_of_steps") self._number_of_steps = kwargs.pop("number_of_steps")
@ -255,6 +267,10 @@ class CTkSlider(CTkBaseClass):
else: else:
self._variable = None self._variable = None
if "orientation" in kwargs:
self._orientation = kwargs.pop("orientation")
require_redraw = True
super().configure(require_redraw=require_redraw, **kwargs) super().configure(require_redraw=require_redraw, **kwargs)
def cget(self, attribute_name: str) -> any: def cget(self, attribute_name: str) -> any:

View File

@ -15,8 +15,8 @@ class CTkTabview(CTkBaseClass):
For detailed information check out the documentation. For detailed information check out the documentation.
""" """
_top_spacing: int = 10 # px on top of the buttons _outer_spacing: int = 10 # px on top or below the button
_top_button_overhang: int = 8 # px _outer_button_overhang: int = 8 # px
_button_height: int = 26 _button_height: int = 26
_segmented_button_border_width: int = 3 _segmented_button_border_width: int = 3
@ -41,6 +41,7 @@ class CTkTabview(CTkBaseClass):
text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None, text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
command: Union[Callable, None] = None, command: Union[Callable, None] = None,
anchor: str = "center",
state: str = "normal", state: str = "normal",
**kwargs): **kwargs):
@ -65,12 +66,13 @@ class CTkTabview(CTkBaseClass):
# shape # shape
self._corner_radius = ThemeManager.theme["CTkFrame"]["corner_radius"] if corner_radius is None else corner_radius self._corner_radius = ThemeManager.theme["CTkFrame"]["corner_radius"] if corner_radius is None else corner_radius
self._border_width = ThemeManager.theme["CTkFrame"]["border_width"] if border_width is None else border_width self._border_width = ThemeManager.theme["CTkFrame"]["border_width"] if border_width is None else border_width
self._anchor = anchor
self._canvas = CTkCanvas(master=self, self._canvas = CTkCanvas(master=self,
bg=self._apply_appearance_mode(self._bg_color), bg=self._apply_appearance_mode(self._bg_color),
highlightthickness=0, highlightthickness=0,
width=self._apply_widget_scaling(self._desired_width), width=self._apply_widget_scaling(self._desired_width),
height=self._apply_widget_scaling(self._desired_height - self._top_spacing - self._top_button_overhang)) height=self._apply_widget_scaling(self._desired_height - self._outer_spacing - self._outer_button_overhang))
self._draw_engine = DrawEngine(self._canvas) self._draw_engine = DrawEngine(self._canvas)
self._segmented_button = CTkSegmentedButton(self, self._segmented_button = CTkSegmentedButton(self,
@ -99,9 +101,9 @@ class CTkTabview(CTkBaseClass):
self._draw() self._draw()
def _segmented_button_callback(self, selected_name): def _segmented_button_callback(self, selected_name):
self._set_grid_tab_by_name(selected_name)
self._tab_dict[self._current_name].grid_forget() self._tab_dict[self._current_name].grid_forget()
self._current_name = selected_name self._current_name = selected_name
self._set_grid_current_tab()
if self._command is not None: if self._command is not None:
self._command() self._command()
@ -124,7 +126,7 @@ class CTkTabview(CTkBaseClass):
super()._set_scaling(*args, **kwargs) super()._set_scaling(*args, **kwargs)
self._canvas.configure(width=self._apply_widget_scaling(self._desired_width), self._canvas.configure(width=self._apply_widget_scaling(self._desired_width),
height=self._apply_widget_scaling(self._desired_height - self._top_spacing - self._top_button_overhang)) height=self._apply_widget_scaling(self._desired_height - self._outer_spacing - self._outer_button_overhang))
self._configure_grid() self._configure_grid()
self._draw(no_color_updates=True) self._draw(no_color_updates=True)
@ -132,44 +134,62 @@ class CTkTabview(CTkBaseClass):
super()._set_dimensions(width, height) super()._set_dimensions(width, height)
self._canvas.configure(width=self._apply_widget_scaling(self._desired_width), self._canvas.configure(width=self._apply_widget_scaling(self._desired_width),
height=self._apply_widget_scaling(self._desired_height - self._top_spacing - self._top_button_overhang)) height=self._apply_widget_scaling(self._desired_height - self._outer_spacing - self._outer_button_overhang))
self._draw() self._draw()
def _configure_segmented_button_background_corners(self): def _configure_segmented_button_background_corners(self):
""" needs to be called for changes in fg_color, bg_color """ """ needs to be called for changes in fg_color, bg_color """
if self._fg_color is not None: if self._fg_color == "transparent":
self._segmented_button.configure(background_corner_colors=(self._bg_color, self._bg_color, self._fg_color, self._fg_color))
else:
self._segmented_button.configure(background_corner_colors=(self._bg_color, self._bg_color, self._bg_color, self._bg_color)) self._segmented_button.configure(background_corner_colors=(self._bg_color, self._bg_color, self._bg_color, self._bg_color))
else:
def _configure_tab_background_corners_by_name(self, name: str): if self._anchor.lower() in ("center", "w", "nw", "n", "ne", "e", "e"):
""" needs to be called for changes in fg_color, bg_color, border_width """ self._segmented_button.configure(background_corner_colors=(self._bg_color, self._bg_color, self._fg_color, self._fg_color))
else:
self._tab_dict[name].configure(background_corner_colors=None) self._segmented_button.configure(background_corner_colors=(self._fg_color, self._fg_color, self._bg_color, self._bg_color))
def _configure_grid(self): def _configure_grid(self):
""" create 3 x 4 grid system """ """ create 3 x 4 grid system """
self.grid_rowconfigure(0, weight=0, minsize=self._apply_widget_scaling(self._top_spacing)) if self._anchor.lower() in ("center", "w", "nw", "n", "ne", "e", "e"):
self.grid_rowconfigure(1, weight=0, minsize=self._apply_widget_scaling(self._top_button_overhang)) self.grid_rowconfigure(0, weight=0, minsize=self._apply_widget_scaling(self._outer_spacing))
self.grid_rowconfigure(2, weight=0, minsize=self._apply_widget_scaling(self._button_height - self._top_button_overhang)) self.grid_rowconfigure(1, weight=0, minsize=self._apply_widget_scaling(self._outer_button_overhang))
self.grid_rowconfigure(3, weight=1) self.grid_rowconfigure(2, weight=0, minsize=self._apply_widget_scaling(self._button_height - self._outer_button_overhang))
self.grid_rowconfigure(3, weight=1)
else:
self.grid_rowconfigure(0, weight=1)
self.grid_rowconfigure(1, weight=0, minsize=self._apply_widget_scaling(self._button_height - self._outer_button_overhang))
self.grid_rowconfigure(2, weight=0, minsize=self._apply_widget_scaling(self._outer_button_overhang))
self.grid_rowconfigure(3, weight=0, minsize=self._apply_widget_scaling(self._outer_spacing))
self.grid_columnconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1)
def _set_grid_canvas(self): def _set_grid_canvas(self):
self._canvas.grid(row=2, rowspan=2, column=0, columnspan=1, sticky="nsew") if self._anchor.lower() in ("center", "w", "nw", "n", "ne", "e", "e"):
self._canvas.grid(row=2, rowspan=2, column=0, columnspan=1, sticky="nsew")
else:
self._canvas.grid(row=0, rowspan=2, column=0, columnspan=1, sticky="nsew")
def _set_grid_segmented_button(self): def _set_grid_segmented_button(self):
""" needs to be called for changes in corner_radius """ """ needs to be called for changes in corner_radius, anchor """
self._segmented_button.grid(row=1, rowspan=2, column=0, columnspan=1, padx=self._apply_widget_scaling(self._corner_radius), sticky="ns")
def _set_grid_tab_by_name(self, name: str): if self._anchor.lower() in ("center", "n", "s"):
self._segmented_button.grid(row=1, rowspan=2, column=0, columnspan=1, padx=self._apply_widget_scaling(self._corner_radius), sticky="ns")
elif self._anchor.lower() in ("nw", "w", "sw"):
self._segmented_button.grid(row=1, rowspan=2, column=0, columnspan=1, padx=self._apply_widget_scaling(self._corner_radius), sticky="nsw")
elif self._anchor.lower() in ("ne", "e", "se"):
self._segmented_button.grid(row=1, rowspan=2, column=0, columnspan=1, padx=self._apply_widget_scaling(self._corner_radius), sticky="nse")
def _set_grid_current_tab(self):
""" needs to be called for changes in corner_radius, border_width """ """ needs to be called for changes in corner_radius, border_width """
self._tab_dict[name].grid(row=3, column=0, sticky="nsew", if self._anchor.lower() in ("center", "w", "nw", "n", "ne", "e", "e"):
padx=self._apply_widget_scaling(max(self._corner_radius, self._border_width)), self._tab_dict[self._current_name].grid(row=3, column=0, sticky="nsew",
pady=self._apply_widget_scaling(max(self._corner_radius, self._border_width))) padx=self._apply_widget_scaling(max(self._corner_radius, self._border_width)),
pady=self._apply_widget_scaling(max(self._corner_radius, self._border_width)))
else:
self._tab_dict[self._current_name].grid(row=0, column=0, sticky="nsew",
padx=self._apply_widget_scaling(max(self._corner_radius, self._border_width)),
pady=self._apply_widget_scaling(max(self._corner_radius, self._border_width)))
def _grid_forget_all_tabs(self, exclude_name=None): def _grid_forget_all_tabs(self, exclude_name=None):
for name, frame in self._tab_dict.items(): for name, frame in self._tab_dict.items():
@ -180,9 +200,16 @@ class CTkTabview(CTkBaseClass):
new_tab = CTkFrame(self, new_tab = CTkFrame(self,
height=0, height=0,
width=0, width=0,
fg_color=self._fg_color,
border_width=0, border_width=0,
corner_radius=self._corner_radius) corner_radius=0)
if self._fg_color == "transparent":
new_tab.configure(fg_color=self._apply_appearance_mode(self._bg_color),
bg_color=self._apply_appearance_mode(self._bg_color))
else:
new_tab.configure(fg_color=self._apply_appearance_mode(self._fg_color),
bg_color=self._apply_appearance_mode(self._fg_color))
return new_tab return new_tab
def _draw(self, no_color_updates: bool = False): def _draw(self, no_color_updates: bool = False):
@ -192,7 +219,7 @@ class CTkTabview(CTkBaseClass):
return return
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._top_spacing - self._top_button_overhang), self._apply_widget_scaling(self._current_height - self._outer_spacing - self._outer_button_overhang),
self._apply_widget_scaling(self._corner_radius), self._apply_widget_scaling(self._corner_radius),
self._apply_widget_scaling(self._border_width)) self._apply_widget_scaling(self._border_width))
@ -201,27 +228,37 @@ class CTkTabview(CTkBaseClass):
self._canvas.itemconfig("inner_parts", self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._bg_color), fill=self._apply_appearance_mode(self._bg_color),
outline=self._apply_appearance_mode(self._bg_color)) outline=self._apply_appearance_mode(self._bg_color))
for tab in self._tab_dict.values():
tab.configure(fg_color=self._apply_appearance_mode(self._bg_color),
bg_color=self._apply_appearance_mode(self._bg_color))
else: else:
self._canvas.itemconfig("inner_parts", self._canvas.itemconfig("inner_parts",
fill=self._apply_appearance_mode(self._fg_color), fill=self._apply_appearance_mode(self._fg_color),
outline=self._apply_appearance_mode(self._fg_color)) outline=self._apply_appearance_mode(self._fg_color))
for tab in self._tab_dict.values():
tab.configure(fg_color=self._apply_appearance_mode(self._fg_color),
bg_color=self._apply_appearance_mode(self._fg_color))
self._canvas.itemconfig("border_parts", self._canvas.itemconfig("border_parts",
fill=self._apply_appearance_mode(self._border_color), fill=self._apply_appearance_mode(self._border_color),
outline=self._apply_appearance_mode(self._border_color)) outline=self._apply_appearance_mode(self._border_color))
self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color)) self._canvas.configure(bg=self._apply_appearance_mode(self._bg_color))
tkinter.Frame.configure(self, bg=self._apply_appearance_mode(self._bg_color)) # configure bg color of tkinter.Frame, cuase canvas does not fill frame tkinter.Frame.configure(self, bg=self._apply_appearance_mode(self._bg_color)) # configure bg color of tkinter.Frame, cause canvas does not fill frame
def configure(self, require_redraw=False, **kwargs): def configure(self, require_redraw=False, **kwargs):
if "corner_radius" in kwargs: if "corner_radius" in kwargs:
self._corner_radius = kwargs.pop("corner_radius") self._corner_radius = kwargs.pop("corner_radius")
require_redraw = True self._set_grid_segmented_button()
self._set_grid_current_tab()
self._set_grid_canvas()
self._configure_segmented_button_background_corners()
self._segmented_button.configure(corner_radius=self._corner_radius)
if "border_width" in kwargs: if "border_width" in kwargs:
self._border_width = kwargs.pop("border_width") self._border_width = kwargs.pop("border_width")
require_redraw = True require_redraw = True
if "fg_color" in kwargs: if "fg_color" in kwargs:
self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True) self._fg_color = self._check_color_type(kwargs.pop("fg_color"), transparency=True)
self._configure_segmented_button_background_corners()
require_redraw = True require_redraw = True
if "border_color" in kwargs: if "border_color" in kwargs:
self._border_color = self._check_color_type(kwargs.pop("border_color")) self._border_color = self._check_color_type(kwargs.pop("border_color"))
@ -243,6 +280,10 @@ class CTkTabview(CTkBaseClass):
if "command" in kwargs: if "command" in kwargs:
self._command = kwargs.pop("command") self._command = kwargs.pop("command")
if "anchor" in kwargs:
self._anchor = kwargs.pop("anchor")
self._configure_grid()
self._set_grid_segmented_button()
if "state" in kwargs: if "state" in kwargs:
self._segmented_button.configure(state=kwargs.pop("state")) self._segmented_button.configure(state=kwargs.pop("state"))
@ -275,6 +316,8 @@ class CTkTabview(CTkBaseClass):
elif attribute_name == "command": elif attribute_name == "command":
return self._command return self._command
elif attribute_name == "anchor":
return self._anchor
elif attribute_name == "state": elif attribute_name == "state":
return self._segmented_button.cget(attribute_name) return self._segmented_button.cget(attribute_name)
@ -297,17 +340,16 @@ class CTkTabview(CTkBaseClass):
if len(self._tab_dict) == 0: if len(self._tab_dict) == 0:
self._set_grid_segmented_button() self._set_grid_segmented_button()
self._name_list.insert(index, name) self._name_list.append(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 created tab is only tab select this tab
if len(self._tab_dict) == 1: if len(self._tab_dict) == 1:
self._current_name = name self._current_name = name
self._segmented_button.set(self._current_name) self._segmented_button.set(self._current_name)
self._grid_forget_all_tabs() self._grid_forget_all_tabs()
self._set_grid_tab_by_name(self._current_name) self._set_grid_current_tab()
return self._tab_dict[name] return self._tab_dict[name]
else: else:
@ -317,6 +359,10 @@ class CTkTabview(CTkBaseClass):
""" appends new tab with given name """ """ appends new tab with given name """
return self.insert(len(self._tab_dict), name) return self.insert(len(self._tab_dict), name)
def index(self, name) -> int:
""" get index of tab with given name """
return self._segmented_button.index(name)
def move(self, new_index: int, name: str): def move(self, new_index: int, name: str):
if 0 <= new_index < len(self._name_list): if 0 <= new_index < len(self._name_list):
if name in self._tab_dict: if name in self._tab_dict:
@ -326,6 +372,22 @@ class CTkTabview(CTkBaseClass):
else: else:
raise ValueError(f"CTkTabview new_index {new_index} not in range of name list with len {len(self._name_list)}") raise ValueError(f"CTkTabview new_index {new_index} not in range of name list with len {len(self._name_list)}")
def rename(self, old_name: str, new_name: str):
if new_name in self._name_list:
raise ValueError(f"new_name '{new_name}' already exists")
# segmented button
old_index = self._segmented_button.index(old_name)
self._segmented_button.delete(old_name)
self._segmented_button.insert(old_index, new_name)
# name list
self._name_list.remove(old_name)
self._name_list.append(new_name)
# tab dictionary
self._tab_dict[new_name] = self._tab_dict.pop(old_name)
def delete(self, name: str): def delete(self, name: str):
""" delete tab by name """ """ delete tab by name """
@ -345,7 +407,7 @@ class CTkTabview(CTkBaseClass):
self._current_name = self._name_list[0] self._current_name = self._name_list[0]
self._segmented_button.set(self._current_name) self._segmented_button.set(self._current_name)
self._grid_forget_all_tabs() self._grid_forget_all_tabs()
self._set_grid_tab_by_name(self._current_name) self._set_grid_current_tab()
# more tabs are left # more tabs are left
else: else:
@ -361,7 +423,7 @@ class CTkTabview(CTkBaseClass):
if name in self._tab_dict: if name in self._tab_dict:
self._current_name = name self._current_name = name
self._segmented_button.set(name) self._segmented_button.set(name)
self._set_grid_tab_by_name(name) self._set_grid_current_tab()
self.after(100, lambda: self._grid_forget_all_tabs(exclude_name=name)) self.after(100, lambda: self._grid_forget_all_tabs(exclude_name=name))
else: else:
raise ValueError(f"CTkTabview has no tab named '{name}'") raise ValueError(f"CTkTabview has no tab named '{name}'")

View File

@ -63,7 +63,7 @@ text_1.insert("0.0", "CTkTextbox\n\n\n\n")
segmented_button_1 = customtkinter.CTkSegmentedButton(master=frame_1, values=["CTkSegmentedButton", "Value 2"]) segmented_button_1 = customtkinter.CTkSegmentedButton(master=frame_1, values=["CTkSegmentedButton", "Value 2"])
segmented_button_1.pack(pady=10, padx=10) segmented_button_1.pack(pady=10, padx=10)
tabview_1 = customtkinter.CTkTabview(master=frame_1, width=200, height=70) tabview_1 = customtkinter.CTkTabview(master=frame_1, width=300)
tabview_1.pack(pady=10, padx=10) tabview_1.pack(pady=10, padx=10)
tabview_1.add("CTkTabview") tabview_1.add("CTkTabview")
tabview_1.add("Tab 2") tabview_1.add("Tab 2")

View File

@ -9,7 +9,7 @@ author = Tom Schimansky
license = Creative Commons Zero v1.0 Universal license = Creative Commons Zero v1.0 Universal
license_file = LICENSE license_file = LICENSE
classifiers = classifiers =
License :: MIT License License :: OSI Approved :: MIT License
Operating System :: OS Independent Operating System :: OS Independent
Programming Language :: Python :: 3 :: Only Programming Language :: Python :: 3 :: Only

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB