【问题标题】:How to make a Tkinter window jump to the front?如何让 Tkinter 窗口跳到前面?
【发布时间】:2010-12-25 22:15:37
【问题描述】:

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

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

【问题讨论】:

    标签: python tkinter focus


    【解决方案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 版本 (stackoverflow.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
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-04-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-08-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多