tkinter失败.focus_set()

时间:2014-11-30 13:25:38

标签: python python-3.x tkinter tk

下面的代码是一个函数的一部分,它生成一个带有调用者选择的文本和按钮的简单对话框。

Dialog with example text and four buttons: Save, save As, Don't save, Cancel

问题在于处理'' a'' d'和&#c; c的关键输入。代码可以正确操作鼠标单击和标签,后跟空格或输入键。该代码是用Python 3.4编写的,目前正在测试是否符合Windows 7的要求。

我的理解是Tk为最终用户的鼠标点击处理重新聚焦。在用户通过Tab键更改焦点后使用空格和输入键。对于所有这些交互,密钥通过代码绑定到每个按钮:

for action in ('<1>', '<space>', '<Return>'): b.bind(action, handler)

对于&#39;强调&#39;键输入我相信我的代码需要在调用处理程序之前处理重新聚焦。这是重新聚焦例程的目的。打印声明(&#34;重新聚焦到......&#34;)打印时,button.winfo_name()的值正确,只要&#39;&#39; a&#39;&#39;,& #39; s&#39;或&#39; c&#39;被压了。这就是为什么我认为button.focus_set()失败了。

如果有效,这将使处理程序只需通过查看event.widget.winfo_name()来检查按下了哪个按钮。实际上,重新聚焦失败意味着使用event.widget.winfo_name()

中的错误按钮调用处理程序

如果我通过标签手动移动焦点,则焦点会显示event.widget.winfo_name()返回的名称,而不管其中的哪个&#39;&#39; a&#39;&#39; d& #39;或者&#39; c&#39;被压了。

在阅读Stack Overflow上的其他帖子后,我尝试在button.focus_force()之后添加button.focus_set()。这对问题没有影响。

我尝试通过将处理程序的签名更改为def button_handler(event, *args)然后将refocus的最后一行更改为handler(event,button.winfo_name())来传递按钮名称,但是{{1调用时为空。

*args

3 个答案:

答案 0 :(得分:2)

您最初关于需要将焦点设置在按钮上的假设是不正确的。在Tk中处理此问题的常用方法是在对话框顶层窗体上绑定加速键事件,并调用事件绑定的按钮调用方法。

在Tcl / Tk中:

toplevel .dlg
pack [button .dlg.b -text "Save" -underline 0 -command {puts "Save pressed"}]
bind .dlg <Alt-s> {.dlg.b invoke}

所以将关键事件绑定到任何顶层是你的按钮的父级。如果那是一个对话框,那么它的父对象应该是应用程序toplevel小部件。

等效的python是:

from tkinter import *
main = Tk()
dialog = Toplevel(main)
button = Button(dialog, text="Send", underline="0", command=lambda: print("hello"))
button.pack()
dialog.bind('<Alt-s>', lambda event: button.invoke())
main.mainloop()

键绑定将一个事件对象追加到回调函数中,我们可以使用lambda将该函数包装为按钮的调用方法。

答案 1 :(得分:0)

focus_set()当然是完美的。我期望重新聚焦会重写事件对象是错误的。以下代码(经过广泛修订以纳入Brian Oakley的建议)产生了预期的结果。:

def _make_buttons(dialog, buttons, buttonbox, default, handler):
    def bcommand_wrapper(button):
        def bcommand():
            name = button.winfo_name()
            dialog.destroy()
            handler(name)
        return bcommand

    for button_text, underline, button_name in buttons:
        b = ttk.Button(buttonbox, text=button_text, underline=underline,
                       name=button_name)
        b.configure(command=bcommand_wrapper(b))
        b.pack(padx=2, side='left')
        action = button_text[underline:underline + 1].lower()
        try:
            dialog.bind(action, lambda event, b=b: b.invoke())
        except tk.TclError:
            raise ValueError(
                "Invalid underline of '{}' in position {}. Character '{}'.".
                format(button_text, underline, action))
        b.bind('<Return>', lambda event, b=b: b.invoke())
        if not default or default == button_name:
            default = button_name
            b.focus_set()

我放弃了将Tk事件返回给调用者的原始想法。这是一个对话框,因此调用者不需要比单击按钮的名称更多的内容。

请注意,我没有使用&#39; Alt&#39;来捕获加速键。修改。 &#39; Alt&#39;至少在MS Windows上,键与加速键一起使用时是一个功能键:它会在菜单上显示下划线。这里的下划线是静态的,所以使用&#39; Alt&#39;关键是不合适的。

答案 2 :(得分:-1)

我建议您使用root.bind(&#39; c&#39;,)让快捷键执行您想要的操作?

确保只在窗口弹出时绑定它们,并在完成后解除绑定。