2014-12-03 90 views
3

我正在使用validatecommand觀察並驗證輸入窗口控件「動態」的輸入。Tk窗口部件/窗口路徑名的訪問控件

validatecommand的標準用法可防止將無效字符輸入到觀察的條目窗口小部件中。這不是我喜歡的行爲,所以我使用validatecommand將條目小部件的字符串傳遞給另一個函數,並且在任何情況下都將其傳遞給return Truefloatstr_to_float使用稱爲preg的正則表達式驗證字符串。

如果正則表達式匹配輸入有效,則一切正常,因此print('approved')被執行。但是,如果用戶輸入了無效輸入,則正則表達式不匹配,print('not approved')將被執行,並且相應的條目窗口小部件應該填充爲紅色(顏色更改尚未正確實施)。

我到目前爲止所做的工作是使用<widget>.config(bg=<background>)來更改第一個條目窗口小部件的背景,以檢查是否能夠通過索引所有創建的條目窗口小部件的列表來訪問每個窗口小部件。

validatecommand可以將幾個arguments傳遞給執行函數(如輸入/文本字符串和窗口小部件/窗口路徑名)。所以一般來說,獲取對無效小部件的引用不是問題。但是,validatecommand傳遞的路徑名似乎不是python可訪問的。如何通過在包含有效輸入的小部件上執行<widget>.config(bg=<background>)來從此路徑名獲取參考(例如,唯一的變量名稱)以更改背景?

- 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() 

回答

2

您可以使用Tknametowidget方法。這會根據其名稱找到該小部件。如此使用:

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