75

如何让 Tkinter 应用程序跳转到前面?目前,该窗口出现在我所有其他窗口的后面并且没有获得焦点。

有什么我应该调用的方法吗?

4

10 回答 10

106

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

root.lift()

如果您希望窗口保持在所有其他窗口之上,请使用:

root.attributes("-topmost", True)

root您的 Toplevel 或 Tk在哪里。别忘了-前面"topmost"

要使其成为临时的,请在以下之后立即禁用 topmost:

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

只需传入您要作为参数提出的窗口,这应该可以。

于 2011-07-22T19:32:46.593 回答
44

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

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

它非常适合我。它使窗口在生成窗口时出现在最前面,并且不会一直保持在最前面。

于 2016-03-24T00:56:13.870 回答
31

如果您在 Mac 上执行此操作,请使用 AppleEvents 将重点放在 Python 上。例如:

import os

os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')
于 2012-01-08T03:07:47.987 回答
6

关于 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''')
于 2014-05-09T18:06:42.653 回答
4

在 Mac OS X 上,PyObjC 提供了一种比使用 osascript 更干净且不易出错的方法:

import os
from Cocoa import NSRunningApplication, NSApplicationActivateIgnoringOtherApps

app = NSRunningApplication.runningApplicationWithProcessIdentifier_(os.getpid())
app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps)
于 2015-03-05T09:29:23.287 回答
4

最近,我在 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()
于 2015-08-20T15:05:03.827 回答
4

在某种程度上是各种其他方法的组合,这适用于 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()
于 2016-05-15T07:08:59.640 回答
2

当您在 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 系统。

于 2017-07-22T20:16:33.490 回答
2

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

在我的应用程序中,我有一个大窗口toplevel,它调用一个小得多的窗口top2,最初出现在toplevel.

如果用户在toplevel窗口内单击,它将获得焦点并扼杀小得多的top2窗口,直到toplevel窗口被拖出它为止。

解决方案是单击按钮toplevel重新启动top2top2open 函数知道它已经在运行,因此只需将其提升到顶部并为其提供焦点:

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
于 2020-08-04T01:22:26.627 回答
1

在 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 运行我的脚本时,应用程序窗口将留在后面。

我的解决方案适用于我遇到的所有情况。

于 2018-12-06T04:52:16.783 回答