显示哪个小部件具有焦点

Display which widget has focus

阅读之前: 我在编程方面完全是个新手,更不用说 Python。我不期待解决方案。即使我只是在正确的方向上得到指示,我也会很感激。如果您觉得我请求帮助的方式不够完善,请告诉我,以便下次我需要帮助时,我会做得更好。

目标: 我正在制作一个程序来测试如何让程序根据必须关注的小部件进行响应。目前,我只是让它通过显示 'what' 具有焦点来响应。 最终,一旦我弄明白了这一点,我就可以将我学到的知识应用到我正在研究的另一个程序中,该程序专注于输入字段,这将导致清除所有输入的字段。所以很自然地,我希望这个程序不仅可以更改标签,还可以更改条目小部件。那以后再说。

进度: 我已经设法让程序打印出哪个小部件在终端和标签小部件中都有焦点。

问题: 我的问题是消息很难看,我希望它看起来更整洁。

问题示例: 它不是说“条目有焦点”,而是说“.!frame.!entry {有焦点}”

我试过: 检查其他人是否制作了类似的程序。我发现的唯一一个是我如何取得如此大的进步,但它并没有使文本更好。我还在各种网站上研究了 Python 如何处理我在该程序中使用的某些命令。 我是编程新手,所以我承认我不完全确定 运行 这个程序的最佳方法是什么,因此尝试研究它对我来说很困难。

代码:

# Call tkinter tools
from tkinter import *
from tkinter import ttk

"""
TODO:
Add different widgets that can 'gain' focus.
Print in the terminal which widget has focus.
Change entry and label text depending on which widget has focus.
"""

# Develop the window and frame
root = Tk()
root.title("Focus Test")
root.columnconfigure(0, weight = 1)
root.rowconfigure(0, weight = 1)

frame = ttk.Frame(root, padding = "1 1 1 1")
frame.grid(column = 0, row = 0, sticky = (N, S, E, W))

# Resizes columns in frame
for col in range(1, 3):
    frame.columnconfigure(col, weight = 1)

# Resizes rows in frame
for row in range(1, 3):
    frame.rowconfigure(row, weight = 1)

# Add response label
foc_labvar = StringVar()
foc_labvar.set("No focus")
foc_lab = ttk.Label(frame, width = 7, textvariable = foc_labvar)
foc_lab.grid(column = 2, row = 2, sticky = (W, E))

# Add entry box
foc_entvar = StringVar()
foc_entvar.set("Entry widget")
foc_ent = ttk.Entry(frame, width = 7, textvariable = foc_entvar)
foc_ent.grid(column = 1, row = 1, sticky = (W, E))

# Add button
foc_butvar = StringVar()
foc_butvar.set("Button widget")
foc_but = ttk.Button(frame, width = 7, textvariable = foc_butvar)
foc_but.grid(column = 2, row = 1, sticky = (W, E))

# Focus commands
def focus(event):
    focused_widget = frame.focus_get()
    foc_labvar.set((focused_widget, "has focus"))
    print(focused_widget, "has focus")

# Bind mouse click to run focus command
root.bind("<Button-1>", focus)

# Resize widgets inside frame
for child in frame.winfo_children():
    child.grid_configure(padx = 5, pady = 5)


root.mainloop()

您可以像这样使用 if 语句:

def focus(event):
    focused_widget = frame.focus_get() # You can also use `event.widget` like what @CoolCloud did.
    if focused_widget == foc_ent:
        foc_labvar.set("Entry has focus")
    if focused_widget == foc_but:
        foc_labvar.set("Button has focus")

您可以轻松地做到这一点 event 处理小部件识别部分,例如:

def focus(event):
    focused_widget = event.widget.winfo_class()
    foc_labvar.set((focused_widget, "has focus")) # Or f'{focused_widget} has focus'
    print(focused_widget, "has focus")

此处 event 将为小部件提供 widget 方法,然后您可以在其上使用任何小部件方法,例如 focus()insert()(如果它是一个条目小部件)等等。这里 winfo_class 应该可以工作,因为它是一种通用方法并且适用于所有小部件。

有关 winfo_class 的更多信息,它将提供小部件的 class,例如按钮的 TButton,因为这就是 tk 引用它们的方式。如果你仍然坚定地想摆脱 T 那么就去 event.widget.winfo_class()[1:] 到 trim 关闭 'T'。

您可以为小部件指定一个您选择的名称。然后,您可以使用 winfo_name 获取小部件的名称。关于名称的唯一要求是名称中不能包含句点。

此外,您应该绑定到 <FocusIn><FocusOut>,这样即使通过键盘更改焦点,您的代码也能正常工作。

foc_ent = ttk.Entry(..., name="foc entry")
foc_but = ttk.Button(..., name="foc button")
...
def focus(event):
    focused_widget = frame.focus_get()
    if focused_widget:
        foc_labvar.set(f"{focused_widget.winfo_name()} as focus")
    else:
        foc_labvar.set("nothing has focus")

root.bind("<FocusIn>", focus)
root.bind("<FocusOut>", focus)

结合提供的建议。这是我最终得到的结果,它按照我脑海中想象的方式工作,再加上大家的帮助:

# Focus commands
def focus(event):
    focused_widget = event.widget.winfo_class()[1:]
    foc_labvar.set(focused_widget + " has focus")
    foc_entvar.set(focused_widget + " has focus")
    print(focused_widget, "has focus")

# Bind mouse and keyboard to run focus command
root.bind("<Button-1>", focus)
root.bind("<FocusIn>", focus)
root.bind("<FocusOut>", focus)