# -*- coding: utf-8 -*-
import typing as t
import tkinter as tk
import ctypes
import ctypes.wintypes as w
def ErrorIfZero(result, func, args):
if not result:
raise ctypes.WinError(ctypes.get_last_error())
return result
# используем user32.dll
user32 = ctypes.windll.user32
# описываем используемые функции, типы и константы
WNDENUMPROC = ctypes.WINFUNCTYPE(w.BOOL, w.HWND, w.LPARAM)
user32.EnumWindows.argtypes = [WNDENUMPROC, w.LPARAM]
user32.EnumWindows.restype = w.BOOL
user32.GetClassNameW.argtypes = [w.HWND, w.LPWSTR, w.INT]
user32.GetClassNameW.restype = w.INT
user32.GetClassNameW.errcheck = ErrorIfZero
user32.GetWindowLongW.argtypes = [w.HWND, w.INT]
user32.GetWindowLongW.restype = w.DWORD
user32.SetWindowLongW.argtypes = [w.HWND, w.INT, w.LONG]
user32.SetWindowLongW.restype = w.DWORD
user32.SetWindowPos.argtypes = [w.HWND, w.HWND, w.INT, w.INT, w.INT, w.INT, w.UINT]
user32.SetWindowPos.restype = w.BOOL
user32.SetWindowPos.errcheck = ErrorIfZero
user32.SetParent.argtypes = [w.HWND, w.HWND]
user32.SetParent.restype = w.HWND
user32.GetParent.argtypes = [w.HWND]
user32.GetParent.restype = w.HWND
GWL_STYLE = w.INT(-16)
WS_CHILD = 0x40000000
SWP_NOACTIVATE = 0x0010
SWP_NOZORDER = 0x0004
SWP_SHOWWINDOW = 0x0040
# определяем дескриптор окна панели задач
def get_taskbar_window() -> w.HWND:
class_buf = ctypes.create_unicode_buffer(256)
handle: w.HWND = 0
#callback - функция будет проверять каждое окно
def process_window(hWnd: w.HWND, lParam: w.LPARAM) -> w.BOOL:
length = user32.GetClassNameW(hWnd, class_buf, len(class_buf))
name = ''.join(class_buf[:length])
if 'Shell_TrayWnd' == name: # имя класса окна панели задач всегда "Shell_TrayWnd"
nonlocal handle
handle = hWnd
return 0 # нашли, стоп
return 1 # не нашли, идём дальше
# перебираем окна верхнего уровня
user32.EnumWindows(WNDENUMPROC(process_window), 0)
if handle == 0:
raise ValueError('Taskbar not found')
return handle
def make_attachment() -> tk.Tk: #создаём простое окно
root = tk.Tk()
def button_command():
print('Bye!')
root.destroy()
item = tk.Button(root, text='Hello, World!', command=button_command)
item.pack(expand=True, fill='both')
return root
def attach(root: tk.Tk, hTaskbar: w.HWND):
hTop: w.HWND = user32.GetParent(w.HWND(root.winfo_id())) #дескриптор окна верхнего уровня для нашего приложения
user32.SetParent(hTop, hTaskbar) #задаём родителем панель задач
user32.SetWindowLongW(hTop, GWL_STYLE, WS_CHILD) #говорим, что наше окно на самом деле дочернее, а не верхнего уровня
user32.SetWindowPos(hTop,
0, #z-order - после какого окна должно идти наше. 0 - наверху
500, 0, # положение окна, пикселей
100, 40, # рамер окна, пикселей
SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW) # позиционируем и показываем окно
hTaskbar = get_taskbar_window()
root = make_attachment()
# откладываем вызов attach(root, hTaskbar)
# так как ткинтер некоторые настройки задаёт не сразу же
root.after(1, attach, root, hTaskbar)
root.mainloop()