簡體   English   中英

如何讓 Tkinter 窗口跳到前面?

[英]How to make a Tkinter window jump to the front?

如何讓 Tkinter 應用程序跳轉到前面? 目前,該窗口出現在我所有其他窗口的后面並且沒有獲得焦點。

有什么方法我應該調用嗎?

假設您說“我的其他窗口”時指的是您的應用程序窗口,則可以在 Toplevel 或 Tk 上使用lift()方法:

root.lift()

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

root.attributes("-topmost", True)

其中root是您的 Toplevel 或 Tk。 不要忘記-"topmost" topmost "topmost"

要使其成為臨時的,請在以下之后立即禁用最上面:

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

只需傳入您想要作為參數提出的窗口,這應該有效。

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

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

它非常適合我。 它使窗口在生成窗口時出現在最前面,並且不會一直保持在前面。

如果您在 Mac 上執行此操作,請使用 AppleEvents 將焦點放在 Python 上。 例如:

import os

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

關於 Mac,我注意到可能存在一個問題,如果有多個 Python GUI 正在運行,每個進程都會被命名為“Python”,而 AppleScript 會傾向於將錯誤的一個提升到前面。 這是我的解決方案。 這個想法是在加載 Tkinter 之前和之后獲取正在運行的進程 ID 列表。 (請注意,這些是 AppleScript 進程 ID,它們似乎與它們的 posix 對應項無關。去算一下。)然后奇怪的人將是你的,你將那個人移到最前面。 (我不認為最后的循環是必要的,但是如果您只是獲取 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''')

在 Mac OS X 上,PyObjC 提供了一種比使用 osascript 更簡潔、更不容易出錯的方法:

import os
from Cocoa import NSRunningApplication, NSApplicationActivateIgnoringOtherApps

app = NSRunningApplication.runningApplicationWithProcessIdentifier_(os.getpid())
app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps)

最近,我在 Mac 上遇到了同樣的問題。 我使用@MagerValp for Mac 和@DK for其他系統組合了幾個答案:

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

某種程度上是各種其他方法的組合,這適用於 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()

當您在 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 系統需要它。

這個答案是讓一個 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

在 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_idle() .after() 它們都在一種情況下失敗:當我直接從 PyCharm 等 IDE 運行我的腳本時,應用程序窗口將留在后面。

我的解決方案適用於我遇到的所有情況。

如果您希望將目標窗口抬起的窗口已知,您可以簡單地使用tkraise方法,並將aboveThis參數設置為您想要繪制的窗口。

from tkinter import Tk, ttk, Toplevel

class App(Tk):

    def __init__(self):
        Tk.__init__(self)
        self.title('Main Window')
        self.state('zoomed')
        self.l1 = ttk.Label(self, text='Hello World!')
        self.l1.pack()

        self.s = Splash()
        self.s.tkraise(aboveThis=self)

class Splash(Toplevel):
    def __init__(self):
        Toplevel.__init__(self)
        self.title('Splash Screen')
        self.lift()


app = App()
app.mainloop()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM