How Can I Change This Python Code To Replace The Placeholder When A Different Item Is Clicked?

36 views Asked by At

I write this code:

from tkinter import * 


count = 0

def click_button(): 
    global count 
    count += 1
    print("You have clicked the button "+str(count)+" Times")

def submit():
    Username = Enter_Box.get() 
    print("You have set your username to: "+Username)
    delete()
    Enter_Box.config(state=DISABLED)

def delete(): 
    Enter_Box.delete(0,END)

def backspace(): 
    Enter_Box.delete(len(Enter_Box.get())-1,END)

def display():
    if (Check_Button_Status.get()==1): 
        print("You agree")
    else: 
        print("You don't agree")

def click(event):    
    Enter_Box.delete(0,END) 
     

Window = Tk() 

Photo = PhotoImage(file="Pig2.png")

Like_Button = PhotoImage(file="Like-Button2.png")

Window.geometry("900x600")

Window.title("The Ultimate GUI Program")

Window.iconbitmap("AngryBird9.ico")


button = Button(Window,
                text="Click me",
                command=click_button,
                font=("Comic Sans,",10,"bold"),
                fg="Red",
                bg="black",
                activeforeground="Red",
                activebackground="black",
                image=Like_Button,
                compound="bottom")

button.place(x=50,y=50)

Window.config(background="white")

#Adding an image and text onto the Window: 


Label = Label(Window, 
              text="You are using the best program ever!", 
              font=("Arial",10,"bold"),
              fg="red",
              bg="white",relief=RAISED,bd=10,
              padx=10,
              pady=10,image=Photo,
              compound="bottom")


Label.place(x=170,y=170) 

Enter_Box = Entry(Window,font=("Arial"),fg="Black",bg="Gray") 

Enter_Box.place(x=460,y=220)

Submit_button = Button(Window,
                       text="Submit",
                       command=submit)

Submit_button.place(x=700,y=220)

Delete_button = Button(Window,
                       text="Delete",
                       command=delete)

Delete_button.place(x=750,y=220)

BackSpace_button = Button(Window,
                          text="Backspace",
                          command=backspace)

BackSpace_button.place(x=795,y=220)

Check_Button_Status = IntVar()

Checkbox = Checkbutton(Window,
                       text="I agree to the TOS",
                       variable=Check_Button_Status,
                       onvalue=1,
                       offvalue=0,
                       command=display)

Checkbox.place(y=100,x=200)

Enter_Box.insert(0,"Enter username")
Enter_Box.bind("<Button-1>",click)


Window.mainloop()

Which has created this GUI program:

enter image description here

However when I press the entry box which says to enter "Username" it removes the place holder of "Enter username" just like most websites do however when clicking on a different item before submitting the username like the Like button or TOS agreement this placeholder does not come back like I would like it to.

How could I achieve the replacement of this placeholder when pressing a different item before submitting? I am guessing that I need to in some way detect when this entry box has been clicked again after a different item has been clicked on but I have no idea how to do so.

I have searched this up on YouTube however all of the videos I could understand to some extent were doing it without replacement and one I found had it so when your mouse leaves the box it replaces the placeholder.

1

There are 1 answers

2
JRiggles On

The most straightforward option is to create a custom widget class that inherits from Entry (either tk.Entry or ttk.Entry). Here's a basic example app with a PlaceholderEntry widget - you can simply use it anywhere you'd like an Entry with a placeholder value.

NB: The Button here is just to give something else focus so you can see that the placeholder text repopulates if the entry is empty when you click away from it.

import tkinter as tk
from tkinter import ttk


class App(tk.Tk):
    def __init__(self) -> None:
        super().__init__()
        self.geometry('400x400')
        self.title('Placeholder Entry Example')
        
        self.entry = PlaceholderEntry(self, 'placeholder text')
        self.entry.pack()
        
        self.btn = ttk.Button(self, text='Does Nothing')
        self.btn.pack()


class PlaceholderEntry(ttk.Entry):
    """Entry widget with focus-toggled placeholder text"""
    def __init__(
        self, parent, placeholder='', color='#828790', *args, **kwargs
    ) -> None:
        super().__init__(parent, *args, **kwargs)
        self.placeholder = placeholder
        self._ph_color = color
        self._default_fg = self._get_fg_string()  # default fg color
        # focus bindings
        self.bind('<FocusIn>', self.clear_placeholder)
        self.bind('<FocusOut>', self.set_placeholder)
        # initialize the placeholder
        self.set_placeholder()

    def clear_placeholder(self, *args) -> None:  # on focus in
        """Clear the placeholder text"""
        if self._get_fg_string() == self._ph_color:
            self.delete(0, tk.END)
            self.configure(foreground=self._default_fg)

    def set_placeholder(self, *args) -> None:  # on focus out
        """Restore the placeholder text"""
        if not self.get():  # if the entry has no text...
            self.insert(0, self.placeholder)
            self.configure(foreground=self._ph_color)

    def _get_fg_string(self) -> str:
        # Get string representation of the foreground color, otherwise 'cget'
        # returns a '_tkinter.Tcl_Obj' and focus won't clear the placeholder
        # This may be a bug in ttk
        # https://github.com/python/cpython/issues/98815
        return str(self.cget('foreground'))

    def ph_get(self) -> str:
        """
        Return the text. Wraps the builtin `get()` method to return an empty
        string if the placeholder is being shown, because using the regular
        `get()` method would otherwise return the placeholder text
        """
        return '' if (content := self.get()) == self.placeholder else content



if __name__ == '__main__':
    app = App()
    app.mainloop()

I've also added a helper method called ph_get() which you can use in place of the standard Entry.get() which would otherwise return the placeholder text, where ph_get returns an empty string if the placeholder is being shown.