From ac0aa465d4272a8d4fa3bf5a6e91cbc57021f8b2 Mon Sep 17 00:00:00 2001 From: Tom Schimansky Date: Mon, 13 Sep 2021 14:27:29 +0200 Subject: [PATCH] updated slider, label --- Readme.md | 4 ++ customtkinter/customtkinter_button.py | 4 +- customtkinter/customtkinter_checkbox.py | 15 ++++- customtkinter/customtkinter_color_manager.py | 21 +++++-- customtkinter/customtkinter_label.py | 3 +- customtkinter/customtkinter_progressbar.py | 2 + customtkinter/customtkinter_slider.py | 61 ++++++++------------ examples/simple_example.py | 11 +++- setup.py | 2 +- 9 files changed, 72 insertions(+), 51 deletions(-) diff --git a/Readme.md b/Readme.md index e4729d0..e7ebc87 100644 --- a/Readme.md +++ b/Readme.md @@ -285,6 +285,8 @@ slider = customtkinter.CTkSlider(master=root_tk, width=160, height=16, border_width=5.5, + from_=0, + to=100, command=slider_event) slider.place(relx=0.5, rely=0.5, anchor=tkinter.CENTER) ``` @@ -297,6 +299,8 @@ master | root, tkinter.Frame or CTkFrame command | callback function, gest called when slider gets changed width | slider width in px height | slider height in px +from_ | lower slider value +to | upper slider value border_width | space around the slider rail in px fg_color | forground color, tuple: (light_color, dark_color) or single color bg_color | background color, tuple: (light_color, dark_color) or single color diff --git a/customtkinter/customtkinter_button.py b/customtkinter/customtkinter_button.py index fe54229..45af9f2 100644 --- a/customtkinter/customtkinter_button.py +++ b/customtkinter/customtkinter_button.py @@ -28,6 +28,8 @@ class CTkButton(tkinter.Frame): *args, **kwargs): super().__init__(*args, **kwargs) + AppearanceModeTracker.add(self.set_appearance_mode) + if bg_color is None: if isinstance(self.master, CTkFrame): self.bg_color = self.master.fg_color @@ -36,8 +38,6 @@ class CTkButton(tkinter.Frame): else: self.bg_color = bg_color - AppearanceModeTracker.add(self.set_appearance_mode) - self.fg_color = self.bg_color if fg_color is None else fg_color self.hover_color = self.bg_color if hover_color is None else hover_color diff --git a/customtkinter/customtkinter_checkbox.py b/customtkinter/customtkinter_checkbox.py index 3b52abd..684f206 100644 --- a/customtkinter/customtkinter_checkbox.py +++ b/customtkinter/customtkinter_checkbox.py @@ -22,10 +22,13 @@ class CTkCheckBox(tkinter.Frame): text_color=CTkColorManager.TEXT, text="CTkCheckBox", hover=True, + command=None, state=tkinter.NORMAL, *args, **kwargs): super().__init__(*args, **kwargs) + AppearanceModeTracker.add(self.set_appearance_mode) + if bg_color is None: if isinstance(self.master, CTkFrame): self.bg_color = self.master.fg_color @@ -34,8 +37,6 @@ class CTkCheckBox(tkinter.Frame): else: self.bg_color = bg_color - AppearanceModeTracker.add(self.set_appearance_mode) - self.fg_color = CTkColorManager.MAIN if fg_color is None else fg_color self.hover_color = CTkColorManager.MAIN_HOVER if hover_color is None else hover_color self.border_color = border_color @@ -71,6 +72,7 @@ class CTkCheckBox(tkinter.Frame): else: self.text_font = text_font + self.function = command self.state = state self.hover = hover self.check_state = False @@ -293,6 +295,9 @@ class CTkCheckBox(tkinter.Frame): else: self.canvas.itemconfig(part, fill=self.fg_color, width=0) + if self.function is not None: + self.function() + def select(self): self.check_state = True for part in self.canvas_fg_parts: @@ -301,6 +306,9 @@ class CTkCheckBox(tkinter.Frame): else: self.canvas.itemconfig(part, fill=self.fg_color, width=0) + if self.function is not None: + self.function() + def deselect(self): self.check_state = False for part in self.canvas_fg_parts: @@ -309,6 +317,9 @@ class CTkCheckBox(tkinter.Frame): else: self.canvas.itemconfig(part, fill=self.bg_color, width=0) + if self.function is not None: + self.function() + def get(self): return 1 if self.check_state is True else 0 diff --git a/customtkinter/customtkinter_color_manager.py b/customtkinter/customtkinter_color_manager.py index 595b132..ef7a129 100644 --- a/customtkinter/customtkinter_color_manager.py +++ b/customtkinter/customtkinter_color_manager.py @@ -2,6 +2,7 @@ import sys class CTkColorManager: + MAIN = ("#1C94CF", "#1C94CF") MAIN_HOVER = ("#5FB4DD", "#5FB4DD") ENTRY = ("white", "#222222") @@ -15,7 +16,18 @@ class CTkColorManager: DARKEN_COLOR_FACTOR = 0.8 # used for generate color for disabled button @staticmethod - def rgb2hex(rgb_color): + def single_color(color, appearance_mode: int) -> str: + """ color can be either a single hex color string or a color name or it can be a + tuple color with (light_color, dark_color). The functions then returns + always a single color string """ + + if type(color) == tuple: + return color[appearance_mode] + else: + return color + + @staticmethod + def rgb2hex(rgb_color: tuple): return "#{:02x}{:02x}{:02x}".format(round(rgb_color[0]), round(rgb_color[1]), round(rgb_color[2])) @staticmethod @@ -23,7 +35,7 @@ class CTkColorManager: return tuple(int(hex_color.strip("#")[i:i+2], 16) for i in (0, 2, 4)) @staticmethod - def darken_hex_color(hex_color): + def darken_hex_color(hex_color: str) -> str: try: rgb_color = CTkColorManager.hex2rgb(hex_color) dark_rgb_color = (rgb_color[0] * CTkColorManager.DARKEN_COLOR_FACTOR, @@ -31,15 +43,16 @@ class CTkColorManager: rgb_color[2] * CTkColorManager.DARKEN_COLOR_FACTOR) return CTkColorManager.rgb2hex(dark_rgb_color) except Exception as err: + sys.stderr.write("ERROR (CTkColorManager): failed to darken the following color: " + str(hex_color) + " " + str(err)) return hex_color @classmethod - def set_theme_color(cls, hex_color, hex_color_hover): + def set_theme_color(cls, hex_color: str, hex_color_hover: str): cls.MAIN = hex_color cls.MAIN_HOVER = hex_color_hover @classmethod - def set_theme(cls, main_color): + def set_theme(cls, main_color: str): if main_color.lower() == "green": cls.set_theme_color("#2EDEA4", "#82FCD4") diff --git a/customtkinter/customtkinter_label.py b/customtkinter/customtkinter_label.py index 9dce823..10b9d9e 100644 --- a/customtkinter/customtkinter_label.py +++ b/customtkinter/customtkinter_label.py @@ -122,7 +122,8 @@ class CTkLabel(tkinter.Frame): self.draw() def set_text(self, text): - self.text_label.configure(text=text, width=len(self.text)) + self.text = text + self.text_label.configure(text=self.text, width=len(self.text)) def change_appearance_mode(self, mode_string): if mode_string.lower() == "dark": diff --git a/customtkinter/customtkinter_progressbar.py b/customtkinter/customtkinter_progressbar.py index fba65b2..701bceb 100644 --- a/customtkinter/customtkinter_progressbar.py +++ b/customtkinter/customtkinter_progressbar.py @@ -6,6 +6,8 @@ from .customtkinter_color_manager import CTkColorManager class CTkProgressBar(tkinter.Frame): + """ tkinter custom progressbar, always horizontal, values are from 0 to 1 """ + def __init__(self, bg_color=None, border_color=CTkColorManager.PROGRESS_BG, diff --git a/customtkinter/customtkinter_slider.py b/customtkinter/customtkinter_slider.py index 1328be5..afe3be1 100644 --- a/customtkinter/customtkinter_slider.py +++ b/customtkinter/customtkinter_slider.py @@ -7,12 +7,16 @@ from .customtkinter_color_manager import CTkColorManager class CTkSlider(tkinter.Frame): + """ tkinter custom slider, always horizontal """ + def __init__(self, bg_color=None, border_color=None, fg_color=CTkColorManager.SLIDER_BG, button_color=CTkColorManager.MAIN, button_hover_color=CTkColorManager.MAIN_HOVER, + from_=0, + to=1, width=160, height=16, border_width=5.5, @@ -34,7 +38,6 @@ class CTkSlider(tkinter.Frame): self.fg_color = fg_color self.button_color = self.bg_color if button_color is None else button_color self.button_hover_color = self.bg_color if button_hover_color is None else button_hover_color - self.appearance_mode = AppearanceModeTracker.get_mode() # 0: "Light" 1: "Dark" self.width = width @@ -43,6 +46,9 @@ class CTkSlider(tkinter.Frame): self.callback_function = command self.value = 0.5 self.hover_state = False + self.from_ = from_ + self.to = to + self.output_value = self.from_ + (self.value * (self.to - self.from_)) self.configure(width=self.width, height=self.height) if sys.platform == "darwin": @@ -91,28 +97,16 @@ class CTkSlider(tkinter.Frame): self.button_parts.append(self.canvas.create_oval(self.value*self.width - self.height/2, 0, self.value*self.width + self.height/2, self.height)) - if type(self.bg_color) == tuple: - self.canvas.configure(bg=self.bg_color[self.appearance_mode]) - else: - self.canvas.configure(bg=self.bg_color) + self.canvas.configure(bg=CTkColorManager.single_color(self.bg_color, self.appearance_mode)) for part in self.border_parts: - if type(self.border_color) == tuple: - self.canvas.itemconfig(part, fill=self.border_color[self.appearance_mode], width=0) - else: - self.canvas.itemconfig(part, fill=self.border_color, width=0) + self.canvas.itemconfig(part, fill=CTkColorManager.single_color(self.border_color, self.appearance_mode), width=0) for part in self.fg_parts: - if type(self.fg_color) == tuple: - self.canvas.itemconfig(part, fill=self.fg_color[self.appearance_mode], width=0) - else: - self.canvas.itemconfig(part, fill=self.fg_color, width=0) + self.canvas.itemconfig(part, fill=CTkColorManager.single_color(self.fg_color, self.appearance_mode), width=0) for part in self.button_parts: - if type(self.button_color) == tuple: - self.canvas.itemconfig(part, fill=self.button_color[self.appearance_mode], width=0) - else: - self.canvas.itemconfig(part, fill=self.button_color, width=0) + self.canvas.itemconfig(part, fill=CTkColorManager.single_color(self.button_color, self.appearance_mode), width=0) def clicked(self, event=0): self.value = event.x / self.width @@ -122,10 +116,12 @@ class CTkSlider(tkinter.Frame): if self.value < 0: self.value = 0 + self.output_value = self.from_ + (self.value * (self.to - self.from_)) + self.update() if self.callback_function is not None: - self.callback_function(self.value) + self.callback_function(self.output_value) def update(self): for part in self.button_parts: @@ -136,41 +132,30 @@ class CTkSlider(tkinter.Frame): for part in self.button_parts: if self.hover_state is True: - if type(self.button_hover_color) == tuple: - self.canvas.itemconfig(part, fill=self.button_hover_color[self.appearance_mode], width=0) - else: - self.canvas.itemconfig(part, fill=self.button_hover_color, width=0) + self.canvas.itemconfig(part, fill=CTkColorManager.single_color(self.button_hover_color, self.appearance_mode), width=0) else: - if type(self.button_color) == tuple: - self.canvas.itemconfig(part, fill=self.button_color[self.appearance_mode], width=0) - else: - self.canvas.itemconfig(part, fill=self.button_color, width=0) + self.canvas.itemconfig(part, fill=CTkColorManager.single_color(self.button_color, self.appearance_mode), width=0) def on_enter(self, event=0): self.hover_state = True for part in self.button_parts: - if type(self.button_hover_color) == tuple: - self.canvas.itemconfig(part, fill=self.button_hover_color[self.appearance_mode], width=0) - else: - self.canvas.itemconfig(part, fill=self.button_hover_color, width=0) + self.canvas.itemconfig(part, fill=CTkColorManager.single_color(self.button_hover_color, self.appearance_mode), width=0) def on_leave(self, event=0): self.hover_state = False for part in self.button_parts: - if type(self.button_color) == tuple: - self.canvas.itemconfig(part, fill=self.button_color[self.appearance_mode], width=0) - else: - self.canvas.itemconfig(part, fill=self.button_color, width=0) + self.canvas.itemconfig(part, fill=CTkColorManager.single_color(self.button_color, self.appearance_mode), width=0) def get(self): - return self.value + return self.output_value - def set(self, value): - self.value = value + def set(self, output_value): + self.output_value = output_value + self.value = (self.output_value - self.from_) / (self.to - self.from_) self.update() if self.callback_function is not None: - self.callback_function(self.value) + self.callback_function(self.output_value) def change_appearance_mode(self, mode_string): if mode_string.lower() == "dark": diff --git a/examples/simple_example.py b/examples/simple_example.py index 4abe2f5..7a24651 100644 --- a/examples/simple_example.py +++ b/examples/simple_example.py @@ -11,13 +11,17 @@ root_tk.title("CustomTkinter Test") def button_function(): - print("CheckBox value:", checkbox_1.get()) + print("Button click") def slider_function(value): progressbar_1.set(value) +def check_box_function(): + print("checkbox_1:", checkbox_1.get()) + + frame_1 = customtkinter.CTkFrame(master=root_tk, width=300, height=260, corner_radius=15) frame_1.place(relx=0.5, rely=0.5, anchor=tkinter.CENTER) @@ -31,13 +35,14 @@ button_1 = customtkinter.CTkButton(master=frame_1, corner_radius=10, command=but button_1.place(relx=0.5, rely=0.4, anchor=tkinter.CENTER) # button_1.configure(state="disabled") -slider_1 = customtkinter.CTkSlider(master=frame_1, command=slider_function) +slider_1 = customtkinter.CTkSlider(master=frame_1, command=slider_function, from_=0, to=2) slider_1.place(relx=0.5, rely=0.55, anchor=tkinter.CENTER) +slider_1.set(1.5) entry_1 = customtkinter.CTkEntry(master=frame_1) entry_1.place(relx=0.5, rely=0.75, anchor=tkinter.CENTER) -checkbox_1 = customtkinter.CTkCheckBox(master=frame_1) +checkbox_1 = customtkinter.CTkCheckBox(master=frame_1, command=check_box_function) checkbox_1.place(relx=0.5, rely=0.9, anchor=tkinter.CENTER) root_tk.mainloop() diff --git a/setup.py b/setup.py index 7eb7bd6..45940ca 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup import os -# Update in pypi: +# Update on pypi: # # 1. delete old /dist # 2. python3 -m pip install --upgrade build