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 tkinter
import sys import sys
from typing import Union, Tuple, Callable from typing import Union, Tuple, Callable, Literal
from .ctk_canvas import CTkCanvas from .ctk_canvas import CTkCanvas
from ..theme_manager import ThemeManager from ..theme_manager import ThemeManager

View File

@ -20,6 +20,7 @@ class CTkEntry(CTkBaseClass):
width=140, width=140,
height=28, height=28,
state=tkinter.NORMAL, state=tkinter.NORMAL,
textvariable: tkinter.Variable = None,
**kwargs): **kwargs):
# transfer basic functionality (bg_color, size, _appearance_mode, scaling) to CTkBaseClass # transfer basic functionality (bg_color, size, _appearance_mode, scaling) to CTkBaseClass
@ -28,23 +29,30 @@ class CTkEntry(CTkBaseClass):
else: else:
super().__init__(*args, bg_color=bg_color, width=width, height=height) super().__init__(*args, bg_color=bg_color, width=width, height=height)
# configure grid system (1x1)
self.grid_rowconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(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.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.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.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.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 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 = placeholder_text
self.placeholder_text_active = False 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.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.state = state
self.border_width = ThemeManager.theme["shape"]["entry_border_width"] if border_width == "default_theme" else border_width
self.canvas = CTkCanvas(master=self, self.canvas = CTkCanvas(master=self,
highlightthickness=0, highlightthickness=0,
@ -59,6 +67,7 @@ class CTkEntry(CTkBaseClass):
highlightthickness=0, highlightthickness=0,
font=self.apply_font_scaling(self.text_font), font=self.apply_font_scaling(self.text_font),
state=self.state, state=self.state,
textvariable=self.textvariable,
**kwargs) **kwargs)
self.entry.grid(column=0, row=0, sticky="nswe", 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), padx=self.apply_widget_scaling(self.corner_radius) if self.corner_radius >= 6 else self.apply_widget_scaling(6),
@ -68,11 +77,8 @@ class CTkEntry(CTkBaseClass):
self.entry.bind('<FocusOut>', self.entry_focus_out) self.entry.bind('<FocusOut>', self.entry_focus_out)
self.entry.bind('<FocusIn>', self.entry_focus_in) self.entry.bind('<FocusIn>', self.entry_focus_in)
self.draw()
if self.placeholder_text is not None:
self.placeholder_text_active = True
self.set_placeholder() self.set_placeholder()
self.draw()
def set_scaling(self, *args, **kwargs): def set_scaling(self, *args, **kwargs):
super().set_scaling( *args, **kwargs) super().set_scaling( *args, **kwargs)
@ -175,6 +181,10 @@ class CTkEntry(CTkBaseClass):
self.placeholder_text_color = kwargs.pop("placeholder_text_color") self.placeholder_text_color = kwargs.pop("placeholder_text_color")
require_redraw = True require_redraw = True
if "textvariable" in kwargs:
self.textvariable = kwargs.pop("textvariable")
self.entry.configure(textvariable=self.textvariable)
if "show" in kwargs: if "show" in kwargs:
if self.placeholder_text_active: if self.placeholder_text_active:
self.pre_placeholder_arguments["show"] = kwargs.pop("show") self.pre_placeholder_arguments["show"] = kwargs.pop("show")
@ -189,25 +199,27 @@ class CTkEntry(CTkBaseClass):
self.entry.configure(**kwargs) # pass remaining kwargs to entry self.entry.configure(**kwargs) # pass remaining kwargs to entry
def set_placeholder(self): def set_placeholder(self):
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.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.config(fg=ThemeManager.single_color(self.placeholder_text_color, self._appearance_mode), show="")
self.entry.delete(0, tkinter.END) self.entry.delete(0, tkinter.END)
self.entry.insert(0, self.placeholder_text) self.entry.insert(0, self.placeholder_text)
def clear_placeholder(self): def clear_placeholder(self):
if self.placeholder_text_active:
self.placeholder_text_active = False
self.entry.config(fg=ThemeManager.single_color(self.text_color, self._appearance_mode)) self.entry.config(fg=ThemeManager.single_color(self.text_color, self._appearance_mode))
self.entry.delete(0, tkinter.END) self.entry.delete(0, tkinter.END)
for argument, value in self.pre_placeholder_arguments.items(): for argument, value in self.pre_placeholder_arguments.items():
self.entry[argument] = value self.entry[argument] = value
def entry_focus_out(self, event=None): def entry_focus_out(self, event=None):
if self.entry.get() == "":
self.placeholder_text_active = True
self.set_placeholder() self.set_placeholder()
def entry_focus_in(self, event=None): def entry_focus_in(self, event=None):
if self.placeholder_text_active:
self.placeholder_text_active = False
self.clear_placeholder() self.clear_placeholder()
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):
@ -218,8 +230,6 @@ class CTkEntry(CTkBaseClass):
self.set_placeholder() self.set_placeholder()
def insert(self, *args, **kwargs): 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) 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.variable_callback_name = self.variable.trace_add("write", self.variable_callback)
self.check_state = True if self.variable.get() == self.onvalue else False self.check_state = True if self.variable.get() == self.onvalue else False
require_redraw = True require_redraw = True
else:
self.variable = None
super().configure(require_redraw=require_redraw, **kwargs) super().configure(require_redraw=require_redraw, **kwargs)

View File

@ -17,7 +17,7 @@ from ..theme_manager import ThemeManager
class CTkBaseClass(tkinter.Frame): 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 """ appearance_mode changes, scaling, bg changes of master if master is not a CTk widget """
def __init__(self, def __init__(self,

View File

@ -12,7 +12,7 @@ def checkbox_event():
print("checkbox_event") print("checkbox_event")
txt_var = tkinter.StringVar(value="") 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) entry_1.pack(pady=15)
txt_var.set("new text test") txt_var.set("new text test")
if TEST_CONFIGURE: entry_1.configure(textvariable=txt_var) 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()