access widget by Tk widget/window path name

python, python-3.x, tk-toolkit, tkinter, widget

Solution

You can use the `nametowidget` method of `Tk`. This finds the widget based on its name. So use:

self.change_bg(self.root.nametowidget(W), 1)

Problem

I am using `validatecommand` to observe and validate the input of an entry widget 'dynamically'. The standard usage of `validatecommand` prevents invalid characters from being entered to the observed entry widget. This is not the behaviour I like to have, so I used `validatecommand` to pass the string of the entry widget to another function and `return True` in any case. `floatstr_to_float` validates the string using a regular expression called `preg`. If the regex matches the input is valid, everything is OK and therefore `print('approved')` is executed. However, if the user entered invalid input, the regex does not match, `print('not approved')` is executed and the appropriate entry widget should be filled red (change of color not implemented properly yet). What I have done so far is changing the background of the very first entry widget using `<widget>.config(bg=<background>)` to check wheather I am able to access every widget by indexing a list of all created entry widgets. `validatecommand` can pass several arguments to the executed function (such as imput/text string and widget/window pathname). So getting a reference to the invalid widget in general is not a problem. However, the pathname passed by `validatecommand` does not seem to be python-accessable. How can I get a reference (e.g. unique variable name) from this pathname to change the background by executing `<widget>.config(bg=<background>)` on the widget containing (in)valid input? -- MWE -- ``` #!/usr/bin/env python3 # -*- coding: <utf-8> -*- # code adapted from: # http://stackoverflow.com/questions/4140437/python-tkinter-interactively-validating-entry-widget-content import tkinter as tk import re class MyApp(): def __init__(self): self.root = tk.Tk() self.parameternames = [ ('a', 'U'), ('b', 'U'), ('c', 'U'), ('d', 'U'), ('e', 'U'), ('f', 'U'), ('g', 'U'), ('h', 'U'), ('i', 'U'), ('j', 'U'), ('k', 'U'), ('l', 'U'), ('m', 'U'), ('n', 'U'), ('o', 'U'), ('p', 'U'), ('q', 'U'), ('r', 'U'), ('s', 'U'), ('t', 'U')] self.vcmd = (self.root.register(self.OnValidate), '%P', '%W') self.create_widgets() def create_widgets(self): self.entries = [] for i in enumerate(self.parameternames): entry = tk.Entry(self.root, validate="all", validatecommand=self.vcmd) self.default_bg = entry.cget("bg") entry.pack() self.entries.append(entry) self.root.mainloop() def OnValidate(self, P, W): # %P = value of the entry if the edit is allowed # %W = the tk name of the widget (pathname) print("OnValidate:") print("P='%s'" % P ) print("W='%s'" % W ) self.floatstr_to_float(P, W) # return True to display inserted character, validation is done by a re in 'floatstr_to_float()' return True def floatstr_to_float(self, fs, W): preg = re.compile('^\s*(?P<int>\d*)\s*[\.,]?\s*(?P<dec>\d*)\s*$') m = preg.match(fs) if m: print('approved') intprt=m.group('int') frcprt=m.group('dec') f = 0. if (intprt == '' and frcprt == '') else float('%s.%s' %(intprt, frcprt)) # not needed yet # currently: just changing the color of the first entry widget (proof of concept) # aim: pass unique name of edited entry widget to self.change_bg() for changing bg of # appropriate entry widget self.change_bg(self.entries[0], 1) else: print('not approved') # see comment in if-statement above self.change_bg(self.entries[0], 0) def change_bg(self, name, approved): if approved == 1: name.config(bg=self.default_bg) else: name.config(bg='#d9534f') app=MyApp() ```

Original source

Related problems