0

I am trying to make the default text disappear when I click in text box to enter data. Also, if I should click on an Add Sales Data button, how would I make a new window pop up for them to enter the data?

from tkinter import *

root=Tk()
root.title("CPS")

menu = Label(root, text="MAIN MENU")
menu1 = Label(root, text="Choose an option below ")
menu2 = Button( root, text="Calculate sales data",
padx=110)
menu3 = Button(root, text=" Exit the Program", padx=70)

salesid =Entry(root, width=30)
salesid.insert(0,"Enter Your Sales ID: ")

salesamount =Entry(root, width=30)
salesamount.insert(0,"Enter Your Sales Amount: ")

class_type =Entry(root, width=30)
class_type.insert(0,"Enter Your Class type: ")

menu.pack()
menu1.pack()
menu2.pack()
menu3.pack()

salesid.pack()
salesamount.pack()
class_type.pack()

root.mainloop()
martineau
  • 119,623
  • 25
  • 170
  • 301
  • Welcome to Stack Overflow! Please try not to include multiple questions in one question. However, I think [this question](https://stackoverflow.com/q/27820178/16775594) should help you find what you need with your entries. – Sylvester Kruin Apr 30 '22 at 17:52
  • FYI, you can pop up new windows by creating [`Toplevel`](https://tkdocs.com/shipman/toplevel.html) widgets. It's a little like having a second `root` with an independent existence (and works better than trying to use more than one `Tk` instance). – martineau Apr 30 '22 at 18:54

1 Answers1

1

You are trying to make a placeholder/hint for your Entry. Tkinter Entrys, by default, doesn't have an option for placeholder text.

Solution

For making the default text disappear when you click in text box, you can add a binding for the mouse button to the Entry, to delete the existing text.

import tkinter as tk
...

salesid.bind("<Button-1>", lambda event: salesid.delete(0, tk.END))

Do notice that this does not bring back the placeholder text even after the focus is lost. In order to do that, you can check if the text in entry is the placeholder or not, and do deletions and insertions based on that. Example:

def focusIn(entry, placeholder):
    if entry.get() == placeholder:
        entry.delete(0, tk.END)

def focusOut(entry, placeholder):
    if entry.get() == "":
        entry.insert(0, placeholder)

placeholder = "Enter Your Sales ID: "
salesid = tk.Entry(root, width=30)
salesid.insert(0, placeholder)

salesid.bind("<FocusIn>", lambda e: focusIn(salesid, placeholder))
salesid.bind("<FocusOut>", lambda e: focusOut(salesid, "Enter Your Sales ID: "))

Now you can make this a custom Entry widget which can take a placeholder option:

class PlaceholderEntry(tk.Entry):
    def __init__(self, master, placeholder=None, *args, **kwargs):
        super().__init__(master, *args, **kwargs)
        self.placeholder = placeholder
        self.insert(0, self.placeholder)

        self.bind("<FocusIn>", self.focusIn)
        self.bind("<FocusOut>", self.focusOut)

    def focusIn(self, _):
        if self.get() == self.placeholder:
            self.delete(0, tk.END)

    def focusOut(self, _):
        if self.get() == "":
            self.insert(0, self.placeholder)

salesid = PlaceholderEntry(root, width=30, placeholder="Enter Your Sales ID: ")

Reference

Suggestions

A better way to approach your problem here would be using labels to show what the Entrys are for. You can create a Frame for all the labels and Entrys, then use grid geometry manager to add them like a table. Here's an example:

# try not to import globally
import tkinter as tk


root = tk.Tk()
root.title("CPS")

menu = tk.Label(root, text="MAIN MENU")
menu1 = tk.Label(root, text="Choose an option below ")
menu2 = tk.Button( root, text="Calculate sales data", padx=110)
menu3 = tk.Button(root, text=" Exit the Program", padx=70)

menu.pack()
menu1.pack()
menu2.pack()
menu3.pack()

# Frame to hold Labels and Entrys
details = tk.Frame()
details.pack(fill=tk.BOTH, expand=True)

lbl_salesid = tk.Label(details, text="Enter Your Sales ID: ")
salesid = tk.Entry(details, width=30)
lbl_sales_amount = tk.Label(details, text="Enter Your Sales Amount: ")
salesamount = tk.Entry(details, width=30)
lbl_class_type = tk.Label(details, text="Enter Your Class Type: ")
class_type = tk.Entry(details, width=30)

lbl_salesid.grid(row=0, column=0, sticky=tk.W)
salesid.grid(row=0, column=1)
lbl_sales_amount.grid(row=1, column=0, sticky=tk.W)
salesamount.grid(row=1, column=1)
lbl_class_type.grid(row=2, column=0, sticky=tk.W)
class_type.grid(row=2, column=1)

root.mainloop()

enter image description here

Billy
  • 1,157
  • 1
  • 9
  • 18
  • If you're not going to use `from tkinter import *`, then you're going to need to use `tk.END` (or hardcode the string literal `"end"`). – martineau Apr 30 '22 at 18:21
  • For the first three codeblocks, I was using the `from tkinter import *` from their code, So not to confuse them with `tk` since I wasn't posting the complete code there. But yes, I should use `tk.END` and point out the imported way instead, since that's the good practice. Fixed it. – Billy Apr 30 '22 at 18:35
  • When using `import tkinter as tk`, I often follow it with `from tkinter.constants import *` because it's relatively safe (name collision-wise) — and to, you know, avoid a foolish consistency. ;¬) – martineau Apr 30 '22 at 18:47
  • 1
    That's pretty great actually! I have felt prefixing every constants with `tk` a bit too spammy some times, and this solves the issue, thanks for sharing :D – Billy Apr 30 '22 at 18:56