将 Tkinter 组合框绑定到条目更改?

问题描述

我有一个 ttk.ComboBox,我的用户可以从选项的下拉列表中进行选择,或者手动输入一些内容。我将它绑定到 Return,这样如果我的用户在创建一个更改它会更新,但是如果我的用户单击该框并不小心输入了其他内容,则会导致错误。需要明确的是,我已经有一个绑定到新选择的事件,以及按下回车键。

我在问是否可以检查当焦点离开框时框值是否已更改,如果是,则调用函数?当我尝试 FocusOut 绑定时,每次我单击其中一个下拉列表时,它都会调用我的函数,并且不允许我从下拉列表中选择任何内容,因此无法正常工作。

selection.bind('<Return>',lambda event,entry=selection,row=row: update(
    updated_entry=entry.get(),row=row,entry=entry))
selection.bind('<<ComboBoxSelected>>',entry=entry))

编辑:这是一个示例代码。这样写的方式,如果用户从下拉列表中选择一个项目,它会更新标签。如果用户输入内容并按下 Return 键,它会更新标签。但是如果用户输入内容并点击另一个下拉菜单,它不会更新标签

import tkinter as tk
from tkinter import ttk

def update(updated_entry,row,entry):
    label = tk.Text(root,height=1,width=10)
    label.insert(tk.END,updated_entry)
    label.grid(row=row,column=2)
    return 'break'

def gui(root):
    root.geometry('300x150')
    root.config(background='sNow3')

    for row in range(2):
        options = ['test','test1','test2']
        selection = tk.ttk.ComboBox(root,value=options)
        selection.bind('<Return>',row=row: update(
            updated_entry=entry.get(),entry=entry))
        selection.bind('<<ComboBoxSelected>>',entry=entry))
        selection.grid(row=row,column=1)

        label = tk.Text(root,width=10)
        label.grid(row=row,column=2)

if __name__ == '__main__':
    root = tk.Tk()
    gui(root)
    tk.mainloop()

解决方法

ttk.Comboboxes 是 Entry 小部件的子类,这意味着您可以将 validation 添加到它们的基类中。即通过使用 validate=validatecommand= 选项 Entry 的支持。

这样做的原因是因为“验证”将允许在失去焦点时检查关联的 Combobox 的内容 - 即你的既定目标。这应该与您已有的绑定事件处理结合使用。以下代码与您的最小可重现示例类似,说明了如何处理类似的事情。

注意:这种方法还允许对用户输入的值进行一些真正的验证,以防止以后出现问题(如果它们无效)。

import tkinter as tk
from tkinter import ttk

def update(updated_entry,entry):
    ''' Combobox change Callback. '''
    entry.delete('1.0',tk.END)
    entry.insert(tk.END,updated_entry)

def gui(root):
    root.geometry('300x150')
    root.config(background='snow3')

    for row in range(2):
        text = tk.Text(root,height=1,width=10)  # Widget to be updated.
        text.grid(row=row,column=2)

        def check_okay(new_value,text=text):
            update(new_value,text)
            return True  # Note: accepts anything.

        combobox = ttk.Combobox(root,value=('test','test1','test2'),validate='focusout',validatecommand=(root.register(check_okay),'%P'))
        combobox.grid(row=row,column=1)

        combobox.bind('<Return>',lambda event,entry=combobox,text=text:
                                    update(entry.get(),entry=text))
        combobox.bind('<<ComboboxSelected>>',text=text:
                                                update(entry.get(),entry=text))

if __name__ == '__main__':
    root = tk.Tk()
    gui(root)
    tk.mainloop()