mirror of
https://github.com/TomSchimansky/CustomTkinter.git
synced 2023-08-10 21:13:13 +03:00
worked on CTkTabview, fixed small issues
This commit is contained in:
parent
dbf5577cf0
commit
466ba7747e
@ -8,11 +8,14 @@ ToDo:
|
|||||||
- remove bg and background support for CTk and CTkToplevel (to be done)
|
- remove bg and background support for CTk and CTkToplevel (to be done)
|
||||||
- enforce font size in pixel
|
- enforce font size in pixel
|
||||||
- enforce font to be tuple
|
- enforce font to be tuple
|
||||||
|
- complete other theme files
|
||||||
|
- auto scaling of images
|
||||||
|
|
||||||
## Unreleased - 2022-10-2
|
## Unreleased - 2022-10-2
|
||||||
### Added
|
### Added
|
||||||
- added .cget() method to all widgets and windows
|
- added .cget() method to all widgets and windows
|
||||||
- added CTkTextbox with automatic x and y scrollbars, corner_radius, border_width, border_spacing
|
- added CTkTextbox with automatic x and y scrollbars, corner_radius, border_width, border_spacing
|
||||||
|
- added CTkSegmentedButton
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- changed 'text_font' attribute to 'font' in all widgets
|
- changed 'text_font' attribute to 'font' in all widgets
|
||||||
|
@ -4,6 +4,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
from tkinter.constants import *
|
from tkinter.constants import *
|
||||||
from tkinter import StringVar, IntVar, DoubleVar, BooleanVar
|
from tkinter import StringVar, IntVar, DoubleVar, BooleanVar
|
||||||
|
from tkinter import filedialog
|
||||||
|
|
||||||
# import manager classes
|
# import manager classes
|
||||||
from .settings import Settings
|
from .settings import Settings
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
"frame_high": ["#C0C2C5", "#343638"],
|
"frame_high": ["#C0C2C5", "#343638"],
|
||||||
"label": [null, null],
|
"label": [null, null],
|
||||||
"text": ["gray10", "#DCE4EE"],
|
"text": ["gray10", "#DCE4EE"],
|
||||||
"text_disabled": ["gray60", "#777B80"],
|
"text_disabled": ["gray60", "gray45"],
|
||||||
"text_button": ["#DCE4EE", "#DCE4EE"],
|
"text_button": ["#DCE4EE", "#DCE4EE"],
|
||||||
"text_button_disabled": ["gray74", "gray74"],
|
"text_button_disabled": ["gray74", "gray60"],
|
||||||
"progressbar": ["#939BA2", "#4A4D50"],
|
"progressbar": ["#939BA2", "#4A4D50"],
|
||||||
"progressbar_progress": ["#3B8ED0", "#1F6AA5"],
|
"progressbar_progress": ["#3B8ED0", "#1F6AA5"],
|
||||||
"progressbar_border": ["gray", "gray"],
|
"progressbar_border": ["gray", "gray"],
|
||||||
|
@ -37,7 +37,7 @@ class CTkEntry(CTkBaseClass):
|
|||||||
|
|
||||||
textvariable: tkinter.Variable = None,
|
textvariable: tkinter.Variable = None,
|
||||||
placeholder_text: str = None,
|
placeholder_text: str = None,
|
||||||
font: Union[str, Tuple[str, str]] = "default_theme",
|
font: Union[str, Tuple] = "default_theme",
|
||||||
state: str = tkinter.NORMAL,
|
state: str = tkinter.NORMAL,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ class CTkFrame(CTkBaseClass):
|
|||||||
bg_color: Union[str, Tuple[str, str], None] = None,
|
bg_color: Union[str, Tuple[str, str], None] = None,
|
||||||
fg_color: Union[str, Tuple[str, str], None] = "default_theme",
|
fg_color: Union[str, Tuple[str, str], None] = "default_theme",
|
||||||
border_color: Union[str, Tuple[str, str]] = "default_theme",
|
border_color: Union[str, Tuple[str, str]] = "default_theme",
|
||||||
|
background_corner_colors: Tuple[Union[str, Tuple[str, str]]] = None,
|
||||||
|
|
||||||
overwrite_preferred_drawing_method: str = None,
|
overwrite_preferred_drawing_method: str = None,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
@ -46,6 +47,8 @@ class CTkFrame(CTkBaseClass):
|
|||||||
else:
|
else:
|
||||||
self._fg_color = fg_color
|
self._fg_color = fg_color
|
||||||
|
|
||||||
|
self._background_corner_colors = background_corner_colors # rendering options for DrawEngine
|
||||||
|
|
||||||
# shape
|
# shape
|
||||||
self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius
|
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
|
self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width == "default_theme" else border_width
|
||||||
@ -90,10 +93,19 @@ class CTkFrame(CTkBaseClass):
|
|||||||
self._draw()
|
self._draw()
|
||||||
|
|
||||||
def _draw(self, no_color_updates=False):
|
def _draw(self, no_color_updates=False):
|
||||||
|
|
||||||
if not self._canvas.winfo_exists():
|
if not self._canvas.winfo_exists():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if self._background_corner_colors is not None:
|
||||||
|
self._draw_engine.draw_background_corners(self._apply_widget_scaling(self._current_width),
|
||||||
|
self._apply_widget_scaling(self._current_height))
|
||||||
|
self._canvas.itemconfig("background_corner_top_left", fill=ThemeManager.single_color(self._background_corner_colors[0], self._appearance_mode))
|
||||||
|
self._canvas.itemconfig("background_corner_top_right", fill=ThemeManager.single_color(self._background_corner_colors[1], self._appearance_mode))
|
||||||
|
self._canvas.itemconfig("background_corner_bottom_right", fill=ThemeManager.single_color(self._background_corner_colors[2], self._appearance_mode))
|
||||||
|
self._canvas.itemconfig("background_corner_bottom_left", fill=ThemeManager.single_color(self._background_corner_colors[3], self._appearance_mode))
|
||||||
|
else:
|
||||||
|
self._canvas.delete("background_parts")
|
||||||
|
|
||||||
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._apply_widget_scaling(self._current_height),
|
||||||
self._apply_widget_scaling(self._corner_radius),
|
self._apply_widget_scaling(self._corner_radius),
|
||||||
@ -115,29 +127,34 @@ class CTkFrame(CTkBaseClass):
|
|||||||
outline=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.configure(bg=ThemeManager.single_color(self._bg_color, self._appearance_mode))
|
||||||
|
|
||||||
self._canvas.tag_lower("inner_parts")
|
# self._canvas.tag_lower("inner_parts") # maybe unnecessary, I don't know ???
|
||||||
self._canvas.tag_lower("border_parts")
|
# self._canvas.tag_lower("border_parts")
|
||||||
|
|
||||||
def configure(self, require_redraw=False, **kwargs):
|
def configure(self, require_redraw=False, **kwargs):
|
||||||
if "fg_color" in kwargs:
|
if "fg_color" in kwargs:
|
||||||
self._fg_color = kwargs.pop("fg_color")
|
self._fg_color = kwargs.pop("fg_color")
|
||||||
require_redraw = True
|
require_redraw = True
|
||||||
|
|
||||||
# check if CTk widgets are children of the frame and change their _bg_color to new frame fg_color
|
# 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():
|
for child in self.winfo_children():
|
||||||
if isinstance(child, CTkBaseClass):
|
if isinstance(child, CTkBaseClass):
|
||||||
child.configure(bg_color=self._fg_color)
|
child.configure(bg_color=self._fg_color)
|
||||||
|
|
||||||
# only workaround, to enable one layer of passing new bg_color for children with fg_color=None,
|
if "bg_color" in kwargs:
|
||||||
# but needs to be abstracted to n-layers somehow
|
# pass bg_color change to children if fg_color is None
|
||||||
if isinstance(child, CTkFrame) and child.cget("fg_color") is None:
|
if self._fg_color is None:
|
||||||
for childrens_child in child.winfo_children():
|
for child in self.winfo_children():
|
||||||
childrens_child.configure(bg_color=self._fg_color)
|
if isinstance(child, CTkBaseClass):
|
||||||
|
child.configure(bg_color=self._fg_color)
|
||||||
|
|
||||||
if "border_color" in kwargs:
|
if "border_color" in kwargs:
|
||||||
self._border_color = kwargs.pop("border_color")
|
self._border_color = kwargs.pop("border_color")
|
||||||
require_redraw = True
|
require_redraw = True
|
||||||
|
|
||||||
|
if "background_corner_colors" in kwargs:
|
||||||
|
self._background_corner_colors = kwargs.pop("background_corner_colors")
|
||||||
|
require_redraw = True
|
||||||
|
|
||||||
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
|
require_redraw = True
|
||||||
@ -164,6 +181,8 @@ class CTkFrame(CTkBaseClass):
|
|||||||
return self._fg_color
|
return self._fg_color
|
||||||
elif attribute_name == "border_color":
|
elif attribute_name == "border_color":
|
||||||
return self._border_color
|
return self._border_color
|
||||||
|
elif attribute_name == "background_corner_colors":
|
||||||
|
return self._background_corner_colors
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return super().cget(attribute_name)
|
return super().cget(attribute_name)
|
||||||
|
@ -38,7 +38,7 @@ class CTkOptionMenu(CTkBaseClass):
|
|||||||
variable: tkinter.Variable = None,
|
variable: tkinter.Variable = None,
|
||||||
state: str = tkinter.NORMAL,
|
state: str = tkinter.NORMAL,
|
||||||
hover: bool = True,
|
hover: bool = True,
|
||||||
command: Callable = None,
|
command: Callable[[str], None] = None,
|
||||||
dynamic_resizing: bool = True,
|
dynamic_resizing: bool = True,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import tkinter
|
import tkinter
|
||||||
from typing import Union, Tuple, List, Dict
|
from typing import Union, Tuple, List, Dict, Callable
|
||||||
|
|
||||||
from ..theme_manager import ThemeManager
|
from ..theme_manager import ThemeManager
|
||||||
from .ctk_button import CTkButton
|
from .ctk_button import CTkButton
|
||||||
@ -27,10 +27,14 @@ class CTkSegmentedButton(CTkFrame):
|
|||||||
unselected_hover_color: Union[str, Tuple[str, str]] = "default_theme",
|
unselected_hover_color: Union[str, Tuple[str, str]] = "default_theme",
|
||||||
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",
|
||||||
|
background_corner_colors: Tuple[Union[str, Tuple[str, str]]] = None,
|
||||||
|
|
||||||
|
font: any = "default_theme",
|
||||||
values: list = None,
|
values: list = None,
|
||||||
variable: tkinter.Variable = None,
|
variable: tkinter.Variable = None,
|
||||||
dynamic_resizing: bool = True,
|
dynamic_resizing: bool = True,
|
||||||
|
command: Callable[[str], None] = None,
|
||||||
|
state: str = "normal",
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
|
||||||
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
|
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
|
||||||
@ -49,11 +53,15 @@ class CTkSegmentedButton(CTkFrame):
|
|||||||
self._sb_corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius
|
self._sb_corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius
|
||||||
self._sb_border_width = ThemeManager.theme["shape"]["button_border_width"] if border_width == "default_theme" else border_width
|
self._sb_border_width = ThemeManager.theme["shape"]["button_border_width"] if border_width == "default_theme" else border_width
|
||||||
|
|
||||||
|
self._background_corner_colors = background_corner_colors # rendering options for DrawEngine
|
||||||
|
|
||||||
|
self._command: Callable[[str], None] = command
|
||||||
|
self._font = (ThemeManager.theme["text"]["font"], ThemeManager.theme["text"]["size"]) if font == "default_theme" else font
|
||||||
|
self._state = state
|
||||||
|
|
||||||
self._buttons_dict: Dict[str, CTkButton] = {} # mapped from value to button object
|
self._buttons_dict: Dict[str, CTkButton] = {} # mapped from value to button object
|
||||||
if values is None:
|
if values is None:
|
||||||
self._value_list: List[str] = ["CTkSegmentedButton"]
|
self._value_list: List[str] = ["CTkSegmentedButton"]
|
||||||
elif len(values) == 0:
|
|
||||||
raise ValueError("values of CTkSegmentedButton can not be empty")
|
|
||||||
else:
|
else:
|
||||||
self._value_list: List[str] = values # Values ordered like buttons rendered on widget
|
self._value_list: List[str] = values # Values ordered like buttons rendered on widget
|
||||||
|
|
||||||
@ -63,8 +71,9 @@ class CTkSegmentedButton(CTkFrame):
|
|||||||
|
|
||||||
self._check_unique_values(self._value_list)
|
self._check_unique_values(self._value_list)
|
||||||
self._current_value: str = ""
|
self._current_value: str = ""
|
||||||
self._create_buttons_from_values()
|
if len(self._value_list) > 0:
|
||||||
self._create_button_grid()
|
self._create_buttons_from_values()
|
||||||
|
self._create_button_grid()
|
||||||
|
|
||||||
self._variable = variable
|
self._variable = variable
|
||||||
self._variable_callback_blocked: bool = False
|
self._variable_callback_blocked: bool = False
|
||||||
@ -74,7 +83,7 @@ class CTkSegmentedButton(CTkFrame):
|
|||||||
self._variable_callback_name = self._variable.trace_add("write", self._variable_callback)
|
self._variable_callback_name = self._variable.trace_add("write", self._variable_callback)
|
||||||
self.set(self._variable.get(), from_variable_callback=True)
|
self.set(self._variable.get(), from_variable_callback=True)
|
||||||
|
|
||||||
super().configure(corner_radius=self._sb_corner_radius)
|
super().configure(corner_radius=self._sb_corner_radius, fg_color=None)
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
if self._variable is not None: # remove old callback
|
if self._variable is not None: # remove old callback
|
||||||
@ -95,11 +104,23 @@ class CTkSegmentedButton(CTkFrame):
|
|||||||
|
|
||||||
def _configure_button_corners_for_index(self, index: int):
|
def _configure_button_corners_for_index(self, index: int):
|
||||||
if index == 0 and len(self._value_list) == 1:
|
if index == 0 and len(self._value_list) == 1:
|
||||||
self._buttons_dict[self._value_list[index]].configure(background_corner_colors=(self._bg_color, self._bg_color, self._bg_color, self._bg_color))
|
if self._background_corner_colors is None:
|
||||||
|
self._buttons_dict[self._value_list[index]].configure(background_corner_colors=(self._bg_color, self._bg_color, self._bg_color, self._bg_color))
|
||||||
|
else:
|
||||||
|
self._buttons_dict[self._value_list[index]].configure(background_corner_colors=self._background_corner_colors)
|
||||||
|
|
||||||
elif index == 0:
|
elif index == 0:
|
||||||
self._buttons_dict[self._value_list[index]].configure(background_corner_colors=(self._bg_color, self._sb_fg_color, self._sb_fg_color, self._bg_color))
|
if self._background_corner_colors is None:
|
||||||
|
self._buttons_dict[self._value_list[index]].configure(background_corner_colors=(self._bg_color, self._sb_fg_color, self._sb_fg_color, self._bg_color))
|
||||||
|
else:
|
||||||
|
self._buttons_dict[self._value_list[index]].configure(background_corner_colors=(self._background_corner_colors[0], self._sb_fg_color, self._sb_fg_color, self._background_corner_colors[3]))
|
||||||
|
|
||||||
elif index == len(self._value_list) - 1:
|
elif index == len(self._value_list) - 1:
|
||||||
self._buttons_dict[self._value_list[index]].configure(background_corner_colors=(self._sb_fg_color, self._bg_color, self._bg_color, self._sb_fg_color))
|
if self._background_corner_colors is None:
|
||||||
|
self._buttons_dict[self._value_list[index]].configure(background_corner_colors=(self._sb_fg_color, self._bg_color, self._bg_color, self._sb_fg_color))
|
||||||
|
else:
|
||||||
|
self._buttons_dict[self._value_list[index]].configure(background_corner_colors=(self._sb_fg_color, self._background_corner_colors[1], self._background_corner_colors[2], self._sb_fg_color))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self._buttons_dict[self._value_list[index]].configure(background_corner_colors=(self._sb_fg_color, self._sb_fg_color, self._sb_fg_color, self._sb_fg_color))
|
self._buttons_dict[self._value_list[index]].configure(background_corner_colors=(self._sb_fg_color, self._sb_fg_color, self._sb_fg_color, self._sb_fg_color))
|
||||||
|
|
||||||
@ -129,7 +150,9 @@ class CTkSegmentedButton(CTkFrame):
|
|||||||
hover_color=self._sb_unselected_hover_color,
|
hover_color=self._sb_unselected_hover_color,
|
||||||
text_color=self._sb_text_color,
|
text_color=self._sb_text_color,
|
||||||
text_color_disabled=self._sb_text_color_disabled,
|
text_color_disabled=self._sb_text_color_disabled,
|
||||||
command=lambda v=value: self.set(v),
|
font=self._font,
|
||||||
|
state=self._state,
|
||||||
|
command=lambda v=value: self.set(v, from_button_callback=True),
|
||||||
background_corner_colors=None,
|
background_corner_colors=None,
|
||||||
round_width_to_even_numbers=False) # DrawEngine rendering option (so that theres no gap between buttons)
|
round_width_to_even_numbers=False) # DrawEngine rendering option (so that theres no gap between buttons)
|
||||||
|
|
||||||
@ -212,19 +235,30 @@ class CTkSegmentedButton(CTkFrame):
|
|||||||
for button in self._buttons_dict.values():
|
for button in self._buttons_dict.values():
|
||||||
button.configure(text_color_disabled=self._sb_text_color_disabled)
|
button.configure(text_color_disabled=self._sb_text_color_disabled)
|
||||||
|
|
||||||
|
if "background_corner_colors" in kwargs:
|
||||||
|
self._background_corner_colors = kwargs.pop("background_corner_colors")
|
||||||
|
for i in range(len(self._buttons_dict)):
|
||||||
|
self._configure_button_corners_for_index(i)
|
||||||
|
|
||||||
|
if "font" in kwargs:
|
||||||
|
self._font = kwargs.pop("font")
|
||||||
|
for button in self._buttons_dict.values():
|
||||||
|
button.configure(font=self._font)
|
||||||
|
|
||||||
if "values" in kwargs:
|
if "values" in kwargs:
|
||||||
for button in self._buttons_dict.values():
|
for button in self._buttons_dict.values():
|
||||||
button.destroy()
|
button.destroy()
|
||||||
self._buttons_dict.clear()
|
self._buttons_dict.clear()
|
||||||
self._value_list = kwargs.pop("values")
|
self._value_list = kwargs.pop("values")
|
||||||
self._current_value = ""
|
|
||||||
|
|
||||||
if len(self._value_list) == 0:
|
|
||||||
raise ValueError("len() of values of CTkSegmentedButton can not be zero")
|
|
||||||
|
|
||||||
self._check_unique_values(self._value_list)
|
self._check_unique_values(self._value_list)
|
||||||
self._create_buttons_from_values()
|
|
||||||
self._create_button_grid()
|
if len(self._value_list) > 0:
|
||||||
|
self._create_buttons_from_values()
|
||||||
|
self._create_button_grid()
|
||||||
|
|
||||||
|
if self._current_value in self._value_list:
|
||||||
|
self._select_button_by_value(self._current_value)
|
||||||
|
|
||||||
if "variable" in kwargs:
|
if "variable" in kwargs:
|
||||||
if self._variable is not None: # remove old callback
|
if self._variable is not None: # remove old callback
|
||||||
@ -245,6 +279,14 @@ class CTkSegmentedButton(CTkFrame):
|
|||||||
else:
|
else:
|
||||||
self.grid_propagate(True)
|
self.grid_propagate(True)
|
||||||
|
|
||||||
|
if "command" in kwargs:
|
||||||
|
self._command = kwargs.pop("command")
|
||||||
|
|
||||||
|
if "state" in kwargs:
|
||||||
|
self._state = kwargs.pop("state")
|
||||||
|
for button in self._buttons_dict.values():
|
||||||
|
button.configure(state=self._state)
|
||||||
|
|
||||||
super().configure(**kwargs)
|
super().configure(**kwargs)
|
||||||
|
|
||||||
def cget(self, attribute_name: str) -> any:
|
def cget(self, attribute_name: str) -> any:
|
||||||
@ -268,17 +310,25 @@ class CTkSegmentedButton(CTkFrame):
|
|||||||
elif attribute_name == "text_color_disabled":
|
elif attribute_name == "text_color_disabled":
|
||||||
return self._sb_text_color_disabled
|
return self._sb_text_color_disabled
|
||||||
|
|
||||||
|
elif attribute_name == "font":
|
||||||
|
return self._font
|
||||||
elif attribute_name == "values":
|
elif attribute_name == "values":
|
||||||
return self._value_list
|
return self._value_list
|
||||||
elif attribute_name == "variable":
|
elif attribute_name == "variable":
|
||||||
return self._variable
|
return self._variable
|
||||||
elif attribute_name == "dynamic_resizing":
|
elif attribute_name == "dynamic_resizing":
|
||||||
return self._dynamic_resizing
|
return self._dynamic_resizing
|
||||||
|
elif attribute_name == "command":
|
||||||
|
return self._command
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return super().cget(attribute_name)
|
return super().cget(attribute_name)
|
||||||
|
|
||||||
def set(self, value: str, from_variable_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:
|
||||||
@ -301,7 +351,7 @@ class CTkSegmentedButton(CTkFrame):
|
|||||||
def get(self) -> str:
|
def get(self) -> str:
|
||||||
return self._current_value
|
return self._current_value
|
||||||
|
|
||||||
def insert_value(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:
|
||||||
self._value_list.insert(index, value)
|
self._value_list.insert(index, value)
|
||||||
self._buttons_dict[value] = self._create_button(index, value)
|
self._buttons_dict[value] = self._create_button(index, value)
|
||||||
@ -319,7 +369,7 @@ class CTkSegmentedButton(CTkFrame):
|
|||||||
else:
|
else:
|
||||||
raise ValueError(f"CTkSegmentedButton can not insert value '{value}', already part of the values")
|
raise ValueError(f"CTkSegmentedButton can not insert value '{value}', already part of the values")
|
||||||
|
|
||||||
def remove_value(self, value: str):
|
def delete(self, value: str):
|
||||||
if value in self._buttons_dict:
|
if value in self._buttons_dict:
|
||||||
self._buttons_dict[value].destroy()
|
self._buttons_dict[value].destroy()
|
||||||
self._buttons_dict.pop(value)
|
self._buttons_dict.pop(value)
|
||||||
|
@ -35,7 +35,7 @@ class CTkSlider(CTkBaseClass):
|
|||||||
to: int = 1,
|
to: int = 1,
|
||||||
state: str = "normal",
|
state: str = "normal",
|
||||||
number_of_steps: Union[int, None] = None,
|
number_of_steps: Union[int, None] = None,
|
||||||
command: Callable = None,
|
command: Callable[[float], None] = None,
|
||||||
variable: tkinter.Variable = None,
|
variable: tkinter.Variable = None,
|
||||||
orientation: str = "horizontal",
|
orientation: str = "horizontal",
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
@ -1,18 +1,11 @@
|
|||||||
import tkinter
|
from typing import Union, Tuple, Dict, List
|
||||||
from typing import Union, Tuple, List
|
|
||||||
|
|
||||||
from ..theme_manager import ThemeManager
|
from ..theme_manager import ThemeManager
|
||||||
from .widget_base_class import CTkBaseClass
|
|
||||||
from .ctk_frame import CTkFrame
|
from .ctk_frame import CTkFrame
|
||||||
|
from .widget_base_class import CTkBaseClass
|
||||||
|
from .ctk_segmented_button import CTkSegmentedButton
|
||||||
class CTkTab:
|
from .ctk_canvas import CTkCanvas
|
||||||
def __init__(self, master=None, identifier: str = None, text: str = "CTkTab", index: int = 0):
|
from ..draw_engine import DrawEngine
|
||||||
self.text: str = text
|
|
||||||
self.frame: tkinter.Frame = tkinter.Frame(master, width=0, height=0)
|
|
||||||
self.identifier = str(id(self.frame)) if identifier is None else identifier
|
|
||||||
self.visible: bool = True
|
|
||||||
self.index = index
|
|
||||||
|
|
||||||
|
|
||||||
class CTkTabview(CTkBaseClass):
|
class CTkTabview(CTkBaseClass):
|
||||||
@ -23,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_size = 24
|
_button_height = 10
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
master: any = None,
|
master: any = None,
|
||||||
@ -34,18 +27,26 @@ class CTkTabview(CTkBaseClass):
|
|||||||
|
|
||||||
bg_color: Union[str, Tuple[str, str], None] = None,
|
bg_color: Union[str, Tuple[str, str], None] = None,
|
||||||
fg_color: Union[str, Tuple[str, str], None] = "default_theme",
|
fg_color: Union[str, Tuple[str, str], None] = "default_theme",
|
||||||
|
|
||||||
button_frame_color: Union[str, Tuple[str, str]] = "default_theme",
|
|
||||||
button_color: Union[str, Tuple[str, str]] = "default_theme",
|
|
||||||
button_hover_color: Union[str, Tuple[str, str]] = "default_theme",
|
|
||||||
border_color: Union[str, Tuple[str, str]] = "default_theme",
|
border_color: Union[str, Tuple[str, str]] = "default_theme",
|
||||||
|
|
||||||
|
segmented_button_fg_color: Union[str, Tuple[str, str], None] = "default_theme",
|
||||||
|
segmented_button_selected_color: Union[str, Tuple[str, str]] = "default_theme",
|
||||||
|
segmented_button_selected_hover_color: Union[str, Tuple[str, str]] = "default_theme",
|
||||||
|
segmented_button_unselected_color: Union[str, Tuple[str, str]] = "default_theme",
|
||||||
|
segmented_button_unselected_hover_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",
|
||||||
|
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
|
||||||
# transfer basic functionality (bg_color, size, appearance_mode, scaling) to CTkBaseClass
|
# transfer some functionality to CTkFrame
|
||||||
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
|
super().__init__(master=master, bg_color=bg_color, width=width, height=height, **kwargs)
|
||||||
|
|
||||||
# determine fg_color
|
# color
|
||||||
|
self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color == "default_theme" else border_color
|
||||||
|
|
||||||
|
# determine fg_color of frame
|
||||||
if fg_color == "default_theme":
|
if fg_color == "default_theme":
|
||||||
if isinstance(self.master, (CTkFrame, CTkTabview)):
|
if isinstance(self.master, (CTkFrame, CTkTabview)):
|
||||||
if self.master.cget("fg_color") == ThemeManager.theme["color"]["frame_low"]:
|
if self.master.cget("fg_color") == ThemeManager.theme["color"]["frame_low"]:
|
||||||
@ -57,65 +58,169 @@ class CTkTabview(CTkBaseClass):
|
|||||||
else:
|
else:
|
||||||
self._fg_color = fg_color
|
self._fg_color = fg_color
|
||||||
|
|
||||||
self._border_color = ThemeManager.theme["color"]["frame_border"] if border_color == "default_theme" else border_color
|
|
||||||
self._button_frame_color = ThemeManager.theme["color"]["tabview_button_frame"] if button_frame_color == "default_theme" else button_frame_color
|
|
||||||
self._button_color = ThemeManager.theme["color"]["tabview_button"] if button_color == "default_theme" else button_color
|
|
||||||
self._button_hover_color = ThemeManager.theme["color"]["tabview_button_hover"] if button_hover_color == "default_theme" else button_hover_color
|
|
||||||
|
|
||||||
# shape
|
# shape
|
||||||
self._corner_radius = ThemeManager.theme["shape"]["frame_corner_radius"] if corner_radius == "default_theme" else corner_radius
|
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
|
self._border_width = ThemeManager.theme["shape"]["frame_border_width"] if border_width == "default_theme" else border_width
|
||||||
|
|
||||||
self._main_frame = CTkFrame(self,
|
self._canvas = CTkCanvas(master=self,
|
||||||
width=width,
|
bg=ThemeManager.single_color(self._bg_color, self._appearance_mode),
|
||||||
height=height - (self._top_spacing + self._top_button_overhang),
|
highlightthickness=0,
|
||||||
bg_color=self._bg_color,
|
width=self._apply_widget_scaling(self._current_width - self._top_spacing - self._top_button_overhang),
|
||||||
fg_color=self._fg_color,
|
height=self._apply_widget_scaling(self._current_height))
|
||||||
border_color=self._border_color,
|
self._draw_engine = DrawEngine(self._canvas)
|
||||||
border_width=self._border_width)
|
|
||||||
self._button_frame = CTkFrame(self,
|
|
||||||
width=0,
|
|
||||||
height=0,
|
|
||||||
bg_color=self._fg_color,
|
|
||||||
fg_color=self._button_frame_color,
|
|
||||||
border_color=self._border_color,
|
|
||||||
border_width=self._border_width)
|
|
||||||
self._create_grid_for_frames()
|
|
||||||
|
|
||||||
self._tab_list: List[CTkTab] = []
|
self._segmented_button = CTkSegmentedButton(self,
|
||||||
|
values=[],
|
||||||
|
height=self._button_height,
|
||||||
|
fg_color=segmented_button_fg_color,
|
||||||
|
selected_color=segmented_button_selected_color,
|
||||||
|
selected_hover_color=segmented_button_selected_hover_color,
|
||||||
|
unselected_color=segmented_button_unselected_color,
|
||||||
|
unselected_hover_color=segmented_button_unselected_hover_color,
|
||||||
|
text_color=text_color,
|
||||||
|
text_color_disabled=text_color_disabled,
|
||||||
|
corner_radius=corner_radius,
|
||||||
|
border_width=self._apply_widget_scaling(3))
|
||||||
|
self._configure_segmented_button_background_corners()
|
||||||
|
self._configure_grid()
|
||||||
|
self._set_grid_canvas()
|
||||||
|
|
||||||
def _create_grid_for_frames(self):
|
self._tab_dict: Dict[str, CTkFrame] = {}
|
||||||
|
self._name_list: List[str] = [] # list of unique tab names in order of tabs
|
||||||
|
self._current_name: str = ""
|
||||||
|
|
||||||
|
super().bind('<Configure>', self._update_dimensions_event)
|
||||||
|
|
||||||
|
def winfo_children(self) -> List[any]:
|
||||||
|
"""
|
||||||
|
winfo_children of CTkTabview without canvas and segmented button widgets,
|
||||||
|
because it's not a child but part of the CTkTabview itself
|
||||||
|
"""
|
||||||
|
|
||||||
|
child_widgets = super().winfo_children()
|
||||||
|
try:
|
||||||
|
child_widgets.remove(self._canvas)
|
||||||
|
child_widgets.remove(self._segmented_button)
|
||||||
|
return child_widgets
|
||||||
|
except ValueError:
|
||||||
|
return child_widgets
|
||||||
|
|
||||||
|
def _set_scaling(self, *args, **kwargs):
|
||||||
|
super()._set_scaling(*args, **kwargs)
|
||||||
|
|
||||||
|
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))
|
||||||
|
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._top_spacing - self._top_button_overhang))
|
||||||
|
self._draw()
|
||||||
|
|
||||||
|
def _configure_segmented_button_background_corners(self):
|
||||||
|
""" needs to be called for changes in fg_color, bg_color """
|
||||||
|
|
||||||
|
if self._fg_color is not None:
|
||||||
|
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))
|
||||||
|
|
||||||
|
def _configure_tab_background_corners_by_name(self, name: str):
|
||||||
|
""" needs to be called for changes in fg_color, bg_color, border_width """
|
||||||
|
|
||||||
|
if self._border_width == 0:
|
||||||
|
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))
|
||||||
|
else:
|
||||||
|
self._tab_dict[name].configure(background_corner_colors=(self._bg_color, self._bg_color, self._bg_color, self._bg_color))
|
||||||
|
else:
|
||||||
|
self._tab_dict[name].configure(background_corner_colors=None)
|
||||||
|
|
||||||
|
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))
|
self.grid_rowconfigure(0, weight=0, minsize=self._apply_widget_scaling(self._top_spacing))
|
||||||
self.grid_rowconfigure(1, weight=0, minsize=self._apply_widget_scaling(self._top_button_overhang))
|
self.grid_rowconfigure(1, weight=0, minsize=self._apply_widget_scaling(self._top_button_overhang))
|
||||||
self.grid_rowconfigure(2, weight=0, minsize=self._apply_widget_scaling(self._button_size - self._top_button_overhang))
|
self.grid_rowconfigure(2, weight=0, minsize=self._apply_widget_scaling(self._button_height - self._top_button_overhang))
|
||||||
self.grid_rowconfigure(3, weight=1)
|
self.grid_rowconfigure(3, weight=1)
|
||||||
|
|
||||||
self.grid_columnconfigure((0, 2), weight=1, minsize=self._apply_widget_scaling(self._corner_radius))
|
self.grid_columnconfigure(0, weight=1)
|
||||||
self.grid_columnconfigure(1, weight=0, minsize=self._apply_widget_scaling(self._corner_radius))
|
|
||||||
|
|
||||||
self._main_frame.grid(row=2, column=0, rowspan=2, columnspan=3, sticky="nsew")
|
def _set_grid_canvas(self):
|
||||||
self._button_frame.grid(row=1, column=1, rowspan=2, columnspan=1, sticky="nsew")
|
self._canvas.grid(row=2, rowspan=2, column=0, columnspan=1, sticky="nsew")
|
||||||
|
|
||||||
def _get_tab_by_identifier(self, identifier: str):
|
def _set_grid_segmented_button(self):
|
||||||
for tab in self._tab_list:
|
""" needs to be called for changes in corner_radius """
|
||||||
if tab.identifier == identifier:
|
self._segmented_button.grid(row=1, rowspan=2, column=0, columnspan=1, padx=self._apply_widget_scaling(self._corner_radius), sticky="ns")
|
||||||
return tab
|
|
||||||
|
|
||||||
def create_tab(self, identifier=None, text="CTkTabview"):
|
def _set_grid_tab_by_name(self, name: str):
|
||||||
new_tab = CTkTab(master=self, identifier=identifier, text=text)
|
""" needs to be called for changes in corner_radius, border_width """
|
||||||
self._tab_list.append(new_tab)
|
if self._border_width == 0:
|
||||||
return new_tab.identifier
|
self._tab_dict[name].grid(row=3, column=0, sticky="nsew")
|
||||||
|
else:
|
||||||
|
self._tab_dict[name].grid(row=3, 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 select_tab(self, identifier: str):
|
def _create_tab(self) -> CTkFrame:
|
||||||
selected_tab = self._get_tab_by_identifier(identifier)
|
new_tab = CTkFrame(self,
|
||||||
for tab in self._tab_list:
|
fg_color=self._fg_color,
|
||||||
if tab != selected_tab:
|
border_width=0,
|
||||||
tab.frame.grid_forget()
|
corner_radius=self._corner_radius)
|
||||||
|
return new_tab
|
||||||
|
|
||||||
selected_tab.frame.grid(row=3, column=0, rowspan=1, columnspan=3, sticky="nsew")
|
def _draw(self, no_color_updates: bool = False):
|
||||||
|
if not self._canvas.winfo_exists():
|
||||||
|
return
|
||||||
|
|
||||||
def get_tab(self, identifier):
|
requires_recoloring = self._draw_engine.draw_rounded_rect_with_border(self._apply_widget_scaling(self._current_width),
|
||||||
pass
|
self._apply_widget_scaling(self._current_height - self._top_spacing - self._top_button_overhang),
|
||||||
|
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))
|
||||||
|
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._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))
|
||||||
|
|
||||||
|
def tab(self, name: str) -> CTkFrame:
|
||||||
|
""" returns reference to the tab with given name """
|
||||||
|
|
||||||
|
if name in self._tab_dict:
|
||||||
|
return self._tab_dict[name]
|
||||||
|
else:
|
||||||
|
raise ValueError(f"CTkTabview has no tab named '{name}'")
|
||||||
|
|
||||||
|
def insert(self, index: int, name: str):
|
||||||
|
""" creates new tab with given name at position index """
|
||||||
|
|
||||||
|
if name not in self._tab_dict:
|
||||||
|
# if no tab exists, set grid for segmented button
|
||||||
|
if len(self._tab_dict) == 0:
|
||||||
|
self._set_grid_segmented_button()
|
||||||
|
|
||||||
|
self._name_list.insert(index, name)
|
||||||
|
self._tab_dict[name] = self._create_tab()
|
||||||
|
self._segmented_button.insert(index, name)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"CTkTabview already has tab named '{name}'")
|
||||||
|
|
||||||
|
def add(self, name: str):
|
||||||
|
""" appends new tab with given name """
|
||||||
|
self.insert(len(self._tab_dict), name)
|
||||||
|
|
||||||
|
def delete(self, name: str):
|
||||||
|
""" deletes tab with given name """
|
||||||
|
return
|
||||||
|
@ -104,9 +104,9 @@ class CTkTextbox(CTkBaseClass):
|
|||||||
orientation="vertical",
|
orientation="vertical",
|
||||||
command=self._textbox.yview)
|
command=self._textbox.yview)
|
||||||
self._textbox.configure(yscrollcommand=self._y_scrollbar.set)
|
self._textbox.configure(yscrollcommand=self._y_scrollbar.set)
|
||||||
self._y_scrollbar.grid(row=0, column=1, rowspan=1, columnspan=1, sticky="ns",
|
#self._y_scrollbar.grid(row=0, column=1, rowspan=1, columnspan=1, sticky="ns",
|
||||||
padx=(self._apply_widget_scaling(3), self._apply_widget_scaling(self._border_spacing + self._border_width)),
|
# padx=(self._apply_widget_scaling(3), self._apply_widget_scaling(self._border_spacing + self._border_width)),
|
||||||
pady=(self._apply_widget_scaling(self._corner_radius + self._border_width), 0))
|
# pady=(self._apply_widget_scaling(self._corner_radius + self._border_width), 0))
|
||||||
|
|
||||||
self._x_scrollbar = CTkScrollbar(self,
|
self._x_scrollbar = CTkScrollbar(self,
|
||||||
height=8,
|
height=8,
|
||||||
@ -118,9 +118,9 @@ class CTkTextbox(CTkBaseClass):
|
|||||||
orientation="horizontal",
|
orientation="horizontal",
|
||||||
command=self._textbox.xview)
|
command=self._textbox.xview)
|
||||||
self._textbox.configure(xscrollcommand=self._x_scrollbar.set)
|
self._textbox.configure(xscrollcommand=self._x_scrollbar.set)
|
||||||
self._x_scrollbar.grid(row=1, column=0, rowspan=1, columnspan=1, sticky="ew",
|
#self._x_scrollbar.grid(row=1, column=0, rowspan=1, columnspan=1, sticky="ew",
|
||||||
pady=(self._apply_widget_scaling(3), self._apply_widget_scaling(self._border_spacing + self._border_width)),
|
# pady=(self._apply_widget_scaling(3), self._apply_widget_scaling(self._border_spacing + self._border_width)),
|
||||||
padx=(self._apply_widget_scaling(self._corner_radius + self._border_width), 0))
|
# padx=(self._apply_widget_scaling(self._corner_radius + self._border_width), 0))
|
||||||
|
|
||||||
self._create_grid_for_text_and_scrollbars(re_grid_textbox=True, re_grid_x_scrollbar=True, re_grid_y_scrollbar=True)
|
self._create_grid_for_text_and_scrollbars(re_grid_textbox=True, re_grid_x_scrollbar=True, re_grid_y_scrollbar=True)
|
||||||
|
|
||||||
@ -269,6 +269,11 @@ class CTkTextbox(CTkBaseClass):
|
|||||||
self._create_grid_for_text_and_scrollbars(re_grid_textbox=True, re_grid_x_scrollbar=True, re_grid_y_scrollbar=True)
|
self._create_grid_for_text_and_scrollbars(re_grid_textbox=True, re_grid_x_scrollbar=True, re_grid_y_scrollbar=True)
|
||||||
require_redraw = True
|
require_redraw = True
|
||||||
|
|
||||||
|
if "border_spacing" in kwargs:
|
||||||
|
self._border_spacing = kwargs.pop("border_spacing")
|
||||||
|
self._create_grid_for_text_and_scrollbars(re_grid_textbox=True, re_grid_x_scrollbar=True, re_grid_y_scrollbar=True)
|
||||||
|
require_redraw = True
|
||||||
|
|
||||||
if "width" in kwargs:
|
if "width" in kwargs:
|
||||||
self._set_dimensions(width=kwargs.pop("width"))
|
self._set_dimensions(width=kwargs.pop("width"))
|
||||||
|
|
||||||
@ -287,6 +292,8 @@ class CTkTextbox(CTkBaseClass):
|
|||||||
return self._corner_radius
|
return self._corner_radius
|
||||||
elif attribute_name == "border_width":
|
elif attribute_name == "border_width":
|
||||||
return self._border_width
|
return self._border_width
|
||||||
|
elif attribute_name == "border_spacing":
|
||||||
|
return self._border_spacing
|
||||||
|
|
||||||
elif attribute_name == "fg_color":
|
elif attribute_name == "fg_color":
|
||||||
return self._fg_color
|
return self._fg_color
|
||||||
@ -336,6 +343,9 @@ class CTkTextbox(CTkBaseClass):
|
|||||||
def compare(self, index, op, index2):
|
def compare(self, index, op, index2):
|
||||||
return self._textbox.compare(index, op, index2)
|
return self._textbox.compare(index, op, index2)
|
||||||
|
|
||||||
|
def delete(self, index1, index2=None):
|
||||||
|
return self._textbox.delete(index1, index2)
|
||||||
|
|
||||||
def dlineinfo(self, index):
|
def dlineinfo(self, index):
|
||||||
return self._textbox.dlineinfo(index)
|
return self._textbox.dlineinfo(index)
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import tkinter
|
|||||||
import tkinter.ttk as ttk
|
import tkinter.ttk as ttk
|
||||||
import copy
|
import copy
|
||||||
import re
|
import re
|
||||||
from typing import Union, Callable
|
from typing import Union, Callable, Tuple
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from typing import TypedDict
|
from typing import TypedDict
|
||||||
@ -30,7 +30,7 @@ class CTkBaseClass(tkinter.Frame):
|
|||||||
width: int = 0,
|
width: int = 0,
|
||||||
height: int = 0,
|
height: int = 0,
|
||||||
|
|
||||||
bg_color: Union[str, tuple] = None,
|
bg_color: Union[str, Tuple[str, str], None] = None,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
|
||||||
super().__init__(master=master, width=width, height=height, **pop_from_dict_by_set(kwargs, self._valid_tk_frame_attributes))
|
super().__init__(master=master, width=width, height=height, **pop_from_dict_by_set(kwargs, self._valid_tk_frame_attributes))
|
||||||
@ -64,7 +64,7 @@ class CTkBaseClass(tkinter.Frame):
|
|||||||
self._appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark"
|
self._appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark"
|
||||||
|
|
||||||
# background color
|
# background color
|
||||||
self._bg_color = self._detect_color_of_master() if bg_color is None else bg_color
|
self._bg_color: Union[str, Tuple[str, str]] = self._detect_color_of_master() if bg_color is None else bg_color
|
||||||
|
|
||||||
super().configure(bg=ThemeManager.single_color(self._bg_color, self._appearance_mode))
|
super().configure(bg=ThemeManager.single_color(self._bg_color, self._appearance_mode))
|
||||||
|
|
||||||
@ -104,6 +104,7 @@ class CTkBaseClass(tkinter.Frame):
|
|||||||
def destroy(self):
|
def destroy(self):
|
||||||
""" Destroy this and all descendants widgets. """
|
""" Destroy this and all descendants widgets. """
|
||||||
AppearanceModeTracker.remove(self._set_appearance_mode)
|
AppearanceModeTracker.remove(self._set_appearance_mode)
|
||||||
|
ScalingTracker.remove_widget(self._set_scaling, self)
|
||||||
super().destroy()
|
super().destroy()
|
||||||
|
|
||||||
def place(self, **kwargs):
|
def place(self, **kwargs):
|
||||||
@ -240,6 +241,7 @@ class CTkBaseClass(tkinter.Frame):
|
|||||||
raise ValueError(f"'{attribute_name}' is not a supported argument. Look at the documentation for supported arguments.")
|
raise ValueError(f"'{attribute_name}' is not a supported argument. Look at the documentation for supported arguments.")
|
||||||
|
|
||||||
def _update_dimensions_event(self, event):
|
def _update_dimensions_event(self, event):
|
||||||
|
print(event)
|
||||||
# only redraw if dimensions changed (for performance), independent of scaling
|
# only redraw if dimensions changed (for performance), independent of scaling
|
||||||
if round(self._current_width) != round(event.width / self._widget_scaling) or round(self._current_height) != round(event.height / self._widget_scaling):
|
if round(self._current_width) != round(event.width / self._widget_scaling) or round(self._current_height) != round(event.height / self._widget_scaling):
|
||||||
self._current_width = (event.width / self._widget_scaling) # adjust current size according to new size given by event
|
self._current_width = (event.width / self._widget_scaling) # adjust current size according to new size given by event
|
||||||
@ -247,7 +249,7 @@ class CTkBaseClass(tkinter.Frame):
|
|||||||
|
|
||||||
self._draw(no_color_updates=True) # faster drawing without color changes
|
self._draw(no_color_updates=True) # faster drawing without color changes
|
||||||
|
|
||||||
def _detect_color_of_master(self, master_widget=None):
|
def _detect_color_of_master(self, master_widget=None) -> Union[str, Tuple[str, str]]:
|
||||||
""" detect color of self.master widget to set correct _bg_color """
|
""" detect color of self.master widget to set correct _bg_color """
|
||||||
|
|
||||||
if master_widget is None:
|
if master_widget is None:
|
||||||
|
@ -12,14 +12,14 @@ class App(customtkinter.CTk):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.title("CustomTkinter complex_example.py")
|
self.title("CustomTkinter complex_example.py")
|
||||||
self.geometry(f"{920}x{500}")
|
self.geometry(f"{1100}x{580}")
|
||||||
self.minsize(700, 400)
|
self.minsize(800, 400)
|
||||||
self.maxsize(1200, 700)
|
self.maxsize(1300, 700)
|
||||||
self.protocol("WM_DELETE_WINDOW", self.on_closing) # call .on_closing() when app gets closed
|
self.protocol("WM_DELETE_WINDOW", self.on_closing) # call .on_closing() when app gets closed
|
||||||
|
|
||||||
# configure grid layout (4x4)
|
# configure grid layout (4x4)
|
||||||
self.grid_columnconfigure(1, weight=1)
|
self.grid_columnconfigure(1, weight=1)
|
||||||
self.grid_columnconfigure((2, 3), weight=0, minsize=200)
|
self.grid_columnconfigure((2, 3, 4), weight=0, minsize=200)
|
||||||
self.grid_rowconfigure((0, 1, 2), weight=1)
|
self.grid_rowconfigure((0, 1, 2), weight=1)
|
||||||
|
|
||||||
# create sidebar frame with widgets
|
# create sidebar frame with widgets
|
||||||
@ -52,22 +52,10 @@ class App(customtkinter.CTk):
|
|||||||
self.main_button_1 = customtkinter.CTkButton(master=self, fg_color=None, border_width=2)
|
self.main_button_1 = customtkinter.CTkButton(master=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.main_button_1.grid(row=3, column=3, padx=(10, 20), pady=(10, 20), sticky="nsew")
|
||||||
|
|
||||||
|
# create textbox
|
||||||
self.textbox = customtkinter.CTkTextbox(self)
|
self.textbox = customtkinter.CTkTextbox(self)
|
||||||
self.textbox.grid(row=0, column=1, padx=(20, 10), pady=(20, 10), sticky="nsew")
|
self.textbox.grid(row=0, column=1, padx=(20, 10), pady=(20, 10), sticky="nsew")
|
||||||
|
|
||||||
# create radiobutton frame
|
|
||||||
self.radiobutton_frame = customtkinter.CTkFrame(self)
|
|
||||||
self.radiobutton_frame.grid(row=0, column=3, padx=(10, 20), pady=(20, 10), sticky="nsew")
|
|
||||||
self.radio_var = tkinter.IntVar(value=0)
|
|
||||||
self.label_radio_group = customtkinter.CTkLabel(master=self.radiobutton_frame, text="CTkRadioButton Group:")
|
|
||||||
self.label_radio_group.grid(row=0, column=2, columnspan=1, padx=10, pady=10, sticky="")
|
|
||||||
self.radio_button_1 = customtkinter.CTkRadioButton(master=self.radiobutton_frame, variable=self.radio_var, value=0)
|
|
||||||
self.radio_button_1.grid(row=1, column=2, pady=10, padx=20, sticky="n")
|
|
||||||
self.radio_button_2 = customtkinter.CTkRadioButton(master=self.radiobutton_frame, variable=self.radio_var, value=1)
|
|
||||||
self.radio_button_2.grid(row=2, column=2, pady=10, padx=20, sticky="n")
|
|
||||||
self.radio_button_3 = customtkinter.CTkRadioButton(master=self.radiobutton_frame, variable=self.radio_var, value=2)
|
|
||||||
self.radio_button_3.grid(row=3, column=2, pady=10, padx=20, sticky="n")
|
|
||||||
|
|
||||||
# create optionemnu and combobox frame
|
# create optionemnu and combobox frame
|
||||||
self.optionemnu_combobox_frame = customtkinter.CTkFrame(self)
|
self.optionemnu_combobox_frame = customtkinter.CTkFrame(self)
|
||||||
self.optionemnu_combobox_frame.grid(row=0, column=2, padx=(10, 10), pady=(20, 10), sticky="nsew")
|
self.optionemnu_combobox_frame.grid(row=0, column=2, padx=(10, 10), pady=(20, 10), sticky="nsew")
|
||||||
@ -82,9 +70,22 @@ class App(customtkinter.CTk):
|
|||||||
command=self.open_input_dialog)
|
command=self.open_input_dialog)
|
||||||
self.string_input_button.grid(row=2, column=0, padx=20, pady=(10, 10), sticky="ew")
|
self.string_input_button.grid(row=2, column=0, padx=20, pady=(10, 10), sticky="ew")
|
||||||
|
|
||||||
|
# create radiobutton frame
|
||||||
|
self.radiobutton_frame = customtkinter.CTkFrame(self)
|
||||||
|
self.radiobutton_frame.grid(row=0, column=3, padx=(10, 10), pady=(20, 10), sticky="nsew")
|
||||||
|
self.radio_var = tkinter.IntVar(value=0)
|
||||||
|
self.label_radio_group = customtkinter.CTkLabel(master=self.radiobutton_frame, text="CTkRadioButton Group:")
|
||||||
|
self.label_radio_group.grid(row=0, column=2, columnspan=1, padx=10, pady=10, sticky="")
|
||||||
|
self.radio_button_1 = customtkinter.CTkRadioButton(master=self.radiobutton_frame, variable=self.radio_var, value=0)
|
||||||
|
self.radio_button_1.grid(row=1, column=2, pady=10, padx=20, sticky="n")
|
||||||
|
self.radio_button_2 = customtkinter.CTkRadioButton(master=self.radiobutton_frame, variable=self.radio_var, value=1)
|
||||||
|
self.radio_button_2.grid(row=2, column=2, pady=10, padx=20, sticky="n")
|
||||||
|
self.radio_button_3 = customtkinter.CTkRadioButton(master=self.radiobutton_frame, variable=self.radio_var, value=2)
|
||||||
|
self.radio_button_3.grid(row=3, column=2, pady=10, padx=20, sticky="n")
|
||||||
|
|
||||||
# create checkbox and switch frame
|
# create checkbox and switch frame
|
||||||
self.checkbox_slider_frame = customtkinter.CTkFrame(self)
|
self.checkbox_slider_frame = customtkinter.CTkFrame(self)
|
||||||
self.checkbox_slider_frame.grid(row=1, column=3, padx=(10, 20), pady=(10, 10), sticky="nsew")
|
self.checkbox_slider_frame.grid(row=0, column=4, padx=(10, 20), pady=(20, 10), sticky="nsew")
|
||||||
self.checkbox_1 = customtkinter.CTkCheckBox(master=self.checkbox_slider_frame)
|
self.checkbox_1 = customtkinter.CTkCheckBox(master=self.checkbox_slider_frame)
|
||||||
self.checkbox_1.grid(row=1, column=0, pady=(20, 10), padx=20, sticky="n")
|
self.checkbox_1.grid(row=1, column=0, pady=(20, 10), padx=20, sticky="n")
|
||||||
self.checkbox_2 = customtkinter.CTkCheckBox(master=self.checkbox_slider_frame)
|
self.checkbox_2 = customtkinter.CTkCheckBox(master=self.checkbox_slider_frame)
|
||||||
@ -100,9 +101,8 @@ class App(customtkinter.CTk):
|
|||||||
self.slider_progressbar_frame.grid_columnconfigure(0, weight=1)
|
self.slider_progressbar_frame.grid_columnconfigure(0, weight=1)
|
||||||
self.slider_progressbar_frame.grid_rowconfigure(4, weight=1)
|
self.slider_progressbar_frame.grid_rowconfigure(4, weight=1)
|
||||||
|
|
||||||
self.seg_button = customtkinter._CTkSegmentedButton(self.slider_progressbar_frame,
|
self.seg_button_1 = customtkinter._CTkSegmentedButton(self.slider_progressbar_frame)
|
||||||
values=["CTkSegmentedButton", "Value 2", "Value 3"])
|
self.seg_button_1.grid(row=0, column=0, padx=(20, 10), pady=(10, 10), sticky="ew")
|
||||||
self.seg_button.grid(row=0, column=0, padx=(20, 10), pady=(10, 10), sticky="ew")
|
|
||||||
|
|
||||||
self.progressbar_1 = customtkinter.CTkProgressBar(self.slider_progressbar_frame)
|
self.progressbar_1 = customtkinter.CTkProgressBar(self.slider_progressbar_frame)
|
||||||
self.progressbar_1.grid(row=1, column=0, padx=(20, 10), pady=(10, 10), sticky="ew")
|
self.progressbar_1.grid(row=1, column=0, padx=(20, 10), pady=(10, 10), sticky="ew")
|
||||||
@ -115,6 +115,10 @@ class App(customtkinter.CTk):
|
|||||||
self.progressbar_3 = customtkinter.CTkProgressBar(self.slider_progressbar_frame, orientation="vertical")
|
self.progressbar_3 = customtkinter.CTkProgressBar(self.slider_progressbar_frame, orientation="vertical")
|
||||||
self.progressbar_3.grid(row=0, column=2, rowspan=5, padx=(10, 20), pady=(10, 10), sticky="ns")
|
self.progressbar_3.grid(row=0, column=2, rowspan=5, padx=(10, 20), pady=(10, 10), sticky="ns")
|
||||||
|
|
||||||
|
# create tabview
|
||||||
|
self.tabview = customtkinter._CTkTabview(self)
|
||||||
|
self.tabview.grid(row=1, column=3, columnspan=2, padx=(10, 20), pady=(10, 10), sticky="nsew")
|
||||||
|
|
||||||
# set default values
|
# set default values
|
||||||
self.sidebar_button_3.configure(state="disabled", text="Disabled CTkButton")
|
self.sidebar_button_3.configure(state="disabled", text="Disabled CTkButton")
|
||||||
self.checkbox_2.configure(state="disabled")
|
self.checkbox_2.configure(state="disabled")
|
||||||
@ -130,8 +134,11 @@ class App(customtkinter.CTk):
|
|||||||
self.slider_2.configure(command=self.progressbar_3.set)
|
self.slider_2.configure(command=self.progressbar_3.set)
|
||||||
self.progressbar_1.configure(mode="indeterminnate")
|
self.progressbar_1.configure(mode="indeterminnate")
|
||||||
self.progressbar_1.start()
|
self.progressbar_1.start()
|
||||||
|
self.textbox.insert("0.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.seg_button_1.configure(values=["CTkSegmentedButton", "Value 2", "Value 3"])
|
||||||
|
self.seg_button_1.set("Value 2")
|
||||||
|
|
||||||
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.radiobutton_frame.configure(border_width=50)
|
||||||
|
|
||||||
def open_input_dialog(self):
|
def open_input_dialog(self):
|
||||||
dialog = customtkinter.CTkInputDialog(master=self, text="Type in a number:", title="CTkInputDialog")
|
dialog = customtkinter.CTkInputDialog(master=self, text="Type in a number:", title="CTkInputDialog")
|
||||||
|
@ -2,7 +2,7 @@ import tkinter
|
|||||||
import customtkinter
|
import customtkinter
|
||||||
|
|
||||||
customtkinter.set_appearance_mode("System") # Other: "Dark", "Light"
|
customtkinter.set_appearance_mode("System") # Other: "Dark", "Light"
|
||||||
customtkinter.set_default_color_theme("green") # Themes: "blue" (standard), "green", "dark-blue"
|
# customtkinter.set_default_color_theme("green") # Themes: "blue" (standard), "green", "dark-blue"
|
||||||
|
|
||||||
|
|
||||||
class TestApp(customtkinter.CTk):
|
class TestApp(customtkinter.CTk):
|
||||||
@ -20,13 +20,13 @@ class TestApp(customtkinter.CTk):
|
|||||||
""" gets called by self.slider_1 """
|
""" gets called by self.slider_1 """
|
||||||
|
|
||||||
if value == 0:
|
if value == 0:
|
||||||
self.label_1.set_text("mode: Light")
|
self.label_1.configure(text="mode: Light")
|
||||||
customtkinter.set_appearance_mode("Light")
|
customtkinter.set_appearance_mode("Light")
|
||||||
elif value == 1:
|
elif value == 1:
|
||||||
self.label_1.set_text("mode: Dark")
|
self.label_1.configure(text="mode: Dark")
|
||||||
customtkinter.set_appearance_mode("Dark")
|
customtkinter.set_appearance_mode("Dark")
|
||||||
else:
|
else:
|
||||||
self.label_1.set_text("mode: System")
|
self.label_1.configure(text="mode: System")
|
||||||
customtkinter.set_appearance_mode("System")
|
customtkinter.set_appearance_mode("System")
|
||||||
|
|
||||||
def create_widgets_on_tk(self):
|
def create_widgets_on_tk(self):
|
||||||
@ -74,7 +74,7 @@ class TestApp(customtkinter.CTk):
|
|||||||
self.progress_bar_2 = customtkinter.CTkProgressBar(master=self.ctk_frame)
|
self.progress_bar_2 = customtkinter.CTkProgressBar(master=self.ctk_frame)
|
||||||
self.progress_bar_2.place(relx=0.5, y=y + 320, anchor=tkinter.CENTER)
|
self.progress_bar_2.place(relx=0.5, y=y + 320, anchor=tkinter.CENTER)
|
||||||
|
|
||||||
self.slider_2 = customtkinter.CTkSlider(master=self.ctk_frame, command=lambda v: self.label_2.set_text(str(round(v, 5))))
|
self.slider_2 = customtkinter.CTkSlider(master=self.ctk_frame, command=lambda v: self.label_2.configure(text=str(round(v, 5))))
|
||||||
self.slider_2.place(relx=0.5, y=y + 400, anchor=tkinter.CENTER)
|
self.slider_2.place(relx=0.5, y=y + 400, anchor=tkinter.CENTER)
|
||||||
|
|
||||||
self.check_box_2 = customtkinter.CTkCheckBox(master=self.ctk_frame)
|
self.check_box_2 = customtkinter.CTkCheckBox(master=self.ctk_frame)
|
||||||
@ -102,7 +102,7 @@ class TestApp(customtkinter.CTk):
|
|||||||
self.ctk_frame_customized.configure(fg_color=("#F4F4FA", "#1E2742"))
|
self.ctk_frame_customized.configure(fg_color=("#F4F4FA", "#1E2742"))
|
||||||
|
|
||||||
self.label_3 = customtkinter.CTkLabel(master=self.ctk_frame_customized, text="customized", corner_radius=60,
|
self.label_3 = customtkinter.CTkLabel(master=self.ctk_frame_customized, text="customized", corner_radius=60,
|
||||||
text_font=("times", 16))
|
font=("times", 16))
|
||||||
self.label_3.place(relx=0.5, y=y, anchor=tkinter.CENTER)
|
self.label_3.place(relx=0.5, y=y, anchor=tkinter.CENTER)
|
||||||
self.label_3.configure(fg_color=("#F4F4FA", "#333D5E"), text_color=("#373E57", "#7992C1"))
|
self.label_3.configure(fg_color=("#F4F4FA", "#333D5E"), text_color=("#373E57", "#7992C1"))
|
||||||
|
|
||||||
@ -111,12 +111,12 @@ class TestApp(customtkinter.CTk):
|
|||||||
self.frame_3.configure(fg_color=("#EBECF3", "#4B577E"))
|
self.frame_3.configure(fg_color=("#EBECF3", "#4B577E"))
|
||||||
|
|
||||||
self.button_3 = customtkinter.CTkButton(master=self.ctk_frame_customized, command=lambda: x, border_width=3,
|
self.button_3 = customtkinter.CTkButton(master=self.ctk_frame_customized, command=lambda: x, border_width=3,
|
||||||
corner_radius=20, text_font=("times", 16))
|
corner_radius=20, font=("times", 16))
|
||||||
self.button_3.place(relx=0.5, y=y + 160, anchor=tkinter.CENTER)
|
self.button_3.place(relx=0.5, y=y + 160, anchor=tkinter.CENTER)
|
||||||
self.button_3.configure(border_color=("#4F90F8", "#6FADF9"), hover_color=("#3A65E8", "#4376EE"))
|
self.button_3.configure(border_color=("#4F90F8", "#6FADF9"), hover_color=("#3A65E8", "#4376EE"))
|
||||||
self.button_3.configure(fg_color=None)
|
self.button_3.configure(fg_color=None)
|
||||||
|
|
||||||
self.entry_3 = customtkinter.CTkEntry(master=self.ctk_frame_customized, text_font=("times", 16))
|
self.entry_3 = customtkinter.CTkEntry(master=self.ctk_frame_customized, font=("times", 16))
|
||||||
self.entry_3.place(relx=0.5, y=y + 240, anchor=tkinter.CENTER)
|
self.entry_3.place(relx=0.5, y=y + 240, anchor=tkinter.CENTER)
|
||||||
self.entry_3.configure(fg_color=("gray60", "gray5"), corner_radius=20)
|
self.entry_3.configure(fg_color=("gray60", "gray5"), corner_radius=20)
|
||||||
self.entry_3.insert(0, "1234567890")
|
self.entry_3.insert(0, "1234567890")
|
||||||
@ -131,7 +131,7 @@ class TestApp(customtkinter.CTk):
|
|||||||
self.slider_3.configure(button_color="#8AE0C3", fg_color=("#EBECF3", "#4B577E"), progress_color=("gray30", "gray10"))
|
self.slider_3.configure(button_color="#8AE0C3", fg_color=("#EBECF3", "#4B577E"), progress_color=("gray30", "gray10"))
|
||||||
self.slider_3.configure(from_=0, to=1)
|
self.slider_3.configure(from_=0, to=1)
|
||||||
|
|
||||||
self.check_box_3 = customtkinter.CTkCheckBox(master=self.ctk_frame_customized, corner_radius=50, text_font=("times", 16))
|
self.check_box_3 = customtkinter.CTkCheckBox(master=self.ctk_frame_customized, corner_radius=50, font=("times", 16))
|
||||||
self.check_box_3.place(relx=0.5, y=y + 480, anchor=tkinter.CENTER)
|
self.check_box_3.place(relx=0.5, y=y + 480, anchor=tkinter.CENTER)
|
||||||
self.check_box_3.configure(border_color="#8AE0C3")
|
self.check_box_3.configure(border_color="#8AE0C3")
|
||||||
|
|
||||||
@ -176,4 +176,4 @@ class TestApp(customtkinter.CTk):
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_app = TestApp()
|
test_app = TestApp()
|
||||||
test_app.mainloop()
|
test_app.mainloop()
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import tkinter
|
import tkinter
|
||||||
import tkinter.messagebox
|
import tkinter.messagebox
|
||||||
from tkinter import filedialog as fd
|
|
||||||
import customtkinter
|
import customtkinter
|
||||||
|
|
||||||
|
|
||||||
@ -23,35 +22,31 @@ class App(customtkinter.CTk):
|
|||||||
self.minsize(App.WIDTH, App.HEIGHT)
|
self.minsize(App.WIDTH, App.HEIGHT)
|
||||||
|
|
||||||
self.protocol("WM_DELETE_WINDOW", self.on_closing)
|
self.protocol("WM_DELETE_WINDOW", self.on_closing)
|
||||||
# ============ create two CTkFrames ============
|
|
||||||
|
|
||||||
self.frame_left = customtkinter.CTkFrame(master=self,
|
self.frame_left = customtkinter.CTkFrame(master=self,
|
||||||
width=220,
|
width=220,
|
||||||
height=App.HEIGHT-40,
|
height=App.HEIGHT-40,
|
||||||
corner_radius=5)
|
corner_radius=5)
|
||||||
self.frame_left.place(relx=0.38, rely=0.5, anchor=tkinter.E)
|
self.frame_left.place(relx=0.38, rely=0.5, anchor=tkinter.E)
|
||||||
|
|
||||||
self.frame_right = customtkinter.CTkFrame(master=self,
|
self.frame_right = customtkinter.CTkFrame(master=self,
|
||||||
width=350,
|
width=350,
|
||||||
height=App.HEIGHT-40,
|
height=App.HEIGHT-40,
|
||||||
corner_radius=5)
|
corner_radius=5)
|
||||||
self.frame_right.place(relx=0.40, rely=0.5, anchor=tkinter.W)
|
self.frame_right.place(relx=0.40, rely=0.5, anchor=tkinter.W)
|
||||||
|
|
||||||
# # ============ frame_right ============
|
|
||||||
|
|
||||||
self.button_output = customtkinter.CTkButton(master=self.frame_right, border_color=App.MAIN_COLOR,
|
self.button_output = customtkinter.CTkButton(master=self.frame_right, border_color=App.MAIN_COLOR,
|
||||||
fg_color=None, hover_color=App.MAIN_HOVER,
|
fg_color=None, hover_color=App.MAIN_HOVER,
|
||||||
height=28, text="Output Folder", command=self.button_outputFunc,
|
height=28, text="Output Folder", command=self.button_outputFunc,
|
||||||
border_width=3, corner_radius=10, text_font=('Calibri',12))
|
border_width=3, corner_radius=10, font=('Calibri',12))
|
||||||
self.button_output.place(relx=0.05, rely=0.06, anchor=tkinter.NW)
|
self.button_output.place(relx=0.05, rely=0.06, anchor=tkinter.NW)
|
||||||
self.entry_output = customtkinter.CTkEntry(master=self.frame_right, width=320, height=38, corner_radius=5)
|
self.entry_output = customtkinter.CTkEntry(master=self.frame_right, width=320, height=38, corner_radius=5)
|
||||||
self.entry_output.place(relx=0.05, rely=0.18, anchor=tkinter.NW)
|
self.entry_output.place(relx=0.05, rely=0.18, anchor=tkinter.NW)
|
||||||
|
|
||||||
def button_outputFunc(self):
|
def button_outputFunc(self):
|
||||||
self.entry_output.delete(0, 'end')
|
self.entry_output.delete(0, 'end')
|
||||||
filename = fd.askdirectory()
|
filename = customtkinter.filedialog.askdirectory()
|
||||||
self.entry_output.insert(0,str(filename))
|
self.entry_output.insert(0, str(filename))
|
||||||
pass
|
|
||||||
|
|
||||||
def on_closing(self, event=0):
|
def on_closing(self, event=0):
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
@ -7,7 +7,8 @@ app.geometry("600x950")
|
|||||||
switch_1 = customtkinter.CTkSwitch(app, text="darkmode", command=lambda: customtkinter.set_appearance_mode("dark" if switch_1.get() == 1 else "light"))
|
switch_1 = customtkinter.CTkSwitch(app, text="darkmode", command=lambda: customtkinter.set_appearance_mode("dark" if switch_1.get() == 1 else "light"))
|
||||||
switch_1.pack(padx=20, pady=20)
|
switch_1.pack(padx=20, pady=20)
|
||||||
|
|
||||||
seg_1 = customtkinter._CTkSegmentedButton(app, values=["value 1", "Value 2", "Value 42", "Value 123", "longlonglong"])
|
seg_1 = customtkinter._CTkSegmentedButton(app, values=[])
|
||||||
|
seg_1.configure(values=["value 1", "Value 2", "Value 42", "Value 123", "longlonglong"])
|
||||||
seg_1.pack(padx=20, pady=20)
|
seg_1.pack(padx=20, pady=20)
|
||||||
|
|
||||||
frame_1 = customtkinter.CTkFrame(app, height=100)
|
frame_1 = customtkinter.CTkFrame(app, height=100)
|
||||||
@ -16,22 +17,23 @@ frame_1.pack(padx=20, pady=20, fill="x")
|
|||||||
seg_2_var = customtkinter.StringVar(value="value 1")
|
seg_2_var = customtkinter.StringVar(value="value 1")
|
||||||
|
|
||||||
seg_2 = customtkinter._CTkSegmentedButton(frame_1, values=["value 1", "Value 2", "Value 42"], variable=seg_2_var)
|
seg_2 = customtkinter._CTkSegmentedButton(frame_1, values=["value 1", "Value 2", "Value 42"], variable=seg_2_var)
|
||||||
seg_2.pack(padx=20, pady=20)
|
seg_2.configure(values=[])
|
||||||
|
seg_2.configure(values=["value 1", "Value 2", "Value 42"])
|
||||||
seg_2.insert_value(0, "insert at 0")
|
seg_2.pack(padx=20, pady=10)
|
||||||
seg_2.insert_value(1, "insert at 1")
|
seg_2.insert(0, "insert at 0")
|
||||||
|
seg_2.insert(1, "insert at 1")
|
||||||
|
|
||||||
label_seg_2 = customtkinter.CTkLabel(frame_1, textvariable=seg_2_var)
|
label_seg_2 = customtkinter.CTkLabel(frame_1, textvariable=seg_2_var)
|
||||||
label_seg_2.pack(padx=20, pady=20)
|
label_seg_2.pack(padx=20, pady=10)
|
||||||
|
|
||||||
frame_1_1 = customtkinter.CTkFrame(frame_1, height=100)
|
frame_1_1 = customtkinter.CTkFrame(frame_1, height=100)
|
||||||
frame_1_1.pack(padx=20, pady=20, fill="x")
|
frame_1_1.pack(padx=20, pady=10, fill="x")
|
||||||
|
|
||||||
switch_2 = customtkinter.CTkSwitch(frame_1_1, text="change fg", command=lambda: frame_1_1.configure(fg_color="red" if switch_2.get() == 1 else "green"))
|
switch_2 = customtkinter.CTkSwitch(frame_1_1, text="change fg", command=lambda: frame_1_1.configure(fg_color="red" if switch_2.get() == 1 else "green"))
|
||||||
switch_2.pack(padx=20, pady=20)
|
switch_2.pack(padx=20, pady=20)
|
||||||
|
|
||||||
seg_3 = customtkinter._CTkSegmentedButton(frame_1_1, values=["value 1", "Value 2", "Value 42"])
|
seg_3 = customtkinter._CTkSegmentedButton(frame_1_1, values=["value 1", "Value 2", "Value 42"])
|
||||||
seg_3.pack(padx=20, pady=20)
|
seg_3.pack(padx=20, pady=10)
|
||||||
|
|
||||||
seg_4 = customtkinter._CTkSegmentedButton(app)
|
seg_4 = customtkinter._CTkSegmentedButton(app)
|
||||||
seg_4.pack(padx=20, pady=20)
|
seg_4.pack(padx=20, pady=20)
|
||||||
@ -41,14 +43,14 @@ seg_5 = customtkinter._CTkSegmentedButton(app, corner_radius=1000, border_width=
|
|||||||
variable=seg_5_var)
|
variable=seg_5_var)
|
||||||
seg_5.pack(padx=20, pady=20)
|
seg_5.pack(padx=20, pady=20)
|
||||||
seg_5.configure(values=["1", "2", "3", "4"])
|
seg_5.configure(values=["1", "2", "3", "4"])
|
||||||
seg_5.insert_value(0, "insert begin")
|
seg_5.insert(0, "insert begin")
|
||||||
seg_5.insert_value(len(seg_5.cget("values")), "insert 1")
|
seg_5.insert(len(seg_5.cget("values")), "insert 1")
|
||||||
seg_5.insert_value(len(seg_5.cget("values")), "insert 2")
|
seg_5.insert(len(seg_5.cget("values")), "insert 2")
|
||||||
seg_5.insert_value(len(seg_5.cget("values")), "insert 3")
|
seg_5.insert(len(seg_5.cget("values")), "insert 3")
|
||||||
seg_5.configure(fg_color="green")
|
seg_5.configure(fg_color="green")
|
||||||
|
|
||||||
seg_5.set("insert 2")
|
seg_5.set("insert 2")
|
||||||
seg_5.remove_value("insert 2")
|
seg_5.delete("insert 2")
|
||||||
|
|
||||||
label_seg_5 = customtkinter.CTkLabel(app, textvariable=seg_5_var)
|
label_seg_5 = customtkinter.CTkLabel(app, textvariable=seg_5_var)
|
||||||
label_seg_5.pack(padx=20, pady=20)
|
label_seg_5.pack(padx=20, pady=20)
|
||||||
@ -58,14 +60,19 @@ seg_6 = customtkinter._CTkSegmentedButton(app, width=300)
|
|||||||
seg_6.pack(padx=20, pady=20)
|
seg_6.pack(padx=20, pady=20)
|
||||||
entry_6 = customtkinter.CTkEntry(app)
|
entry_6 = customtkinter.CTkEntry(app)
|
||||||
entry_6.pack(padx=20, pady=(0, 20))
|
entry_6.pack(padx=20, pady=(0, 20))
|
||||||
button_6 = customtkinter.CTkButton(app, text="set", command=lambda: seg_6.set(entry_6.get()), corner_radius=1000)
|
button_6 = customtkinter.CTkButton(app, text="set", command=lambda: seg_6.set(entry_6.get()))
|
||||||
button_6.pack(padx=20, pady=(0, 20))
|
button_6.pack(padx=20, pady=(0, 20))
|
||||||
button_6 = customtkinter.CTkButton(app, text="insert value", command=lambda: seg_6.insert_value(0, entry_6.get()))
|
button_6 = customtkinter.CTkButton(app, text="insert value", command=lambda: seg_6.insert(0, entry_6.get()))
|
||||||
button_6.pack(padx=20, pady=(0, 20))
|
button_6.pack(padx=20, pady=(0, 20))
|
||||||
label_6 = customtkinter.CTkLabel(app, textvariable=seg_6_var)
|
label_6 = customtkinter.CTkLabel(app, textvariable=seg_6_var)
|
||||||
label_6.pack(padx=20, pady=(0, 20))
|
label_6.pack(padx=20, pady=(0, 20))
|
||||||
|
|
||||||
seg_6.configure(height=50, variable=seg_6_var)
|
seg_6.configure(height=50, variable=seg_6_var)
|
||||||
seg_6.remove_value("CTkSegmentedButton")
|
seg_6.delete("CTkSegmentedButton")
|
||||||
|
|
||||||
|
seg_7 = customtkinter._CTkSegmentedButton(app, values=["disabled seg button", "2", "3"])
|
||||||
|
seg_7.pack(padx=20, pady=20)
|
||||||
|
seg_7.configure(state="disabled")
|
||||||
|
seg_7.set("2")
|
||||||
|
|
||||||
app.mainloop()
|
app.mainloop()
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
import customtkinter
|
import customtkinter
|
||||||
import tkinter.ttk as ttk
|
|
||||||
|
|
||||||
app = customtkinter.CTk()
|
app = customtkinter.CTk()
|
||||||
|
|
||||||
tabview = customtkinter._CTkTabview(app)
|
tabview_1 = customtkinter._CTkTabview(app)
|
||||||
tabview.pack(pady=20, padx=20)
|
tabview_1.pack(padx=20, pady=20)
|
||||||
|
tabview_1.add("tab 1")
|
||||||
|
tabview_1.insert(0, "tab 0 g |ß$§")
|
||||||
|
|
||||||
tabview.create_tab(identifier="tab1", text="Tab 1")
|
app.update()
|
||||||
tabview.select_tab("tab1")
|
|
||||||
|
|
||||||
|
tabview_1._segmented_button._buttons_dict["tab 0 g |ß$§"]._text_label.configure(padx=0, pady=0, bd=0)
|
||||||
switch = customtkinter.CTkSwitch(app, text="Darkmode", onvalue="dark", offvalue="light",
|
tabview_1._segmented_button._buttons_dict["tab 0 g |ß$§"]._text_label.configure(bg="red")
|
||||||
command=lambda: customtkinter.set_appearance_mode(switch.get()))
|
|
||||||
switch.pack(padx=20, pady=20)
|
|
||||||
app.mainloop()
|
app.mainloop()
|
||||||
|
Loading…
Reference in New Issue
Block a user