Home > Back-end >  How to clear what's inside a Text Widget when the user presses a new number in Tkinter?
How to clear what's inside a Text Widget when the user presses a new number in Tkinter?

Time:06-17

text = ""

e = Text(window, width = 15, height = 2, font = ("Times New Roman", 24))
e.grid(column = 0, row = 0, columnspan=5)

def show_value(val): # Displays the text when user clicks buttons
    global text
    text =str(val)
    e.insert(END, val)
    
def clear(): # Clears what's inside the text frame
    global text
    e.delete("1.0", "end")
    text = ""

def delete(): # Deletes the last value/character
    e.delete("end-2c") 

def equal(): # Computes
    global text
    try:
        text = str(eval(text))
        e.delete("1.0", "end")
        e.insert("1.0", text)
    except:
        clear()
        e.insert("1.0", "Error")

#Buttons

# button_negative = Button(window, text = " /-", width = 6, font = ("Arial", 10)) # ADD THIS SOON
button_zero = Button(window, text = "0", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(0))
button_one = Button(window, text = "1", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(1))
button_two = Button(window, text = "2", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(2))
button_three = Button(window, text = "3", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(3))
button_four = Button(window, text = "4", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(4))
button_five = Button(window, text = "5", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(5))
button_six = Button(window, text = "6", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(6))
button_seven = Button(window, text = "7", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(7))
button_eight = Button(window, text = "8", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(8))
button_nine = Button(window, text = "9", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(9))
button_equals = Button(window, text = "=", width = 6, font = ("Arial", 10), bg = "#7C3D00", fg = "white", command = equal)
button_decimal = Button(window, text = ".", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value("."))
button_add = Button(window, text = " ", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(" "))
button_subtract = Button(window, text = "-", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value("-"))
button_divide = Button(window, text = "/", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value("/"))
button_multiply = Button(window, text = "*", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value("*"))
button_clear = Button(window, text = "AC", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = clear)
button_delete = Button(window, text = "DEL", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = delete)
button_left_bracket = Button(window, text = "(", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value("("))
button_right_bracket = Button(window, text = ")", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(")"))

#button_negative.grid(row = 7, column = 0)
button_zero.grid(row = 7, column = 0)
button_decimal.grid(row = 7, column = 1)
button_equals.grid(row = 7, column = 3)
button_delete.grid(row = 7, column = 2)

button_one.grid(row = 5, column = 0)
button_two.grid(row = 5, column = 1)
button_three.grid(row = 5, column = 2)
button_add.grid(row = 5, column = 3)

button_four.grid(row = 4, column = 0)
button_five.grid(row = 4, column = 1)
button_six.grid(row = 4, column = 2)
button_subtract.grid(row = 4, column = 3)

button_seven.grid(row = 3, column = 0)
button_eight.grid(row = 3, column = 1)
button_nine.grid(row = 3, column = 2)
button_multiply.grid(row = 3, column = 3)

button_clear.grid(row = 2, column = 0)
button_left_bracket.grid(row = 2, column = 1)
button_right_bracket.grid(row = 2, column = 2)
button_divide.grid(row = 2, column = 3)

window.mainloop()


I'm still learning Python and wanted to create a Calculator as my first project. My issue is, when the user wants to compute 8 8 and clicks on the equals button, it displays 16. However, I want it to be cleared without pressing the all clear button when the user wants to calculate something new e.g 56 6 and displays that instead. How would I go about doing this?

CodePudding user response:

When manipulating GUI like tkinter, I recommend you to use Python classes, as it will be easier to manipulate elements.

As for your problem, does something like this suits your needs ?

#!/usr/bin/python3
import tkinter as tk

text = ""

CALCUL_DONE=False

window=tk.Tk()

e = tk.Text(window, width = 15, height = 2, font = ("Times New Roman", 24))
e.grid(column = 0, row = 0, columnspan=5)

def clear(): # Clears what's inside the text frame
    global text
    e.delete("1.0", "end")
    text = ""

def show_value(val): # Displays the text when user clicks buttons
    global text, CALCUL_DONE
    if CALCUL_DONE:
        clear()
        CALCUL_DONE=False
    text =str(val)
    e.insert(tk.END, val)
    

def delete(): # Deletes the last value/character
    e.delete("end-2c") 

def equal(): # Computes
    global text, CALCUL_DONE
    try:
        text = str(eval(text))
        e.delete("1.0", "end")
        e.insert("1.0", text)
        CALCUL_DONE=True
    except:
        clear()
        e.insert("1.0", "Error")

#Buttons

# button_negative = tk.Button(window, text = " /-", width = 6, font = ("Arial", 10)) # ADD THIS SOON
button_zero = tk.Button(window, text = "0", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(0))

[...]

button_right_bracket = tk.Button(window, text = ")", width = 6, font = ("Arial", 10), bg = "black", fg = "white", command = lambda: show_value(")"))

#button_negative.grid(row = 7, column = 0)
button_zero.grid(row = 7, column = 0)

[...]

button_divide.grid(row = 2, column = 3)

window.mainloop()

I added a boolean (CALCUL_DONE) initialized at False, so when you click on " ","-",... it changes its value to True, and when clicking on a number again, the funtion clear() is called.

CodePudding user response:

@sramazoth answer is the right basic idea, but unfortunately the way your code is written it won't work if the user is using the keyboard to enter values (and not just the displayed calculator's buttons). The problem is due to the use of that global text variable being used. Your attempt to make make its contents the same be the same as what is in the Text only works for clicking on the Buttons being displayed, but it's also possible for a user to directly enter values into the Text widget via the keyboard, which will not be detect by your code.

I corrected the issue by doing two things (in addition to adding a global flag like @sramazoth suggested):

  1. Eliminating the global text string variable completely — there's really no need for it since the text you need us already being stored in the Text widget itself.
  2. Added a keypress event handler and bound it to the Text widget which will set the global flag just like clicking on one of the buttons to enter a value would.

You also need to understand that applying eval() to untrusted user input is a severe security hazard because they can enter arbitrary code that can do bad things.

Given that caveat, here's the modified code:

import tkinter as tk
from tkinter.constants import *

clear_flag = False  # Indicates when Text widget should be cleared.

window = tk.Tk()

e = tk.Text(window, width=15, height=2, font=("Times New Roman", 24))
e.grid(column=0, row=0, columnspan=5)


def on_keypress(event):
    global clear_flag
    if clear_flag:
        clear()
        clear_flag = False

e.bind('<KeyPress>', on_keypress)

def show_value(val): # Displays the expression when user clicks buttons
    global clear_flag
    if clear_flag:
        clear()
        clear_flag = False
    e.insert(END, val)

def clear(): # Clears what's inside the expression frame
    e.delete("1.0", "end")

def delete(): # Deletes the last value/character
    e.delete("end-2c")

def equal(): # Computes
    global clear_flag
    try:
        result = eval(e.get("1.0", END))
        e.delete("1.0", "end")
        e.insert("1.0", result)
    except Exception as exc:
        clear()
        e.insert("1.0", "Error")
    clear_flag = True

#Buttons

# button_negative = tk.Button(window, text=" /-", width=6, font=("Arial", 10)) # ADD THIS SOON
button_zero = tk.Button(window, text="0", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value(0))
button_one = tk.Button(window, text="1", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value(1))
button_two = tk.Button(window, text="2", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value(2))
button_three = tk.Button(window, text="3", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value(3))
button_four = tk.Button(window, text="4", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value(4))
button_five = tk.Button(window, text="5", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value(5))
button_six = tk.Button(window, text="6", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value(6))
button_seven = tk.Button(window, text="7", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value(7))
button_eight = tk.Button(window, text="8", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value(8))
button_nine = tk.Button(window, text="9", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value(9))
button_equals = tk.Button(window, text="=", width=6, font=("Arial", 10), bg="#7C3D00", fg="white", command=equal)
button_decimal = tk.Button(window, text=".", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value("."))
button_add = tk.Button(window, text=" ", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value(" "))
button_subtract = tk.Button(window, text="-", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value("-"))
button_divide = tk.Button(window, text="/", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value("/"))
button_multiply = tk.Button(window, text="*", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value("*"))

button_clear = tk.Button(window, text="AC", width=6, font=("Arial", 10), bg="black", fg="white", command=clear)
button_delete = tk.Button(window, text="DEL", width=6, font=("Arial", 10), bg="black", fg="white", command=delete)

button_left_bracket = tk.Button(window, text="(", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value("("))
button_right_bracket=tk.Button(window, text=")", width=6, font=("Arial", 10), bg="black", fg="white", command=lambda: show_value(")"))

#button_negative.grid(row = 7, column = 0)
button_zero.grid(row = 7, column = 0)
button_decimal.grid(row = 7, column = 1)
button_equals.grid(row = 7, column = 3)
button_delete.grid(row = 7, column = 2)

button_one.grid(row = 5, column = 0)
button_two.grid(row = 5, column = 1)
button_three.grid(row = 5, column = 2)
button_add.grid(row = 5, column = 3)

button_four.grid(row = 4, column = 0)
button_five.grid(row = 4, column = 1)
button_six.grid(row = 4, column = 2)
button_subtract.grid(row = 4, column = 3)

button_seven.grid(row = 3, column = 0)
button_eight.grid(row = 3, column = 1)
button_nine.grid(row = 3, column = 2)
button_multiply.grid(row = 3, column = 3)

button_clear.grid(row = 2, column = 0)
button_left_bracket.grid(row = 2, column = 1)
button_right_bracket.grid(row = 2, column = 2)
button_divide.grid(row = 2, column = 3)

window.mainloop()

  • Related