Tkinter,Windows:如何在没有标题栏的windows任务栏中查看window?

Tkinter, Windows: How to view window in windows task bar which has no title bar?

我创建了一个 window:

root = Tk()

并删除了标题栏:

root.overrideredirect(True)

现在 window 不在 windows 的任务栏上。我怎样才能在任务栏中显示它? (如果其他 windows 在我的上面,我只想把我的 window 放在前面)

Tk 不提供一种方法来使顶层 window 具有 overrideredirect 设置为出现在任务栏上。为此,window 需要应用 WS_EX_APPWINDOW 扩展样式,而这种类型的 Tk window 设置了 WS_EX_TOOLWINDOW。我们可以使用 python ctypes 扩展来重置它,但我们需要注意 Windows 上的 Tk 顶层 windows 不直接由 window 管理器管理。因此,我们必须将这种新样式应用于 winfo_id 方法返回的 windows 的父级。

下面的例子展示了这样一个window。

import tkinter as tk
import tkinter.ttk as ttk
from ctypes import windll

GWL_EXSTYLE = -20
WS_EX_APPWINDOW = 0x00040000
WS_EX_TOOLWINDOW = 0x00000080

def set_appwindow(root):
    hwnd = windll.user32.GetParent(root.winfo_id())
    style = windll.user32.GetWindowLongPtrW(hwnd, GWL_EXSTYLE)
    style = style & ~WS_EX_TOOLWINDOW
    style = style | WS_EX_APPWINDOW
    res = windll.user32.SetWindowLongPtrW(hwnd, GWL_EXSTYLE, style)
    # re-assert the new window style
    root.withdraw()
    root.after(10, root.deiconify)

def main():
    root = tk.Tk()
    root.wm_title("AppWindow Test")
    button = ttk.Button(root, text='Exit', command=root.destroy)
    button.place(x=10, y=10)
    root.overrideredirect(True)
    root.after(10, set_appwindow, root)
    root.mainloop()

if __name__ == '__main__':
    main()

@patthoyts 回答的简化:

# Partially taken from: https://whosebug.com/a/2400467/11106801
from ctypes.wintypes import BOOL, HWND, LONG
import tkinter as tk
import ctypes

# Defining functions
GetWindowLongPtrW = ctypes.windll.user32.GetWindowLongPtrW
SetWindowLongPtrW = ctypes.windll.user32.SetWindowLongPtrW

def get_handle(root) -> int:
    root.update_idletasks()
    # This gets the window's parent same as `ctypes.windll.user32.GetParent`
    return GetWindowLongPtrW(root.winfo_id(), GWLP_HWNDPARENT)

# Constants
GWL_STYLE = -16
GWLP_HWNDPARENT = -8
WS_CAPTION = 0x00C00000
WS_THICKFRAME = 0x00040000


if __name__ == "__main__":
    root = tk.Tk()

    hwnd:int = get_handle(root)
    style:int = GetWindowLongPtrW(hwnd, GWL_STYLE)
    style &= ~(WS_CAPTION | WS_THICKFRAME)
    SetWindowLongPtrW(hwnd, GWL_STYLE, style)

style &= ~(WS_CAPTION | WS_THICKFRAME)只是删除了window的标题栏。有关详细信息,请阅读 Microsoft's documentation


不是真的需要,但为了更安全使用它来定义函数:

# Defining types
INT = ctypes.c_int
LONG_PTR = ctypes.c_long

def _errcheck_not_zero(value, func, args):
    if value == 0:
        raise ctypes.WinError()
    return args

# Defining functions
GetWindowLongPtrW = ctypes.windll.user32.GetWindowLongPtrW
GetWindowLongPtrW.argtypes = (HWND, INT)
GetWindowLongPtrW.restype = LONG_PTR
GetWindowLongPtrW.errcheck = _errcheck_not_zero

SetWindowLongPtrW = ctypes.windll.user32.SetWindowLongPtrW
SetWindowLongPtrW.argtypes = (HWND, INT, LONG_PTR)
SetWindowLongPtrW.restype = LONG_PTR
SetWindowLongPtrW.errcheck = _errcheck_not_zero

我知道这个问题具体说是关于 Windows 但对于 Linux,this 应该有效。