Tkinter,Windows:如何在没有标题栏的 Windows 任务栏中查看窗口?
Posted
技术标签:
【中文标题】Tkinter,Windows:如何在没有标题栏的 Windows 任务栏中查看窗口?【英文标题】:Tkinter, Windows: How to view window in windows task bar which has no title bar? 【发布时间】:2015-08-27 11:25:27 【问题描述】:我创建了一个窗口:
root = Tk()
并删除了标题栏:
root.overrideredirect(True)
现在窗口不在窗口的任务栏上。如何在任务栏中显示它? (如果我的上面有其他窗户,我只想把我的窗户放在前面)
【问题讨论】:
我不知道确切原因,但我猜overrideredirect
设置为 true 会消除管理窗口的所有可能性,例如调整大小或类似的事情...查看@ 987654321@ 和其他地方,我希望有人想出一个详尽的答案......
可以这样做,但需要调用 Win32 API 函数,因为这不是 Tk 提供的。您应该解释为什么要这样做,因为您可能正在寻找错误问题的解决方案。
不使用任何 Win32 API 函数的相关答案:***.com/a/6662135/10742758
【参考方案1】:
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.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()
【讨论】:
我看到GetWindowLongPtrW
和SetWindowLongPtrW
方法只适用于win64bit,而在win32bit 中你必须使用其他方法,这里有一种方法可以同时用于32 位和64 位?
为什么没有 root.after(10, lambda: set_appwindow(root))
就不行?像set_appwindow(root)
这样的简单调用不起作用。
@CoolCloud 窗口需要在屏幕上映射。这个延迟是足够的,但它可能应该使用<Map>
事件。例如:bind $root <Map> [list set_appwindow $root]
。但是在 set_appwindow 函数中,您需要删除 Map 绑定以避免每次在屏幕上映射窗口时都会调用它。
基本上直到某些事件处理发生(通过运行主循环)你的窗口还没有正确存在。一旦它被映射,它就被完全创建和初始化,我们可以设置额外的窗口管理器属性。
哦,我明白了,所以root.update()
也可以这样做?【参考方案2】:
@patthoyts 回答的简化:
# Partially taken from: https://***.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)
只是删除了窗口的标题栏。更多信息请阅读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 应该可以工作。
【讨论】:
以上是关于Tkinter,Windows:如何在没有标题栏的 Windows 任务栏中查看窗口?的主要内容,如果未能解决你的问题,请参考以下文章
如何创建一个有边框但没有标题栏的表单? (如 Windows 7 上的音量控制)
如何使用 python Tkinter 隐藏 Windows 控制台?