Search code examples
pythondictionarytkinterfocusin

tkinter: Dynamically change label text without repetitive If testing


I want unique messages associated with certain widget names to display as a single label's text when those widgets take focus. The messages are values in a dictionary corresponding to the dictionary's keys which are strings identical to the widget names. As shown, this works if I use repetitive IF statements to identify keys and display corresponding values, but I want to replace what would become a large collection of IF statements with a single function that does the same thing without the repetition. I've done this in Javascript but had to get help and I don't understand coding well enough to translate the js to Python. I've been working on this for days and the closest example I've found does something similar by getting the entry selection from a combobox. This might theoretically apply to my case if I had the experience to guess how a combobox knows what's going on inside it. Also if textvariable is not needed then how to do this without it, but since I'm "sharing the variable between two or more widgets" (per Bryan Oakley), I think it might be needed. I might even need two textvariables? Thanks.

import tkinter as tk
from tkinter import ttk

def clear(event):
    statusBar_value.set('')

def set_statusBar(event):
    w = widget_name
    focw = root.focus_get()
    if entry1==focw: 
        statusBar_value.set(w['entry1'])
    if entry2==focw:
        statusBar_value.set(w['entry2'])

root = tk.Tk()

statusBar_value = tk.StringVar()
statusBar_value.set('Status Bar...')

widget_name = {'entry1':'Entry 1 has focus', 'entry2':'Entry 2 has focus'}

entry1 = ttk.Entry(root)
dummy =  ttk.Entry(root)
entry2 = ttk.Entry(root)

statusBar = ttk.Label(root, textvariable = statusBar_value)

entry1.grid()
dummy.grid()
entry2.grid()

statusBar.grid()

entry1.bind('<FocusIn>', set_statusBar)
entry1.bind('<FocusOut>', clear)

entry2.bind('<FocusIn>', set_statusBar)
entry2.bind('<FocusOut>', clear)

root.mainloop()

Solution

  • A simple way to do this is to make the Entry widgets the keys of the widget_name dictionary:

    import tkinter as tk
    from tkinter import ttk
    
    def clear(event):
        statusBar_value.set('')
    
    def set_statusBar(event):
        statusBar_value.set(widget_name[event.widget])
    
    root = tk.Tk()
    
    statusBar_value = tk.StringVar()
    statusBar_value.set('Status Bar...')
    
    entry1 = ttk.Entry(root)
    dummy =  ttk.Entry(root)
    entry2 = ttk.Entry(root)
    
    widget_name = {entry1:'Entry 1 has focus', entry2:'Entry 2 has focus'}
    
    statusBar = ttk.Label(root, textvariable = statusBar_value)
    
    entry1.grid()
    dummy.grid()
    entry2.grid()
    
    statusBar.grid()
    
    entry1.bind('<FocusIn>', set_statusBar)
    entry1.bind('<FocusOut>', clear)
    
    entry2.bind('<FocusIn>', set_statusBar)
    entry2.bind('<FocusOut>', clear)
    
    root.mainloop()