Search code examples
pythontkinterplaceholder

User entering same placeholder text python tkinter


I made a placeholder for tkinter and was wondering to take it forward, but what if the user enters the same text as the placeholder, all the effects that are supposed to take place for the placeholders gets implemented onto the text. Anyway to overcome this?

Placeholder:

import tkinter as tk
from tkinter import ttk

class PlaceholderEntry(tk.Entry):
    '''
    Custom modern Placeholder Entry box, takes positional argument master and placeholder\n
    Use ret() for getting output from entry widget\n
    Use ins() for inserting into entry widget\n
    Use remove() for deleting from entry widget\n
    ISSUES: What if the user types exactly same text as the placeholders in the entrybox?
    '''

    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

        # 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):
        if self.get() == self.text:  # remove placeholder when focus gain
            self.delete(0, tk.END)
            self.s.configure('my.TEntry', foreground='black',
                             font=(0, 0, 'normal'))

    def add(self, *args):
        if self.get() == '':  # 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

    def normal(self, *args):
        self.s.configure('my.TEntry', foreground='black',
                         font=(0, 0, 'normal'))  # set normal font
        self.add()  # if empty add placeholder
        if self.get() == self.text:  # clear the placeholder if starts typing
            self.bind('<Key>', self.clear)
            self.icursor(-1)  # keep insertion cursor to the end

    def ret(self):  # custom method to get the text
        if self.get() == self.text:
            return None
        else:
            return self.get()

    def ins(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()

    def cursor(self, *args):  # method to not allow user to move cursor when placeholder there
        if self.get() == self.text:
            self.icursor(0)

if __name__ == '__main__':
    root = tk.Tk()
    plc = PlaceholderEntry(root,placeholder='Type')
    plc.pack(padx=10,pady=10)
    root.mainloop()

You can reproduce the issue by typing in Type on the box and its going to remove the further insertion because it mistakes the entry to be a placeholder.

Thanks in advance :D


Solution

  • Since you have a custom class, it's easy to set a flag when you add the placeholder text, and easy to unset it when you remove the placeholder. Then it's just a matter of checking whether or not the flag is set when you get the value.

    def add(self, *args):
        if self.get() == '':  # if no text add placeholder
            ...
            self._has_placeholder = True
    
    def clear(self, *args):
        if self.get() == self.text:  # remove placeholder when focus gain
            self._has_placeholder = False
            ...