如何使Tkinter窗口跳到前面?

80

如何使Tkinter应用程序跳转到前台?目前,窗口显示在我的所有其他窗口后面,并且没有焦点。

是否有一些我应该调用的方法?

12个回答

117

假设你所说的“我的其他窗口”是指你的应用程序窗口,你可以在Toplevel或Tk上使用lift()方法:

root.lift()

如果你想让窗口保持在所有其他窗口的上方,请使用:

root.attributes("-topmost", True)

请注意,在root参数中传入你的 ToplevelTk 对象。不要忘记在"topmost"之前加上-符号!

如果想要临时取消置顶,可以在操作后立即将topmost设置为False

def raise_above_all(window):
    window.attributes('-topmost', 1)
    window.attributes('-topmost', 0)

只需将您想要提升的窗口作为参数传递即可,这应该可以起作用。


4
我想表达的是:windows.attributes(1)可以将窗口置于前台,但attributes(0)似乎不能禁用此功能,它实际上会将窗口发送到后台。 - shawn
root.attributes("-topmost", True) 可以工作,但它不能将焦点带到窗口。之后请使用 _root_window.focus_force()。 - nikoo28
1
root.attributes("-topmost", True) 可以工作,但 root.lift() 不行(在 Windows 7 上)。这似乎是与操作系统有关的问题(?)。 - Josep
2
确保在 root.mainloop() 之前添加此代码! - DaveK
@shawn 虽然我也在寻找更好的方法,但我有一个不将其发送到后面的解决方法。将 windows.attributes(0) 绑定到 <focusOut> 上的窗口。由于已经过了这么多年,请分享您是否有更好的方法。 - Subham Burnwal

49

在主循环(mainloop())之前添加以下行:

root.lift()
root.attributes('-topmost',True)
root.after_idle(root.attributes,'-topmost',False)

这对我来说完美无缺。它使窗口在生成时前置,并且不会一直保持在前面。


4
我正在运行10.11系统,这是唯一有效的答案。 - user1247
这个和osascript版本(https://dev59.com/aXI-5IYBdhLWcg3wW3Gp#8775078)对我有用(10.14),但是这个看起来更好,可能运行更快,而且似乎不太可能产生意外的副作用。 - Stan Kurdziel

31

如果您正在Mac上进行操作,请使用AppleEvents将焦点放在Python上。例如:

import os

os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')

1
在Mavericks上完美运行。非常感谢。 - edsonlp1
3
在root.mainloop()之前需要发生的事情。 - Joris
5
对我来说,它需要在 root = tk.Tk() 之后,root.mainloop() 之前完成。此外,对于我的 Anaconda 安装,它必须是小写的 process "python" - user3148185
3
缺点是:它将所有的 Python Tk 进程都移动到前台,这可能不符合预期。 - Alan Zhiliang Feng
请注意,这将导致在较新版本的 macOS 上向用户请求“Finder”应用程序权限。 - hurturk

6
关于Mac电脑,我发现如果有多个Python GUI运行,则每个进程都将被命名为“Python”,而AppleScript往往会将错误的进程提升到前台。这是我的解决方案。思路是在加载Tkinter之前和之后获取正在运行的进程ID列表。(请注意,这些是似乎与其posix对应项无关的AppleScript进程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)

关闭窗口时出现错误:分段错误:11。 - thinker3
它在Tkinter应用程序中运行,不会在10.10.2上的系统Python中崩溃。尝试删除代码的其他部分,很可能是其他导致崩溃的原因。 - MagerValp

4

这种方法有点像其他几种方法的结合体,在运行OS X 10.11和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()

4

最近,我在Mac上遇到了同样的问题。我结合了多个答案,其中包括@MagerValp提供的Mac系统方案,以及@DK提供的其他系统方案:

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()

这是什么编程语言? - zavr
这种语言是Python。 - Tomasz Nguyen
在Sierra上添加和删除“-topmost”对我有用,而另一个分支不行(其中没有Cocoa模块)。我正在运行OS X默认的tk。 - Victor Sergienko

3

在Tkinter._test()函数中有一个提示,可以使Tkinter窗口在调用mainloop()时获得焦点。

# The following three commands are needed so the window pops
# up on top on Windows...
root.iconify()
root.update()
root.deiconify()
root.mainloop()

这是我找到的最干净、最合适的做法,但它仅适用于Windows系统。


2

这个答案是为了让一个Tkinter窗口在其他Tkinter窗口上方弹出。

在我的应用程序中,我有一个大窗口toplevel,它调用一个较小的窗口top2,最初出现在toplevel的上方。

如果用户在toplevel窗口内单击,它将获得焦点并覆盖较小的top2窗口,直到toplevel窗口被拖离它。

解决方案是在toplevel中单击按钮以再次启动top2top2打开函数知道它已经在运行,因此只需将其提升到顶部并使其获得焦点:

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

1

还需要一行(对于Python 3.11和tkinter 8.6):

def lift_window(window):
    window.attributes('-topmost', True)
    window.update_idletasks()  # get window on top
    window.attributes('-topmost', False)  # prevent permanent focus 
    window.focus_force()  # focus to the window

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