Search code examples
pythontkintertkinter-entry

Entry.delete in Tkinter not clearing


I tried making a simple number checker that shows if the number is correct or wrong. After some hastily written prototype code, I can't get the fields to clear. I dug through many questions regarding this topic, but couldn't find an answer. My attempt is in show_result()

What am I doing wrong?

It should accept the numbers, and with the last number; verify. If it's correct, show accepted-image, else show denied-image and clear Entries after wrong entry. And after 3 seconds remove the image.

I suspect the num_limit() function messes something up, but I can't figure what.

All other files can be found here: https://bytebitten.stackstorage.com/s/JeRD33P92Us4a1Li

from tkinter import *
import time

#####
# Variables
code_check = 0
codeLength = 4
list3 = 123, 456
list4 = 2345, 3452

#####
# System

root = Tk()
root.title('Code Verifier')
root.attributes('-fullscreen', True)
root.bind('<Escape>',lambda e: root.quit())

#####
# Functions

# Input limiter function (WIP)
def num_limit(p, this_field):
    global codeLength
    print("Entry" + this_field + ": " + p)
    
    this_field = int(this_field)
    
    entries = [entry1, entry2, entry3, entry4]
    
    next_field = entries[this_field]
    
    # Check if it's a number
    if p.isdigit():
        if this_field < codeLength:
            # Set focus on next field
            next_field.focus_set()
            pass
        else:
            code_checker()
        return True
    else:
        # Check if it's Backspace or del/home/end/PgUp/PgDn
        if p!="\x08" and p!="":
            return False
        else:
            if this_field < codeLength:
                next_field.focus_set()
            else:
                return True

def code_checker():
    global code_check
    global codeLength
    print("== Code Check ==")
    
    enteredCode = ''
    
    enteredCode += entry1.get()
    enteredCode += entry2.get()
    enteredCode += entry3.get()
    
    if codeLength == 3:
        if enteredCode in list3:
            code_check = 1
        else:
            code_check = 2
    if codeLength == 4:
        enteredCode += entry4.get()
        if enteredCode in list4:
            code_check = 1
        else:
            code_check = 2
    show_result()

def show_result():
    global code_check
    print("== Show Result ==")
    print(code_check)
    # If code is correct
    if code_check == 1:
        # Image code accepted
        main_canvas.create_image(width/2, 750, anchor=N, image=codeAccepted)
    # If code is wrong
    elif code_check == 2:
        # Image code denied
        main_canvas.create_image(width/2, 750, anchor=N, image=codeDenied)
        
        # Clear fields
        entry1.delete(0, END)
        entry2.delete(0, END)
        entry3.delete(0, END)
        entry4.delete(0, END)
        
        # Set focus to first field
        entry1.focus_set()
    else:
        pass

#####
# Screen items

# Load images
codeDenied = PhotoImage(file='Assets/code_denied.png')
codeAccepted = PhotoImage(file='Assets/code_accepted.png')

# Set fullscreen canvas
main_canvas = Canvas(root, bg="#000000", bd=0, highlightthickness=0)
main_canvas.pack(fill="both", expand=True)

width = root.winfo_screenwidth()
height = root.winfo_screenheight()

# Input num limiter command
vcmd = root.register(func=num_limit)

# 3-6 single-digit input fields
entry1 = Entry(root, validate='key', validatecommand=(vcmd, '%P', 1), font=("Helvetica", 100), fg="#000000", bg="#ffffff", width=1, bd=0)
entry2 = Entry(root, validate='key', validatecommand=(vcmd, '%P', 2), font=("Helvetica", 100), fg="#000000", bg="#ffffff", width=1, bd=0)
entry3 = Entry(root, validate='key', validatecommand=(vcmd, '%P', 3), font=("Helvetica", 100), fg="#000000", bg="#ffffff", width=1, bd=0)
entry4 = Entry(root, validate='key', validatecommand=(vcmd, '%P', 4), font=("Helvetica", 100), fg="#000000", bg="#ffffff", width=1, bd=0)

# Entry position adjust
field1 = -100
field2 = 0
field3 = 100
field4 = 150

# Entry placing
if codeLength == 3:
    entry_window1 = main_canvas.create_window(width+field1, 500, anchor=N, window=entry1)
    entry_window2 = main_canvas.create_window(width+field2, 500, anchor=N, window=entry2)
    entry_window3 = main_canvas.create_window(width+field3, 500, anchor=N, window=entry3)
elif codeLength == 4:
    field1 = field1-50
    field2 = field2-50
    field3 = field3-50
    entry_window1 = main_canvas.create_window(width/2+field1, 500, anchor=N, window=entry1)
    entry_window2 = main_canvas.create_window(width/2+field2, 500, anchor=N, window=entry2)
    entry_window3 = main_canvas.create_window(width/2+field3, 500, anchor=N, window=entry3)
    entry_window4 = main_canvas.create_window(width/2+field4, 500, anchor=N, window=entry4)
else:
    pass

#####

root.mainloop()

Solution

  • Inside num_limit(), you should check whether the content of Entry is empty or not, if it is empty return True. Without this validation, you cannot delete content of the Entry as empty string is not a valid input.

    Also you called code_checker() before the validation function returns, so you will get empty string from Entry4 inside code_checker(). Use after() to schedule the execution of code_checker() after the validation.

    Finally, list3 and list4 are list of integers, but enteredCode is string, so the checking result will always be 2. Convert enteredCode to integer before checking.

    Below are modified num_limit() and code_checker():

    def num_limit(p, this_field):
        global codeLength
    
        ### check for empty string
        if p == "": return True
    
        print("Entry" + this_field + ": " + p)
        
        this_field = int(this_field)
        
        entries = [entry1, entry2, entry3, entry4]
        
        if this_field < codeLength:
            next_field = entries[this_field]
        
        # Check if it's a number
        if p.isdigit():
            if this_field < codeLength:
                # Set focus on next field
                next_field.focus_set()
            else:
                # schedule execution of code_checker() after validation
                root.after(100, code_checker)
            return True
        else:
            # Check if it's Backspace or del/home/end/PgUp/PgDn
            if p!="\x08" and p!="":
                return False
            else:
                if this_field < codeLength:
                    next_field.focus_set()
                else:
                    return True
    
    def code_checker():
        global code_check
        global codeLength
        print("== Code Check ==")
        
        enteredCode = ''
        
        enteredCode += entry1.get()
        enteredCode += entry2.get()
        enteredCode += entry3.get()
        
        if codeLength == 3:
            if int(enteredCode) in list3:  # convert enteredCode to integer
                code_check = 1
            else:
                code_check = 2
        if codeLength == 4:
            enteredCode += entry4.get()
            if int(enteredCode) in list4:  # convert enteredCode to integer
                code_check = 1
            else:
                code_check = 2
        show_result()