fixed entry placeholder for textvariables and added test_entry_placeholder.py

This commit is contained in:
Tom Schimansky 2022-07-07 18:07:54 +02:00
parent 162997c7da
commit de33629e7d
6 changed files with 66 additions and 31 deletions

View File

@ -1,6 +1,6 @@
import tkinter
import sys
from typing import Union, Tuple, Callable
from typing import Union, Tuple, Callable, Literal
from .ctk_canvas import CTkCanvas
from ..theme_manager import ThemeManager

View File

@ -20,6 +20,7 @@ class CTkEntry(CTkBaseClass):
width=140,
height=28,
state=tkinter.NORMAL,
textvariable: tkinter.Variable = None,
**kwargs):
# transfer basic functionality (bg_color, size, _appearance_mode, scaling) to CTkBaseClass
@ -28,23 +29,30 @@ class CTkEntry(CTkBaseClass):
else:
super().__init__(*args, bg_color=bg_color, width=width, height=height)
# configure grid system (1x1)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
# color
self.fg_color = ThemeManager.theme["color"]["entry"] if fg_color == "default_theme" else fg_color
self.text_color = ThemeManager.theme["color"]["text"] if text_color == "default_theme" else text_color
self.placeholder_text_color = ThemeManager.theme["color"]["entry_placeholder_text"] if placeholder_text_color == "default_theme" else placeholder_text_color
self.text_font = (ThemeManager.theme["text"]["font"], ThemeManager.theme["text"]["size"]) if text_font == "default_theme" else text_font
self.border_color = ThemeManager.theme["color"]["entry_border"] if border_color == "default_theme" else border_color
# shape
self.corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius
self.border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width == "default_theme" else border_width
# placeholder text
self.placeholder_text = placeholder_text
self.placeholder_text_active = False
self.pre_placeholder_arguments = {} # some set arguments of the entry will be changed for placeholder and then set back
self.state = state
# textvariable
self.textvariable = textvariable
self.corner_radius = ThemeManager.theme["shape"]["button_corner_radius"] if corner_radius == "default_theme" else corner_radius
self.border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width == "default_theme" else border_width
self.state = state
self.canvas = CTkCanvas(master=self,
highlightthickness=0,
@ -59,6 +67,7 @@ class CTkEntry(CTkBaseClass):
highlightthickness=0,
font=self.apply_font_scaling(self.text_font),
state=self.state,
textvariable=self.textvariable,
**kwargs)
self.entry.grid(column=0, row=0, sticky="nswe",
padx=self.apply_widget_scaling(self.corner_radius) if self.corner_radius >= 6 else self.apply_widget_scaling(6),
@ -68,12 +77,9 @@ class CTkEntry(CTkBaseClass):
self.entry.bind('<FocusOut>', self.entry_focus_out)
self.entry.bind('<FocusIn>', self.entry_focus_in)
self.set_placeholder()
self.draw()
if self.placeholder_text is not None:
self.placeholder_text_active = True
self.set_placeholder()
def set_scaling(self, *args, **kwargs):
super().set_scaling( *args, **kwargs)
@ -175,6 +181,10 @@ class CTkEntry(CTkBaseClass):
self.placeholder_text_color = kwargs.pop("placeholder_text_color")
require_redraw = True
if "textvariable" in kwargs:
self.textvariable = kwargs.pop("textvariable")
self.entry.configure(textvariable=self.textvariable)
if "show" in kwargs:
if self.placeholder_text_active:
self.pre_placeholder_arguments["show"] = kwargs.pop("show")
@ -189,26 +199,28 @@ class CTkEntry(CTkBaseClass):
self.entry.configure(**kwargs) # pass remaining kwargs to entry
def set_placeholder(self):
self.pre_placeholder_arguments = {"show": self.entry.cget("show")}
self.entry.config(fg=ThemeManager.single_color(self.placeholder_text_color, self._appearance_mode), show="")
self.entry.delete(0, tkinter.END)
self.entry.insert(0, self.placeholder_text)
if self.entry.get() == "" and self.placeholder_text is not None and (self.textvariable is None or self.textvariable == ""):
self.placeholder_text_active = True
self.pre_placeholder_arguments = {"show": self.entry.cget("show")}
self.entry.config(fg=ThemeManager.single_color(self.placeholder_text_color, self._appearance_mode), show="")
self.entry.delete(0, tkinter.END)
self.entry.insert(0, self.placeholder_text)
def clear_placeholder(self):
self.entry.config(fg=ThemeManager.single_color(self.text_color, self._appearance_mode))
self.entry.delete(0, tkinter.END)
for argument, value in self.pre_placeholder_arguments.items():
self.entry[argument] = value
def entry_focus_out(self, event=None):
if self.entry.get() == "":
self.placeholder_text_active = True
self.set_placeholder()
def entry_focus_in(self, event=None):
if self.placeholder_text_active:
self.placeholder_text_active = False
self.clear_placeholder()
self.entry.config(fg=ThemeManager.single_color(self.text_color, self._appearance_mode))
self.entry.delete(0, tkinter.END)
for argument, value in self.pre_placeholder_arguments.items():
self.entry[argument] = value
def entry_focus_out(self, event=None):
self.set_placeholder()
def entry_focus_in(self, event=None):
self.clear_placeholder()
def delete(self, *args, **kwargs):
self.entry.delete(*args, **kwargs)
@ -218,9 +230,7 @@ class CTkEntry(CTkBaseClass):
self.set_placeholder()
def insert(self, *args, **kwargs):
if self.placeholder_text_active:
self.placeholder_text_active = False
self.clear_placeholder()
self.clear_placeholder()
return self.entry.insert(*args, **kwargs)

View File

@ -322,7 +322,5 @@ class CTkSwitch(CTkBaseClass):
self.variable_callback_name = self.variable.trace_add("write", self.variable_callback)
self.check_state = True if self.variable.get() == self.onvalue else False
require_redraw = True
else:
self.variable = None
super().configure(require_redraw=require_redraw, **kwargs)

View File

@ -17,7 +17,7 @@ from ..theme_manager import ThemeManager
class CTkBaseClass(tkinter.Frame):
""" Base class of every Ctk widget, handles the dimensions, bg_color,
""" Base class of every CTk widget, handles the dimensions, bg_color,
appearance_mode changes, scaling, bg changes of master if master is not a CTk widget """
def __init__(self,

View File

@ -12,7 +12,7 @@ def checkbox_event():
print("checkbox_event")
txt_var = tkinter.StringVar(value="")
entry_1 = customtkinter.CTkEntry(app, width=200, textvariable=txt_var)
entry_1 = customtkinter.CTkEntry(app, width=200, textvariable=txt_var, placeholder_text="placeholder")
entry_1.pack(pady=15)
txt_var.set("new text test")
if TEST_CONFIGURE: entry_1.configure(textvariable=txt_var)

View File

@ -0,0 +1,27 @@
import customtkinter
app = customtkinter.CTk() # create CTk window like you do with the Tk window (you can also use normal tkinter.Tk window)
app.geometry("400x400")
app.title("test_entry_placeholder.py")
str_var = customtkinter.StringVar(value="test")
entry_1 = customtkinter.CTkEntry(app, placeholder_text="placeholder", textvariable=str_var)
entry_1.pack(pady=20)
entry_2 = customtkinter.CTkEntry(app, placeholder_text="placeholder", textvariable=str_var)
entry_2.pack(pady=20)
entry_2.insert(0, "sdfjk ")
entry_2.delete(0, 2)
entry_3 = customtkinter.CTkEntry(app, placeholder_text="placeholder")
entry_3.pack(pady=(40, 20))
entry_3.insert(0, "sdfjk")
entry_3.delete(0, "end")
entry_4 = customtkinter.CTkEntry(app, placeholder_text="password", show="*")
entry_4.pack(pady=(20, 20))
entry_4.insert(0, "sdfjk")
entry_4.delete(0, 2)
app.mainloop()