I have made a custom placeholder entry class that inherits from the ttk.Entry
. The problem with that is, it only works with the instantiation once, if I make two instances of the same entry, it will start to show some weird effects.
Class and its usage:
import tkinter as tk
from tkinter import ttk
class PlaceholderEntry(ttk.Entry):
'''
Custom modern Placeholder Entry box, takes positional argument master and placeholder\n
Use acquire() for getting output from entry widget\n
Use shove() for inserting into entry widget\n
Use remove() for deleting from entry widget\n
Use length() for getting the length of text in the widget\n
BUG 1: Possible bugs with binding to this class\n
BUG 2: Anomalous behaviour with config or configure method
'''
def __init__(self, master, placeholder, **kwargs):
# style for ttk widget
self.s = ttk.Style()
self.s.configure('my.TEntry')
# init entry box
ttk.Entry.__init__(self, master, style='my.TEntry', **kwargs)
self.text = placeholder
self.__has_placeholder = False # placeholder flag
# add placeholder if box empty
self._add()
# bindings of the widget
self.bind('<FocusIn>', self._clear)
self.bind('<FocusOut>', self._add)
self.bind_all('<Key>', self._normal)
self.bind_all('<Button-1>', self._cursor)
def _clear(self, *args): # method to remove the placeholder
if self.get() == self.text and self.__has_placeholder: # remove placeholder when focus gain
self.delete(0, tk.END)
self.s.configure('my.TEntry', foreground='black',
font=(0, 0, 'normal'))
self.__has_placeholder = False # set flag to false
def _add(self, *args): # method to add placeholder
if self.get() == '' and not self.__has_placeholder: # if no text add placeholder
self.s.configure('my.TEntry', foreground='grey',
font=(0, 0, 'bold'))
self.insert(0, self.text) # insert placeholder
self.icursor(0) # move insertion cursor to start of entrybox
self.__has_placeholder = True # set flag to true
def _normal(self, *args): # method to set the text to normal properties
self._add() # if empty add placeholder
if self.get() == self.text and self.__has_placeholder: # clear the placeholder if starts typing
self.bind('<Key>', self._clear)
self.icursor(-1) # keep insertion cursor to the end
else:
self.s.configure('my.TEntry', foreground='black',
font=(0, 0, 'normal')) # set normal font
def acquire(self): # custom method to get the text
if self.get() == self.text and self.__has_placeholder:
return 'None'
else:
return self.get()
def shove(self, index, string): # custom method to insert into entry
self._clear()
self.insert(index, string)
def remove(self, first, last): # custom method to remove from entry
if self.get() != self.text:
self.delete(first, last)
self._add()
elif self.acquire() == self.text and not self.__has_placeholder:
self.delete(first, last)
self._add()
def length(self):
if self.get() == self.text and self.__has_placeholder:
return 0
else:
return len(self.get())
def _cursor(self, *args): # method to not allow user to move cursor when placeholder exists
if self.get() == self.text and self.__has_placeholder:
self.icursor(0)
# MRE
if __name__ == '__main__':
root = tk.Tk()
e1 = PlaceholderEntry(root,'First Entry')
e1.pack()
e2 = PlaceholderEntry(root,'Second Entry')
e2.pack()
root.mainloop()
Here on clicking one of the entry and changing focus to the next entry, you can notice the "behavior" that the both the instances are somewhat linked? Although a single instance works perfectly fine. It was my first OOP project, so im not sure what went wrong.
Thanks in advance :D