设置启用overrideredirect的tkinter窗口激活时显示任务栏图标
问题解决方法
问题原因
你设置overrideredirect(1)后,窗口会被系统识别为无系统标题栏的工具类窗口,默认不会在任务栏生成对应图标,你当前只有最小化时临时切回overrideredirect(0)才会触发任务栏图标显示。
解决方案(Windows平台通用,适配你现有代码逻辑)
我们可以通过ctypes调用Windows系统API,修改窗口的扩展样式,强制让无标题栏窗口在任务栏显示图标,不需要改动你现有的最小化、拖拽、缩放逻辑。
具体修改步骤:
- 导入ctypes相关模块,获取主窗口的HWND句柄
- 在窗口初始化完成后调用API修改窗口扩展属性
- 调整恢复窗口的逻辑,避免恢复时覆盖修改的样式
修改后的完整代码:
from tkinter import Tk, Frame, TOP, X from tkinter.constants import DISABLED, LEFT, RIGHT from tkinter.ttk import Button, Label import pyautogui as pg import time import ctypes from ctypes import wintypes # 定义Windows API需要的常量 GWL_EXSTYLE = -20 WS_EX_APPWINDOW = 0x00040000 WS_EX_TOOLWINDOW = 0x00000080 def set_taskbar_icon(hwnd): # 修改窗口扩展样式,添加任务栏显示属性 style = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE) style = style & ~WS_EX_TOOLWINDOW # 移除工具窗口属性 style = style | WS_EX_APPWINDOW # 添加常规窗口属性 ctypes.windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, style) # 刷新窗口样式使其生效 ctypes.windll.user32.ShowWindow(hwnd, 1) root = Tk() root.geometry("700x700") root.attributes("-topmost", 1) root.overrideredirect(1) # 初始化完成后设置任务栏图标 root.update() hwnd = wintypes.HWND(root.winfo_id()) set_taskbar_icon(hwnd) ma = False # For getting window state tr = 1 # Transparency level gx = 700 # Geometry X and Y gy = 700 def nor(event): top.config(cursor="arrow") def place_center(): # Getting screen size reso = pg.size() rx = reso[0] # Resolution: X and Y ry = reso[1] x = int((rx/2) - (700/2)) # Places to place the window in the center y = int((ry/2) - (700/2)) root.geometry(f"700x700+{x}+{y}") def drag(event): global ma root.state("normal") top.config(cursor="fleur") # Changing the cursor resb.config(text=" [ ] ") # Changing the button ma = False # Window isn't maximized fx = root.winfo_pointerx() - 250 # Placing the window as per cursor movement fy = root.winfo_pointery() - 10 root.geometry(f"700x700+{fx}+{fy}") def restore(event): global tr tr = 0 root.overrideredirect(1) root.unbind("<Map>") # So that it wont flicker while restoring # 恢复后重新设置任务栏图标属性 set_taskbar_icon(hwnd) while tr <= 1.0: # Fade in animation root.attributes("-alpha", tr) tr += 0.2 time.sleep(0.04) else: root.state('normal') def minimize(): global tr root.update_idletasks() while tr > 0: # fade out animation root.attributes("-alpha", tr) tr -= 0.1 else: root.withdraw() # withdrawing the window root.overrideredirect(0) # Activating DWM to be able to minimize root.iconify() root.bind("<Map>", restore) # To be able to restore the window def cl(): # Closing the window global tr if tr > 0: # Fade out animation root.attributes("-alpha", tr) tr -= 0.1 root.after(4, lambda: cl()) else: root.quit() def zoom(): # To maximize the window global ma root.state("zoomed") ma = True # Window is maximized resb.config(text=" []] ") # Changing the maximize button def maximize(): global ma root.unbind("<Map>") # To avoid flickering if ma == False: # Maximize if not zoom() else: root.state('normal') root.geometry(f"700x700") ma = False # Window isn't maximized resb.config(text=" [ ] ") # Changing the maximize button place_center() # Packing the control buttons and other things (like title bar) top = Frame(root, height=50, bg='white') closeb = Button(top, text=" X ", command=cl) closeb.pack(side=RIGHT) resb = Button(top, text=" [ ] ", command=maximize) resb.pack(side=RIGHT) minb = Button(top, text=" __ ", command=minimize) minb.pack(side=RIGHT) tit = Label(top, text="My Window", background="white") tit.pack(side=LEFT) top.pack(side=TOP, fill=X) # For the window to move top.bind("<B1-Motion>", drag) top.bind("<ButtonRelease-1>", nor) root.attributes("-topmost", 1) root.config(bg="grey") root.mainloop()
补充说明
- 上述方案仅适用于Windows平台,如果你需要跨平台适配,可以考虑创建一个不可见的辅助主窗口,将自定义窗口作为它的子窗口,辅助窗口始终保持在任务栏显示状态,两个窗口的最小化、激活状态同步即可。
- 你原代码的可读性很好,逻辑清晰。
内容的提问来源于stack exchange,提问作者IJ_123
相关产品推荐
相关产品推荐

