4
\$\begingroup\$

I made a placeholder for entry widgets from tkinter, so I was wondering how good it is. I just started learning Python a bit before, so please do correct me if I'm wrong or if I missed something, or some easy steps or where it loses the efficiency.

Code:

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: Potential bugs with config or configure method
    '''

    def __init__(self, master, placeholder, **kwargs):
        # style for ttk widget
        self.s = ttk.Style()
        self.s.configure('my.TEntry', foreground='black', font=(0, 0, 'normal'))
        self.s.configure('placeholder.TEntry', foreground='grey', font=(0, 0, 'bold'))

        # 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('<KeyRelease>',self._normal)

    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.configure(style='my.TEntry')
            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.configure(style='placeholder.TEntry')
            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.configure(style='my.TEntry')  # 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())

#usage of class
if __name__ == '__main__':
    root = tk.Tk()
    e = PlaceholderEntry(root,placeholder='Type something here...')
    e.pack(padx=10,pady=10)
    root.mainloop()

Edit:

The older update used global changes, which lead to problems when using more than one entry widget, now that is fixed.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.