Tkinter主窗口焦点

23 投票
5 回答
42050 浏览
提问于 2025-04-18 00:36

我有以下代码:

window = Tk()
window.lift()
window.attributes("-topmost", True)

这段代码可以让我的Tkinter窗口显示在所有其他窗口的上面,但这只是解决了一半的问题。虽然窗口确实显示在最上面,但它并没有获得焦点。有没有办法不仅让这个窗口在Tkinter中处于最前面,还能让它获得焦点呢?

5 个回答

0

对于Linux(Ubuntu 16.04.6 LTS),我尝试了很多建议,包括使用 .grab,但这导致了一些问题。最后我使用了:

if self.top2_is_active is True: # Are we already playing songs?
    self.top2.focus_force()     # Get focus
    self.top2.lift()            # Raise in stacking order
    root.update()
    return                      # Don't want to start playing again

这其实并不是在“抢夺”焦点,因为我在主窗口上定义了一个按钮,内容是:

''' ▶  Play Button '''
self.play_text="▶  Play"                # play songs window is opened.
self.listbox_btn2 = tk.Button(frame3, text=self.play_text, \
                    width=BTN_WID, command=self.play_items)
self.listbox_btn2.grid(row=0, column=1, padx=2)

点击这个按钮后,文本会变成:

self.listbox_btn2 ["text"] = "  Show playing"     # Play button
5

注意:这只适用于Windows系统。这是让整个主窗口获得焦点,实际上就是强制你按Alt+Tab键来切换到这个窗口。


这些回答对我来说都没用,虽然我给tk窗口加了-topmost标志,它确实会显示在最上面,我的输入框也能获得焦点,但整个窗口却没有获得焦点,这就导致我在tk窗口里输入的内容看不见。它的情况是这样的:

这里输入图片描述

解决这个问题的方法是调用Windows的API来强制获取焦点:

import win32gui    
root = tk.Tk()

# Application specific setup ...

win32gui.SetForegroundWindow(root.winfo_id())

免责声明:强制获取焦点是不好的行为,所以只有在必要时并且合情合理的情况下才使用,比如用户会立即在输入框中输入内容。

5

我不太清楚你遇到了什么问题。不过下面是一些示例代码,对我来说运行得很好。

from tkinter import *

window = Tk()

def handle_focus(event):
    if event.widget == window:
        window.focus_set()
        input1.focus_set()


label1 = Label(window,text = "Enter Text 2")
input1 = Entry(window, bd=5)

label2 = Label(window,text = "Enter Text 2")
input2 = Entry(window, bd=5)

submit = Button(window, text="Submit")

label1.pack()
input1.pack()
label2.pack()
input2.pack()
submit.pack(side=BOTTOM)

window.lift()
window.attributes("-topmost", True)

window.bind("<FocusIn>", handle_focus)

hwnd = window.winfo_id()

window.mainloop()

这是在Windows 10上使用最新的Python 3.6测试的。

测试结果

运行程序后,结果是我可以直接开始输入,输入的内容会自动进入第一个文本框。

14

在Windows系统上解决这个问题有点复杂——你不能直接抢走其他窗口的焦点,而是要想办法把你的应用程序放到最前面。不过,首先我建议你了解一些关于Windows的基本知识,这样我们才能确认这是我们想要实现的目标。

正如我在之前的评论中提到的,这其实是一个很好的机会来使用SetForegroundWindow这个函数(记得查看一下限制哦!)。不过要注意,这种方法有点像小把戏,因为用户是“拥有”前景窗口的,Windows会尽量阻止你这样做:

当用户正在使用其他窗口时,应用程序不能强制将一个窗口放到最前面。相反,Windows会闪烁该窗口的任务栏按钮来提醒用户。

另外,看看这个页面上的备注:

如果用户按下ALT键或采取某些操作导致系统本身更改前景窗口(例如,点击一个后台窗口),系统会自动允许调用SetForegroundWindow。

这里有一个最简单的解决方案,因为我们可以模拟按下Alt键:

import tkinter as tk
import ctypes

#   store some stuff for win api interaction
set_to_foreground = ctypes.windll.user32.SetForegroundWindow
keybd_event = ctypes.windll.user32.keybd_event

alt_key = 0x12
extended_key = 0x0001
key_up = 0x0002


def steal_focus():
    keybd_event(alt_key, 0, extended_key | 0, 0)
    set_to_foreground(window.winfo_id())
    keybd_event(alt_key, 0, extended_key | key_up, 0)

    entry.focus_set()


window = tk.Tk()

entry = tk.Entry(window)
entry.pack()

#   after 2 seconds focus will be stolen
window.after(2000, steal_focus)

window.mainloop()

一些链接和示例:

19

如果 focus_force() 这个方法不管用,你可以试试下面的方法:

window.after(1, lambda: window.focus_force())

其实这两个方法是一样的,只是写法不同。我刚刚在 Python 2.7 上测试过。

root.focus_force() 这个方法不管用,但上面的方法可以正常工作。

撰写回答