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

问题描述 投票:0回答:3

我创建了一个窗口:

root = Tk()

并删除了标题栏:

root.overrideredirect(True)

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

python windows tkinter python-3.4
3个回答
15
投票

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

2
投票

@patthoyts 答案的简化:

# Partially taken from: https://stackoverflow.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 的文档


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

# 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 应该有效。


0
投票
from tkinter import *
from ctypes import windll
import win32gui
import win32con
from win32api import GetMonitorInfo, MonitorFromPoint

def get_taskbar_height():
    monitor_info = GetMonitorInfo(MonitorFromPoint((0, 0)))
    monitor_area = monitor_info.get("Monitor")
    work_area = monitor_info.get("Work")
    taskbar_height = monitor_area[3] - work_area[3]
    return taskbar_height

class CustomTitle():
        """
        Ex:
            win = Tk()
            titleBar = CustomTitle(win,title_text = 'Hello,World!' , bg = "#000000" , fg = '#ffffff')
            titleBar.resizeable = True
            titleBar.packBar()
            win.mainloop()
    
            Note:
                    Try to Give Color value in Hex and the 3rd car should be number
                        #7a4e7a             
        """
        global win
        def __init__(self,win,title_text='Custom Title Bar',
                     bg='black',fg="white",binding_bg="gray",
                     font_style = ('Candara',13) , resizable=True,width=3,height=5):  
            # deactivating main title bar
            self._win = win
            win.title(title_text)
            self.binding_bg=binding_bg
            self.font_style = font_style
            self.resizeable = resizable
            self.moveable = True
            self.btnwidth = width
            self.height = height
    
            # props
            self.bg = bg
            self._maximized = False
            self._win_width = win.winfo_width()
            self._win_height = win.winfo_height()
            self._scr_width = win.winfo_screenwidth()
            self._scr_height = win.winfo_screenheight()
            self._addWidget(title_text,bg,fg)
            self.y = win.winfo_y()
            
        def packBar(self):
            self._title_bar.pack(fill=X)
            self._checkAbility()
            self._win.overrideredirect(1)
            self._finilize()
    
        def _checkAbility(self):
            if not self.resizeable:
                self._maximize_btn.config(state=DISABLED)
            else:
                self._resizey_widget.pack(side=BOTTOM,ipadx=.1,fill=X)
                self._resizex_widget.pack(side=RIGHT,ipadx=.1,fill=Y)
    
        def _maximize_win(self):
            if not self._maximized or self.y<=0:
                self._past_size = win.geometry()
                self._win.geometry(f"{self._scr_width}x{self._scr_height-get_taskbar_height()//2}+{0}+{0}")
                self._maximize_btn.config(text = '🗗')
                self.moveable = False                      
            else:
                self._win.geometry(self._past_size)
                self._maximize_btn.config(text = '🗖')
                self.moveable = True
            self._maximized = not self._maximized
    
    
        def _minimize(self):
            Minimize = win32gui.GetForegroundWindow()
            win32gui.ShowWindow(Minimize, win32con.SW_MINIMIZE)
    
        
        def _setIconToTaskBar(self,mainWindow):
            GWL_EXSTYLE = -20
            WS_EX_APPWINDOW = 0x00040000
            WS_EX_TOOLWINDOW = 0x00000080
            # Magic
            hwnd = windll.user32.GetParent(mainWindow.winfo_id())
            stylew = windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
            stylew = stylew & ~WS_EX_TOOLWINDOW
            stylew = stylew | WS_EX_APPWINDOW
            res = windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, stylew)
        
            mainWindow.wm_withdraw()
            mainWindow.after(1, mainWindow.wm_deiconify)
    
        def _addWidget(self,title_text,bg,fg):
            self._title_bar = Frame(self._win,bd=1,bg=bg,height=self.height,)
    
            self._title_text = Label(self._title_bar,text=title_text,height=self.height,
                                     bg=bg,fg=fg,font=self.font_style)
            self._title_text.pack(side=LEFT,padx=4,pady=3)
            self._title_text.bind("<B1-Motion>",self._drag)
    
            self._close_btn = Button(self._title_bar,text = '❌',height=self.height,
                                     bd=0,bg=bg,fg=fg,width=self.btnwidth,
                                     font=self.font_style,command=self._win.destroy)
            self._close_btn.pack(side=RIGHT,fill=Y)
            self._maximize_btn = Button(self._title_bar,text="🗖",height=self.height,
                                        bd=0,bg=bg,fg=fg,width=self.btnwidth,
                                        font=self.font_style,command=self._maximize_win)
            self._maximize_btn.pack(side=RIGHT,fill=Y)
            self._minimize_btn = Button(self._title_bar,text="_",bd=0,height=self.height,
                                        bg=bg,fg=fg,width=self.btnwidth,
                                        font=self.font_style,command=self._minimize)
            self._minimize_btn.pack(side=RIGHT,fill=Y)
            
            self._title_bar.bind('<Button-1>', self._drag)
    
            self._resizex_widget = Frame(self._win,cursor='sb_h_double_arrow')
            self._resizex_widget.bind("<B1-Motion>",self._resizex)
    
            self._resizey_widget = Frame(self._win,cursor='sb_v_double_arrow')
            self._resizey_widget.bind("<B1-Motion>",self._resizey)
    
            self._hover_effect()
    
        def _hover_effect(self):    
            def change_bg(which_one,bg = self.binding_bg):
                which_one.config(bg=bg)
            def restore_bg(which_one):
                which_one.config(bg=self.bg)
            self._maximize_btn.bind('<Enter>',lambda event: change_bg(self._maximize_btn))
            self._maximize_btn.bind('<Leave>',lambda event: restore_bg(self._maximize_btn))
            self._minimize_btn.bind('<Enter>',lambda event: change_bg(self._minimize_btn))
            self._minimize_btn.bind('<Leave>',lambda event: restore_bg(self._minimize_btn))
            self._close_btn.bind('<Enter>',lambda event: change_bg(self._close_btn,bg='red'))
            self._close_btn.bind('<Leave>',lambda event: restore_bg(self._close_btn))
    
    
        def _finilize(self):
            self._win.after(1, lambda: self._setIconToTaskBar(self._win))
    
        def _drag(self,event):
          if self.moveable:
            xwin = win.winfo_x()
            ywin = win.winfo_y()
            print(ywin)
            startx = event.x_root
            starty = event.y_root
    
            ywin = ywin - starty
            xwin = xwin - startx
    
            def _move_window(event): # runs when window is dragged
    
                win.geometry(f'+{event.x_root + xwin}+{event.y_root + ywin}')
    
    
            def _release_window(event): # runs when window is released
                win.config(cursor="arrow")
                
            self._title_bar.bind('<B1-Motion>', _move_window)
            self._title_bar.bind('<ButtonRelease-1>', _release_window)
            self._title_text.bind('<B1-Motion>', _move_window)
            self._title_text.bind('<ButtonRelease-1>', _release_window)
    
          else:
             pass
             
        def _resizex(self,event):
    
            xwin = win.winfo_x()
    
            difference = (event.x_root - xwin) - win.winfo_width()
    
            if win.winfo_width() > 150 : # 150 is the minimum width for the window
                try:
                    win.geometry(f"{ win.winfo_width() + difference }x{ win.winfo_height() }")
                except:
                    pass
            else:
                if difference > 0: # so the window can't be too small (150x150)
                    try:
                        win.geometry(f"{ win.winfo_width() + difference }x{ win.winfo_height() }")
                    except:
                        pass
    
    
        def _resizey(self,event):
    
            ywin = win.winfo_y()
    
            difference = (event.y_root - ywin) - win.winfo_height()
    
            if win.winfo_height() > 150: # 150 is the minimum height for the window
                try:
                    win.geometry(f"{ win.winfo_width()  }x{ win.winfo_height() + difference}")
                except:
                    pass
            else:
                if difference > 0: # so the window can't be too small (150x150)
                    try:
                        win.geometry(f"{ win.winfo_width()  }x{ win.winfo_height() + difference}")
                    except:
                        pass

# Example usage
win = Tk()
win.geometry("300x200")
win.eval(f'tk::PlaceWindow {win.winfo_pathname(win.winfo_id())} center')
titleBar = CustomTitle(win,title_text = 'Hello,World!' , bg = "blue" , 
                       fg = 'white' ,binding_bg="lightblue",font_style=("Candress",13)
                       ,resizable=True,width = 5,height=1)
titleBar.packBar()
win.mainloop()
© www.soinside.com 2019 - 2024. All rights reserved.