Search code examples
pythontkinter

Tkinter Search Box with Editable Output


I am using the following TKinter Code to return a matching value from an existing dictionary.

However, in my use case, the returned value is not always going to be accurate; it is just a good guess based on past data. So I will need to be able to edit the second field after the 'guess'.

If I remove output_entry.delete(0, END) under def key_pressed(name, index, mode): upon keypress, values just accumulate with both the Entry and the Result.

As an example, If I type "A" in the Entry field, "1" will returns as a result. If I try to type "B" in the Result field to correct it, I will get "11B1" because each keypress is still calculating guesses from the Entry Field.

How can I modify this so that the second field will return a search of the dictionary by the first field, but remain editable (and overwrietable) upon clickingthe second field?

import tkinter as tk
from tkinter import *
import json

Lookup =  { "A": "1", "B": "2", "C": "3" }

app = Tk()
app.geometry("400x350")

input_var = tk.StringVar()
Label(app, text="Letter: ", padx=3, pady=3).grid(column=0, row=0)
input_entry = tk.Entry(width=15, textvariable=input_var)
input_entry.grid(column=1, row=0, padx=20, pady=20)

result_var = tk.StringVar()
Label(app, text="Number: ", padx=3, pady=3).grid(column=0, row=20)
output_entry = tk.Entry(app, width=15, textvariable=result_var)
output_entry.grid(column=1, row=20)

def key_pressed(name, index, mode):
    output_entry.delete(0, END)
    try:
        output_entry.insert(0, Lookup[input_entry.get()])
    except Exception:
        output_entry.insert(0, "")

output_entry.delete(0, END)
input_entry.delete(0, END) 
input_var.trace("w", key_pressed)
result_var.trace("w", key_pressed)

app.mainloop()

Solution

  • Maybe I'm misunderstanding the problem statement here a bit, but it seems to me that removing the trace on result_var does the trick just fine. Entering text into the Letter entry will populate the Number entry if a match is found, but the Number entry is still editable after the fact.

    I've also modified key_pressed to catch KeyError specifically, since that's what's actually thrown when a value from Letter isn't present in Lookup.keys() (it's good practice to catch exceptions as specifically as possible, and best to avoid except Exception if you can).

    I've also updated key_pressed to accept *_args since the arguments passed in by the trace are unused (this is just a convention thing).

    import tkinter as tk
    from tkinter import *
    import json
    
    Lookup =  { "A": "1", "B": "2", "C": "3" }
    
    app = Tk()
    app.geometry("400x350")
    
    input_var = tk.StringVar()
    Label(app, text="Letter: ", padx=3, pady=3).grid(column=0, row=0)
    input_entry = tk.Entry(width=15, textvariable=input_var)
    input_entry.grid(column=1, row=0, padx=20, pady=20)
    
    result_var = tk.StringVar()
    Label(app, text="Number: ", padx=3, pady=3).grid(column=0, row=20)
    output_entry = tk.Entry(app, width=15, textvariable=result_var)
    output_entry.grid(column=1, row=20)
    
    
    def key_pressed(*_args):
        output_entry.delete(0, END)
        try:
            output_entry.insert(0, Lookup[input_entry.get()])
        except KeyError:
            pass
    
    
    output_entry.delete(0, END)
    input_entry.delete(0, END)
    input_var.trace("w", key_pressed)
    # result_var.trace("w", key_pressed)  # get rid of this trace
    
    app.mainloop()