如何在修改Tkinter Entry小部件时获取事件回调?

时间:2011-07-01 13:49:24

标签: python tkinter

正如问题所说。 Text个小部件有<<Modified>>个事件,但Entry个小部件似乎没有。

8 个答案:

答案 0 :(得分:61)

将Tkinter StringVar添加到Entry小部件中。使用trace方法将回调绑定到StringVar。

from Tkinter import *

def callback(sv):
    print sv.get()

root = Tk()
sv = StringVar()
sv.trace("w", lambda name, index, mode, sv=sv: callback(sv))
e = Entry(root, textvariable=sv)
e.pack()
root.mainloop()  

答案 1 :(得分:16)

在撰写本文时(2017年,Python 3.6,tkinter版本8.6.6),文档建议不推荐使用.trace。建议的表格现在似乎是:

sv.trace_add("write", callback)

如果您希望在更改变量时通知,则此方法非常有效。但是,我的应用程序只是在用户完成编辑文本时才想要通知。我发现了&#34;验证&#34;机制在这里运作良好:

from tkinter import *

root = Tk()
sv = StringVar()

def callback():
    print(sv.get())
    return True

e = Entry(root, textvariable=sv, validate="focusout", validatecommand=callback)
e.grid()
e = Entry(root)
e.grid()
root.mainloop()

每当条目小部件失去焦点时,这将调用callback(我添加了第二个条目小部件,因此第一个小部件实际上可能失去焦点!)

答案 2 :(得分:9)

谢谢史蒂文! Russell Owen的Tkinter Folklore解释了如何使用globalgetvar()直接从name参数(PY_VAR#)获取StringVar值,而不是如何将名称映射到窗口小部件。你改变回调算法的lambda方法就像魔术一样(对我们来说至少是Python新手)。

如果有多个条目,通常不仅要知道值,还要知道哪个条目已更改。稍微扩展了Steven的示例,以下(Python3)传递了一个索引,该索引可用于跟踪多个条目。

from tkinter import Tk, Frame, Label, Entry, StringVar

class Fruitlist:
    def entryupdate(self, sv, i):
        print(sv, i, self.fruit[i], sv.get())

    def __init__(self, root):
        cf = Frame(root)
        cf.pack()
        self.string_vars = []
        self.fruit = ("Apple", "Banana", "Cherry", "Date")
        for f in self.fruit:
            i = len(self.string_vars)
            self.string_vars.append(StringVar())
            self.string_vars[i].trace("w", lambda name, index, mode, var=self.string_vars[i], i=i:
                              self.entryupdate(var, i))
            Label(cf, text=f).grid(column=2, row=i)
            Entry(cf, width=6, textvariable=self.string_vars[i]).grid(column=4, row=i)

root = Tk()
root.title("EntryUpdate")
app = Fruitlist(root)
root.mainloop() 

答案 3 :(得分:0)

我知道其他变种。

在输入代码之前,它可以更好地解释编码路径:阅读here

并且有我的代码:

from Tkinter import *

class ttt:
   def __init__(self):
      self.str1 = StringVar()
      self.e1 = Entry(root, textvariable=self.str1)
      self.str1.trace('w', self.callback_1)
      self.e1.pack()

      self.str2 = StringVar()
      self.e2 = Entry(root, textvariable=self.str2, state='readonly')
      self.e2.pack()

      self.str3 = StringVar()
      self.e3 = Entry(root, textvariable=self.str3, state='readonly')
      self.e3.pack()

      bt = Button(root, text = 'ещё', command = self.callback_2)
      bt.pack()

   def callback_1(self, name='', index='', mode=''):
      tmp = self.str1.get()
      if tmp:
         self.str2.set(int(tmp) * 6)
         print self.str2.get()

   def callback_2(self, name='', index='', mode=''):
      tmp = self.str1.get()
      if tmp:
         self.str3.set(int(tmp) * 6)
         print self.str3.get()   

root = Tk()
t = ttt()
root.mainloop()

有两种变体:按下按钮并进入输入。 现在您可以选择任何变体

答案 4 :(得分:0)

我使用Python 3.6并且无法使.trace工作。以下代码允许接受或编辑StringVar的默认值。按下返回键时调用on_changed。

from tkinter import Tk, LEFT, BOTH, StringVar
from tkinter.ttk import Entry, Frame


class Example(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.parent = parent
        self.initUI()

    def initUI(self):
        self.parent.title("Entry")
        self.pack(fill=BOTH, expand=1)
        self.contents = StringVar()
        # give the StringVar a default value
        self.contents.set('test')
        self.entry = Entry(self)
        self.entry.pack(side=LEFT, padx=15)
        self.entry["textvariable"] = self.contents
        self.entry.bind('<Key-Return>', self.on_changed)

    def on_changed(self, event):
        print('contents: {}'.format(self.contents.get()))
        return True


def main():
    root = Tk()
    ex = Example(root)
    root.geometry("250x100+300+300")
    root.mainloop()


if __name__ == '__main__':
    main()

答案 5 :(得分:0)

您还可以使用KeyRelease事件,该事件将在用户单击窗口小部件时每次触发。
比滤除更改还重要。

from tkinter import * 
from tkinter import ttk

class GUI():                              
    def __init__(self):  
        self.root = Tk()
        self.sv = StringVar() 
        self.prevlaue=''
        #entry
        self.entry = ttk.Entry(self.root, width=30, textvariable =self.sv)
        self.entry.grid(pady=20,padx=20) 
        self.entry.bind("<KeyRelease>", self.OnEntryClick) #keyup                  
        self.root.mainloop()       

    def OnEntryClick(self, event):
        value=self.sv.get().strip()
        changed = True if self.prevlaue != value else False
        print(value, 'Text has changed ? {}'.format(changed))
        self.prevlaue = value

#create the gui
GUI()

希望对您有帮助。

答案 6 :(得分:0)

为什么需要知道Entry修改的时间?

可能您需要其他行为:

  1. 用户在“条目”中输入文字
  2. 用户按Enter键以应用更改

在这种情况下,您只需处理Enter键

self.entry.bind('<Return>', self.on_enter)

def on_enter(self, key_info):
    text = self.entry.get()

答案 7 :(得分:0)

我发现使用内置的TK验证更适合我的python初学者水平。 tkinter本身并未很好地记录Entry元素的验证,您必须使用register()方法设置回调,并且通过始终从已注册的验证回调中返回True,您可以通知。

def filter_callback(self,new_value):
    print(new_value)
    # must return true since we want the validation events to keep coming
    return(True)

def __init__(self,root)
    self.edit_filter = ttk.Entry(root)
    # %d = Type of action (1=insert, 0=delete, -1 for others)
    # %i = index of char string to be inserted/deleted, or -1
    # %P = value of the entry if the edit is allowed
    # %s = value of entry prior to editing
    # %S = the text string being inserted or deleted, if any
    # %v = the type of validation that is currently set
    # %V = the type of validation that triggered the callback
    #      (key, focusin, focusout, forced)
    # %W = the tk name of the widget
    vcmd = (self.edit_filter.register(self.filter_callback), "%P")
    # notify key presses only
    self.edit_filter.config(validate = "key", validatecommand = vcmd) 

(仅说明性代码)

此处的示例答案Interactively validating Entry widget content in tkinter,以及此处事件的一些文档https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/entry-validation.html。它的代码不少于使用trace,但对于某些初学者而言,可能更容易遵循和建立。