tkinter: search widget by name in an efficient way

41 Views Asked by At

I like to isolate production code from gui code. I would like to set/retrieve widget values over message queues.

Therefore, given a named widget, I thought I could pass the name along with the set/retrieve message and let the gui code associate the name with the widget instance.

Unfortunately, I cannot simply pass the widget name, I need to pass the widget path which is sth like this: leftwindow.button_grid.my_button1. I don't want the production code need to know the complete path, as it contradicts my isolation purpose and is subject to change if the widgets in the gui are rearranged.

I know, I can run a recursion loop starting with the top level window and comparing the name of each widget with the name of the widget of interest. E.g.: Is it possible to search widget by name in Tkinter?

However, doing this every time I need to set/get a widget value is a performance penality.

Does somebody know how to do this in a more efficient way, given just the widget name without specifying the full widget path?

My idea is to implement an own parser which translates a widget pseudo path into an actual widget path, e.g.:

def translate_widget_pseudo_path(wpath: str):
    wpath = wpath.replace("process_control_buttons", "leftwindow.button_grid")
    wpath = wpath.replace("...", "...")
    return wpath

This way, I could isolate my code, providing a stable pseudo path to the production code and letting the gui decide which part of the pseudo path translate into which part of the actual path to the gui element.

1

There are 1 best solutions below

0
Suramuthu R On

As the code is not complete I've made a similar program from which you'll get a clear idea of how to do this. In the following program, there is a search-entry widget. When you search your preferred widget and enter(or if 'Go' button is pressed'), The cursor will go to the required entry-widget. Be creative and modify to search with part of the text as well. Modify other things as well according to your requirement.

Checked for its working. works perfect.

from tkinter import *
from tkinter import messagebox as mb

def goto_wdgt():
    x = dct['search_lbl'].get()
    
    # the actual key in the dct is search term + '_lbl'
    x = x + '_lbl'
    x = x.lower()
    
    if x == '':
        mb.showinfo('Enter Widget Name', 'Enter the widget Name or go to the widget directly')
    
    elif x in dct.keys():
        
        dct[x].focus_set()
    else:
        mb.showinfo('Wrong widget', f'There is no widget with name {x} available')



root = Tk()
root.geometry('500x700')

# Create a dct -all keys in small letters, for entry widgets value being blank
dct = { 'search': '',
        'search_lbl' : 'xxxx',
        'name': '',
        'name_lbl':'xxxx',
        'phone number': '',
        'phone number_lbl' : 'xxxx',
        'address 1st line' : '',
        'address 1st line_lbl' : 'xxxx',
        'address 2nd line': '',
        'address 2nd line_lbl' : 'xxxx',
        'pincode' : '',
        'pincode_lbl' : 'xxxx'
        }

#iterate thru dct to pack each widget
for key, val in dct.items():

    #if value is empty, the widget should be a Label and the text should be key.capitalize()
    if val == '':
        dct[key] = Label(root, text = key.capitalize())
        dct[key].pack(side='top')
    
    # if value is not empty the widget should be entry widget
    else:
        dct[key] = Entry(root)
        dct[key].pack(side='top')
        
    # if key is 'search_lbl', we need a btn after that to initiate search, map btn with function goto_wdgt
    if key == 'search_lbl':
        
        btn = Button(root, text = 'Go', command = goto_wdgt)
        btn.pack(side='top') 
        

# Bind search-entry widget with return-key inturn with btn so that search can also be initiated by pressing 'enter'
dct['search_lbl'].bind('<Return>', lambda evnt: btn.invoke())
      
root.mainloop()