I know this Q has been answered in this site, but im looking for a more simpler answer, and ive seen one before but then the question has been deleted or something, I cant find
Here is a very simple example. In this example we include a couple of features/caveats:
entry.input
will return None
if it's text is the placeholder or emptyentry.input
should be used in place of .get()
and .insert()
. The .input
logic is designed to give you the proper results for this type of widget. .get()
is not smart enough to return the proper data, and .insert()
has been reconfigured as a proxy to .input
.insert()
~ no need to use .delete()
. You should still use entry.input
instead#widgets.py
import tkinter as tk
class PlaceholderEntry(tk.Entry):
'''
All Of These Properties Are For Convenience
'''
@property
def input(self):
return self.get() if self.get() not in [self.__ph, ''] else None
@input.setter
def input(self, value):
self.delete(0, 'end')
self.insert(0, value)
self.configure(fg = self.ghost if value == self.__ph else self.normal)
@property
def isempty(self) -> bool:
return self.get() == ''
@property
def isholder(self) -> bool:
return self.get() == self.__ph
def __init__(self, master, placeholder, **kwargs):
tk.Entry.__init__(self, master, **{'disabledforeground':'#BBBBBB', **kwargs})
self.normal = self['foreground']
self.ghost = self['disabledforeground']
self.__ph = placeholder
self.input = placeholder
vcmd = self.register(self.validate)
self.configure(validate='all', validatecommand=(vcmd, '%S', '%s', '%d'))
self.bind('' , self.focusin)
self.bind('', self.focusout)
self.bind('' , self.check)
#rewire .insert() to be a proxy of .input
def validate(self, action_text, orig_text, action):
if action == '1':
if orig_text == self.__ph:
self.input = action_text
return True
#removes placeholder if necessary
def focusin(self, event=None):
if self.isholder:
self.input = ''
#adds placeholder if necessary
def focusout(self, event=None):
if self.isempty:
self.input = self.__ph
#juggles the placeholder while you type
def check(self, event):
if event.keysym == 'BackSpace':
if self.input and len(self.input) == 1:
self.input = self.__ph
self.icursor(0)
return 'break'
elif self.isholder:
if event.char:
self.input = ''
else:
return 'break'
usage example:
#__main__.py
import tkinter as tk
import widgets as ctk #custom tk
if __name__ == "__main__":
root = tk.Tk()
root.title("Placeholder Entry")
root.grid_columnconfigure(2, weight=1)
#init some data
entries = [] #for storing entry references
label_text = ['email', 'name']
entry_text = ['you@mail.com', 'John Smith']
#create form
for n, (label, placeholder) in enumerate(zip(label_text, entry_text)):
#make label
tk.Label(root, text=f'{label}: ', width=8, font='consolas 12 bold', anchor='w').grid(row=n, column=0, sticky='w')
#make entry
entries.append(ctk.PlaceholderEntry(root, placeholder, width=14, font='consolas 12 bold'))
entries[-1].grid(row=n, column=1, sticky='w')
#form submit function
def submit():
for l, e in zip(label_text, entries):
if e.input:
print(f'{l}: {e.input}')
#form submit button
tk.Button(root, text='submit', command=submit).grid(column=1, sticky='e')
root.mainloop()