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

问题描述 投票:0回答:9

正如问题所说。

Text
小部件具有
<<Modified>>
事件,但
Entry
小部件似乎没有。

python tkinter
9个回答
121
投票

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

67
投票

在撰写本文时(2017 年,Python 3.6,tkinter 版本 8.6.6),文档表明

.trace
已弃用。现在建议的形式似乎是:

sv.trace_add("write", callback)

如果您希望在变量更改时收到通知,这非常有效。但是,我的应用程序只想在用户完成编辑文本时收到通知。我发现“验证”机制在这里运行良好:

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
(我添加了第二个条目小部件,因此第一个条目实际上可以失去焦点!)


13
投票

谢谢史蒂文! Russell Owen 的 Tkinter Folklore 解释了如何使用 globalgetvar() 直接从名称参数 (PY_VAR#) 获取 StringVar 值,但没有解释如何将名称映射到小部件。更改回调参数的 lambda 方法就像魔法(至少对于我们 Python 新手来说)。

当有多个 Entry 时,通常不仅需要知道其值,还需要知道哪个 Entry 被更改。稍微扩展一下 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() 

11
投票

您还可以使用 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()

希望有帮助。


5
投票

我已经能够使用

<FocusOut>
事件完成我需要的事情。这是一个示例:

import tkinter
from tkinter import ttk

def doSomething(event):
    text = event.widget.get()
    print(text)

window = tkinter.Tk()
testEntry = ttk.Entry(window)
testEntry.bind('<FocusOut>', doSomething)
testEntry.grid(column=0,row=0)
thingEntry = ttk.Entry(window)
thingEntry.bind('<FocusOut>', doSomething)
thingEntry.grid(column=0,row=1)
startButton = ttk.Button(window,text='OK',command=lambda: print('click'))
startButton.grid(column=0,row=2, sticky='W')

window.mainloop()
print('Bye Bye')

重要的部分是:

def doSomething(event):
    text = event.widget.get()
    print(text)

testEntry.bind('<FocusOut>', doSomething)

使用

Entry.bind(event,function)
您可以附加事件侦听器,在本例中为
doSomething
函数。该函数获取一个参数,一个
Event
对象。反过来,您可以使用
Entry
阅读
event.widget.get()
小部件中的内容。

每次留下

Entry
时,都会打印其值。这包括当您单击按钮时。正如您从测试中看到的,按钮的事件是在
Entry
的事件之后触发的,


3
投票

我使用 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()

2
投票

我知道其他变体。

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

这是我的代码:

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

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


0
投票

我发现使用内置的 TK 验证更适合我的 Python 初学者水平。 Entry 元素的验证在 tkinter 本身中没有详细记录,您必须使用 register() 方法来设置回调,并且通过从注册的验证回调中always返回 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) 

(仅说明性代码)

此处的示例答案交互式验证 tkinter 中的 Entry 小部件内容,以及此处有关事件的一些文档https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/entry-validation.html。它的代码并不比使用跟踪少,但对于一些初学者来说可能更容易遵循和构建。


0
投票

这是我基于 @Avi ba 答案对此的看法。通过为文本变量添加 setter 和 getter 使其变得更简单。也避免使用

StrinVar

class CustomEntry(ttk.Entry):
    def __init__(self, parent, valueChangeCallback=lambda x: print(x), **kwargs):
        super().__init__(parent, **kwargs)

        # bind function callback when value of the text is changed
        self.bind("<KeyRelease>", lambda e: valueChangeCallback(self.text))


    @property
    def text(self) -> str:
        return self.get()


    @text.setter
    def text(self, value) -> None:
        self.delete(0, 'end')
        self.insert(0, value)
© www.soinside.com 2019 - 2024. All rights reserved.