Tkinter OptionMenu无法使用空格键第二次打开。

5

我在使用Tkinter时遇到了一些问题,我只能假设这是一个bug。

from tkinter import *

def refocus(event, obj):
    obj.focus()

root = Tk()
options = ["Hello", "world", "How", "are", "you"]
v1 = StringVar()
v2 = StringVar()
v3 = StringVar()

o1 = OptionMenu(root, v1, *options)
o1.configure(takefocus=1)
o2 = OptionMenu(root, v2, *options)
o2.configure(takefocus=1)
o3 = OptionMenu(root, v3, *options)
o3.configure(takefocus=1)

o1.bind("<Configure>", lambda e=Event(), o=o1: refocus(e, o))
o2.bind("<Configure>", lambda e=Event(), o=o2: refocus(e, o))
o3.bind("<Configure>", lambda e=Event(), o=o3: refocus(e, o))

o1.pack(side=TOP)
o2.pack(side=TOP)
o3.pack(side=TOP)

root.mainloop()



从代码中可以看出,我正在尝试使用键盘上的 tab、空格、箭头和 Enter 键来导航三个 OptionMenu 菜单。问题在于,一旦菜单框弹出,它似乎就失去了原始 OptionMenu 的焦点。为了解决这个问题,我绑定了configure,重新聚焦选项框,但这只适用于输入已更改的情况,因此我需要一种新的方法来解决这个问题。还有一个问题是,如果我选择了错误的选项,则必须循环遍历所有其他输入(OptionMenus、Entrys、Checkboxes等)才能回到那个选项以再次打开它。在只有一个 OptionMenu 的情况下,它将无法工作,直到我使用鼠标点击另一个输入。我正在寻找一种方法,在菜单部分失去焦点后,我可以重新聚焦在 OptionMenu 上。我还尝试使用 o1['menu'].bind(...),但这根本没有起作用。例程流程如下:o1 获得焦点 -> 按下空格 -> 打开菜单 -> 使用箭头移动 -> 按 Enter 选择 -> 聚焦于 o1 -> 按空格 -> 打开菜单 -> 使用箭头移动 -> 按 Enter 选择 -> 聚焦于 o1 -> 按 Tab -> o2 获得焦点。

1
你是否考虑过使用 ttk.Combobox 而不是 OptionMenu - Bryan Oakley
@BryanOakley 不,我希望在转向ttk小部件之前尽可能重复使用Tk小部件。 - Scott Paterson
我可以问一下你为什么避免使用ttk小部件吗? - JRiggles
我找不到解决方法,但我注意到你可以将 o1.bind("<Configure>", lambda e=Event(), o=o1: refocus(e, o) 重构为 o1.bind("<Configure>", refocus),并且 def refocus(event): event.widget.focus()(值得思考)。 - JRiggles
@JRiggles,Tk小部件不需要Style(),但ttk小部件需要。我计划添加具有主题/样式管理器的ttk小部件,但我还没有达到那个阶段。由于我的当前代码依赖于tk.pallet(),因此我需要将其转换为ttk样式,目前来说这是一项很费力的工作。 - Scott Paterson
焦点始终设置为o3,甚至不是o1或o2。 - toyota Supra
1个回答

3

看这个:

import tkinter as tk


def open_option_menu(event):
    # Get the widget from the event that tkinter passed in
    obj = event.widget
    # Calculate the x/y position of the popup window
    x = obj.winfo_rootx()
    y = obj.winfo_rooty() + obj.winfo_height()
    # Show the popup window
    #   obj["menu"] returns a `tk.Menu` object which has a `.post` method
    obj["menu"].post(x, y)
    # Stop tkinter from showing the popup window again.
    return "break"


root = tk.Tk()
options = ["Hello", "world", "How", "are", "you"]

v1 = tk.StringVar(root)
v2 = tk.StringVar(root)
v3 = tk.StringVar(root)

o1 = tk.OptionMenu(root, v1, *options)
o2 = tk.OptionMenu(root, v2, *options)
o3 = tk.OptionMenu(root, v3, *options)

o1.configure(takefocus=True)
o2.configure(takefocus=True)
o3.configure(takefocus=True)

o1.bind("<space>", open_option_menu)
o2.bind("<space>", open_option_menu)
o3.bind("<space>", open_option_menu)

o1.pack()
o2.pack()
o3.pack()

root.mainloop()

我认为这是tkinter中的一个bug,因此我创建了一个名为open_option_menu的函数来显示弹出窗口。如果你不喜欢tkinter的某些方面,你可以自己重建它,加入你需要的功能。如果你想了解更多关于.post方法的信息,在python中输入help(tkinter.Menu.post)

请注意,这个问题只存在于Windows系统中,所以这个解决方案只适用于Windows。在Ubuntu上,当弹出菜单被显示时,它没有获得焦点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接