如何让 Tkinter 窗口跳到前面?
Posted
技术标签:
【中文标题】如何让 Tkinter 窗口跳到前面?【英文标题】:How to make a Tkinter window jump to the front? 【发布时间】:2010-12-25 22:15:37 【问题描述】:如何让 Tkinter 应用程序跳转到前面?目前,该窗口出现在我所有其他窗口的后面并且没有获得焦点。
有什么我应该调用的方法吗?
【问题讨论】:
【参考方案1】:假设您说“我的其他窗口”时指的是您的应用程序窗口,您可以在 Toplevel 或 Tk 上使用 lift()
方法:
root.lift()
如果您希望窗口保持在所有其他窗口之上,请使用:
root.attributes("-topmost", True)
root
是您的***或 Tk。不要忘记"topmost"
前面的-
!
要使其临时,请在以下之后禁用最上面:
def raise_above_all(window):
window.attributes('-topmost', 1)
window.attributes('-topmost', 0)
只需将要引发的窗口作为参数传入,这应该可以工作。
【讨论】:
我的意思是:windows.attributes(1) 确实出现在前面,但 (0) 似乎并没有禁用它。它实际上将其发送到后面。 root.attributes("-topmost", True) 工作,但它不会将焦点带到窗口使用 _root_window.focus_force() 之后 root.attributes("-topmost", True) 有效,root.lift() 无效(Windows 7)。它似乎依赖于操作系统(?) 确保在 root.mainloop() 之前添加这个! @shawn 虽然我也在寻找更好的方法,但我有一个不将其发送回的解决方法。将 windows.attributes(0) 绑定到如果您在 Mac 上执行此操作,请使用 AppleEvents 将重点放在 Python 上。例如:
import os
os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')
【讨论】:
在小牛队完美运行。非常感谢。 需要在root.mainloop()之前发生 对我来说,它需要在root = tk.Tk()
之后和root.mainloop()
之前发生。另外,对于我的 anaconda 安装,它必须是小写的 process "python"
。
缺点是:它将所有python Tk进程移动到前台,这可能不是预期的。
当心,这将导致用户请求“Finder”应用程序权限以获取更新的 macOS。【参考方案3】:
关于 Mac,我注意到可能存在一个问题,即如果运行多个 python GUI,每个进程都将被命名为“Python”,AppleScript 会倾向于将错误的进程推到前面。这是我的解决方案。这个想法是在加载 Tkinter 之前和之后获取正在运行的进程 ID 列表。 (请注意,这些是 AppleScript 进程 ID,它们似乎与 posix 对应的进程 ID 无关。去想一想。)然后奇怪的人将是你的,你把那个人移到最前面。 (我不认为最后的循环是必要的,但是如果你简单地获取 ID 为 procID 的每个进程,AppleScript 显然会返回一个由名称标识的对象,这当然是那个非唯一的“Python”,所以除非我遗漏了什么,否则我们会回到第一方。)
import Tkinter, subprocess
def applescript(script):
return subprocess.check_output(['/usr/bin/osascript', '-e', script])
def procidset():
return set(applescript(
'tell app "System Events" to return id of every process whose name is "Python"'
).replace(',','').split())
idset = procidset()
root = Tkinter.Tk()
procid = iter(procidset() - idset).next()
applescript('''
tell app "System Events"
repeat with proc in every process whose name is "Python"
if id of proc is ''' + procid + ''' then
set frontmost of proc to true
exit repeat
end if
end repeat
end tell''')
【讨论】:
【参考方案4】:在 Mac OS X 上,PyObjC 提供了一种比使用 osascript 脱壳更干净且不易出错的方法:
import os
from Cocoa import NSRunningApplication, NSApplicationActivateIgnoringOtherApps
app = NSRunningApplication.runningApplicationWithProcessIdentifier_(os.getpid())
app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps)
【讨论】:
关闭窗口时报错:Segmentation fault: 11 它在 Tkinter 应用程序中运行,在 10.10.2 上使用系统 python 没有段错误。尝试删除代码的其他部分,它可能会崩溃。【参考方案5】:最近,我在 Mac 上遇到了同样的问题。我使用@MagerValp
为Mac 和@D K
为其他系统组合了几个答案:
import platform
if platform.system() != 'Darwin':
root.lift()
root.call('wm', 'attributes', '.', '-topmost', True)
root.after_idle(root.call, 'wm', 'attributes', '.', '-topmost', False)
else:
import os
from Cocoa import NSRunningApplication, NSApplicationActivateIgnoringOtherApps
app = NSRunningApplication.runningApplicationWithProcessIdentifier_(os.getpid())
app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps)
root.mainloop()
【讨论】:
这是什么编程语言 语言是 Python 添加和删除-topmost
在 Sierra 上为我工作,与其他分支不同(其中没有 Cocoa 模块)。我正在运行 OS X 默认 tk。【参考方案6】:
在 mainloop() 之前添加以下行:
root.lift()
root.attributes('-topmost',True)
root.after_idle(root.attributes,'-topmost',False)
它非常适合我。它使窗口在生成窗口时位于最前面,并且不会一直保持在最前面。
【讨论】:
我正在运行 10.11 这是唯一对我有用的答案。 这个和 osascript 版本 (***.com/a/8775078/431296) 对我有用 (10.14),但这对我来说看起来更好,可能运行得更快,而且似乎不太可能有意外的副作用【参考方案7】:某种其他各种方法的组合,这适用于 OS X 10.11,以及在 venv 中运行的 Python 3.5.1,并且应该也适用于其他平台。它还通过进程 ID 而不是应用名称来定位应用。
from tkinter import Tk
import os
import subprocess
import platform
def raise_app(root: Tk):
root.attributes("-topmost", True)
if platform.system() == 'Darwin':
tmpl = 'tell application "System Events" to set frontmost of every process whose unix id is to true'
script = tmpl.format(os.getpid())
output = subprocess.check_call(['/usr/bin/osascript', '-e', script])
root.after(0, lambda: root.attributes("-topmost", False))
您在mainloop()
调用之前调用它,如下所示:
raise_app(root)
root.mainloop()
【讨论】:
【参考方案8】:当你在 Tkinter._test() 函数中调用 mainloop() 时,有一个关于如何使 Tkinter 窗口获得焦点的提示。
# The following three commands are needed so the window pops
# up on top on Windows...
root.iconify()
root.update()
root.deiconify()
root.mainloop()
这是我发现的最干净最合适的方法,但它仅适用于 Windows 系统。
【讨论】:
【参考方案9】:在 macOS High Sierra 上,py3.6.4,这是我的解决方案:
def OnFocusIn(event):
if type(event.widget).__name__ == 'Tk':
event.widget.attributes('-topmost', False)
# Create and configure your root ...
root.attributes('-topmost', True)
root.focus_force()
root.bind('<FocusIn>', OnFocusIn)
这个想法是把它放在前面,直到用户与之交互,即获得焦点。
我尝试了接受的答案 .after_idle()
和 .after()
。在一种情况下它们都失败了:当我直接从像 PyCharm 这样的 IDE 运行我的脚本时,应用程序窗口将留在后面。
我的解决方案适用于我遇到的所有情况。
【讨论】:
【参考方案10】:这个答案是让一个 Tkinter 窗口在其他 Tkinter 窗口之上弹出。
在我的应用程序中,我有一个大窗口 toplevel
,它调用一个小得多的窗口 top2
,它最初出现在 toplevel
的顶部。
如果用户在toplevel
窗口内单击,它会获得焦点并窒息更小的top2
窗口,直到toplevel
窗口被拖出。
解决方法是点击toplevel
中的按钮再次启动top2
。 top2
open 函数知道它已经在运行,因此只需将其提升到顶部并使其获得焦点:
def play_items(self):
''' Play 1 or more songs in listbox.selection(). Define buttons:
Close, Pause, Prev, Next, Commercial and Intermission
'''
if self.top2_is_active is True:
self.top2.focus_force() # Get focus
self.top2.lift() # Raise in stacking order
root.update()
return # Don't want to start playing again
【讨论】:
以上是关于如何让 Tkinter 窗口跳到前面?的主要内容,如果未能解决你的问题,请参考以下文章