Tkinter主窗口焦点
我有以下代码:
window = Tk()
window.lift()
window.attributes("-topmost", True)
这段代码可以让我的Tkinter窗口显示在所有其他窗口的上面,但这只是解决了一半的问题。虽然窗口确实显示在最上面,但它并没有获得焦点。有没有办法不仅让这个窗口在Tkinter中处于最前面,还能让它获得焦点呢?
5 个回答
对于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
注意:这只适用于Windows系统。这是让整个主窗口获得焦点,实际上就是强制你按Alt+Tab键来切换到这个窗口。
这些回答对我来说都没用,虽然我给tk
窗口加了-topmost
标志,它确实会显示在最上面,我的输入框也能获得焦点,但整个窗口却没有获得焦点,这就导致我在tk
窗口里输入的内容看不见。它的情况是这样的:
解决这个问题的方法是调用Windows的API来强制获取焦点:
import win32gui
root = tk.Tk()
# Application specific setup ...
win32gui.SetForegroundWindow(root.winfo_id())
免责声明:强制获取焦点是不好的行为,所以只有在必要时并且合情合理的情况下才使用,比如用户会立即在输入框中输入内容。
我不太清楚你遇到了什么问题。不过下面是一些示例代码,对我来说运行得很好。
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测试的。
运行程序后,结果是我可以直接开始输入,输入的内容会自动进入第一个文本框。
在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()
一些链接和示例:
如果 focus_force()
这个方法不管用,你可以试试下面的方法:
window.after(1, lambda: window.focus_force())
其实这两个方法是一样的,只是写法不同。我刚刚在 Python 2.7 上测试过。
root.focus_force()
这个方法不管用,但上面的方法可以正常工作。