正如问题所说。
Text
小部件具有 <<Modified>>
事件,但 Entry
小部件似乎没有。
将 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()
在撰写本文时(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
(我添加了第二个条目小部件,因此第一个条目实际上可以失去焦点!)
谢谢史蒂文! 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()
您还可以使用 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()
希望有帮助。
我已经能够使用
<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
的事件之后触发的,
我使用 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()
我知道其他变体。
在输入代码之前,它可以更好地解释编码路径:阅读这里
这是我的代码:
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 种变体:通过按按钮并输入进入。 现在您可以选择任何变体
我发现使用内置的 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。它的代码并不比使用跟踪少,但对于一些初学者来说可能更容易遵循和构建。
这是我基于 @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)