如何让 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) 绑定到 上的窗口。这么多年了,有什么更好的欢迎分享【参考方案2】:

如果您在 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中的按钮再次启动top2top2 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 窗口跳到前面?的主要内容,如果未能解决你的问题,请参考以下文章

如何让 tkinter 消息框出现在顶层前面

pythy标准库之Tkinter(hello world窗口显示)

python怎么用tkinter

在单独的线程中运行 Tkinter 表单

Python中tkinter控件中的Listbox控件详解

python - 如何在Python的Tkinter模块中使对话框窗口出现在最前面?