Tkinter,Windows:如何查看没有标题栏的Windows任务栏中的窗口?

时间:2015-06-11 16:26:19

标签: python windows tkinter python-3.4

我创建了一个窗口:

root = Tk()

并删除了标题栏:

root.overrideredirect(True)

现在窗口不在Windows的任务栏上。如何在任务栏中显示它? (如果其他窗户在我的上面,我只想把窗户拉到前面)

2 个答案:

答案 0 :(得分:6)

Tk没有提供一种方法来设置一个顶层窗口,其中 overrideredirect 设置为显示在任务栏上。要执行此操作,窗口需要应用WS_EX_APPWINDOW扩展样式,并且此类型的Tk窗口设置为WS_EX_TOOLWINDOW。我们可以使用python ctypes扩展来重置它,但是我们需要注意Windows上的Tk顶层窗口不是由窗口管理器直接管理的。因此,我们必须将此新样式应用于winfo_id方法返回的窗口的父级。

以下示例显示了这样一个窗口。

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.wm_withdraw()
    root.after(10, lambda: root.wm_deiconify())

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

if __name__ == '__main__':
    main()

答案 1 :(得分:0)

这是@patthoyts 在同样实现的类中的回答:.toggle_fullscreen.iconify

import tkinter as tk

import ctypes
from ctypes.wintypes import BOOL, HWND, LONG

INT = ctypes.c_int
UINT = ctypes.c_uint
LONG_PTR = ctypes.c_uint

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

GetParent = ctypes.windll.user32.GetParent
GetParent.argtypes = (HWND, )
GetParent.restype = HWND
GetParent.errcheck = _errcheck_not_zero

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

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


class NoTitlebarTk(tk.Tk):
    def __init__(self):
        super().__init__()
        self.locked = False
        self._fullscreen = False
        self.map_binding = super().bind("<Map>", self._overrideredirect)

    def _overrideredirect(self, event:tk.Event=None) -> None:
        if self.locked:
            return None
        self.locked = True
        if self.map_binding is not None:
            super().unbind("<Map>", self.map_binding)
            self.map_binding = None
        super().overrideredirect(True)
        super().update_idletasks()
        self.hwnd = GetParent(super().winfo_id())
        style = GetWindowLongPtrW(self.hwnd, GWL_EXSTYLE)
        style = (style & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW
        res = SetWindowLongPtrW(self.hwnd, GWL_EXSTYLE, style)

        # re-assert the new window style
        super().withdraw()
        super().after(10, self.deiconify)
        super().after(20, self.focus_force)
        self.locked = False

    def overrideredirect(self, boolean:bool=None) -> None:
        raise RuntimeError("This window must stay as `overrideredirect`")
    wm_overrideredirect = overrideredirect

    def attributes(self, *args) -> None:
        if (len(args) == 2) and (args[0] == "-fullscreen"):
            value = args[1]
            if isinstance(value, str):
                value = value.lower() in ("1", "true")
            if bool(value):
                return self.fullscreen()
            return self.notfullscreen()
        return super().attributes(*args)
    wm_attributes = attributes

    def iconify(self) -> None:
        super().overrideredirect(False)
        super().iconify()
        super().update()
        self.map_binding = super().bind("<Map>", self._overrideredirect)

    def fullscreen(self) -> None:
        if self._fullscreen:
            return None
        self._fullscreen = True
        super().overrideredirect(False)
        super().attributes("-fullscreen", True)

    def notfullscreen(self) -> None:
        if not self._fullscreen:
            return None
        self._fullscreen = False
        super().attributes("-fullscreen", False)
        self._overrideredirect()
        self.map_binding = super().bind("<Map>", self._overrideredirect)

    def toggle_fullscreen(self) -> None:
        if self._fullscreen:
            self.notfullscreen()
        else:
            self.fullscreen()


if __name__ == "__main__":
    root = NoTitlebarTk()
    root.title("AppWindow Test")
    root.geometry("400x400")

    button = tk.Button(root, text="Exit", command=root.destroy)
    button.pack()

    button = tk.Button(root, text="Minimise", command=root.iconify)
    button.pack()

    button = tk.Button(root, text="Fullscreen", command=root.toggle_fullscreen)
    button.pack()

    root.mainloop()