上一篇有点小BUG,就是最大化时把状态栏给遮挡了,所以在最大化时调整一下窗体大小。
鼠标在按钮上移动时窗体也跟着移动,要过滤一下事件。
from tkinter import Tk, Frame, Label, Button, Canvas
from ctypes import Structure, c_long, windll, byref
from PIL import Image, ImageTk
class RECT(Structure):
_fields_ = [("left", c_long), ("top", c_long), ("right", c_long), ("bottom", c_long)]
SPI_GETWORKAREA = 48
GWL_STYLE = -16 # 用于获取窗口样式
WS_CAPTION = 12582912 # 窗口标题栏样式
WS_THICKFRAME = 262144 # 窗口可调整边框样式
WM_SYSCOMMAND = 274
SC_SIZE = 61440
SC_MOVE = 61456
HTCAPTION = 2
WMSZ_LEFT = 1
WMSZ_RIGHT = 2
WMSZ_TOP = 3
WMSZ_TOPLEFT = 4
WMSZ_TOPRIGHT = 5
WMSZ_BOTTOM = 6
WMSZ_BOTTOMLEFT = 7
WMSZ_BOTTOMRIGHT = 8
class WindowTk(Tk):
def __init__(self, icon='logo.ico', name='TK窗体', width=1000, height=600, min_w=600, min_h=400):
super().__init__()
self.margin = 10
self.bg_color = 'white'
self.head_height = 30
'''居中显示'''
work_rect = RECT()
windll.user32.SystemParametersInfoW(SPI_GETWORKAREA, 0, byref(work_rect), 0)
self.ww = work_rect.right - work_rect.left
self.wh = work_rect.bottom - work_rect.top
size = '%dx%d+%d+%d' % (width, height, (self.ww - width) / 2, (self.wh - height) / 2)
self.geometry(size)
self.iconbitmap(icon)
self.title(name)
self.minsize(min_w, min_h)
self.configure(bg=self.bg_color)
'''无边框'''
self.update_idletasks() # 刷新窗口状态
self.hwnd = windll.user32.GetParent(self.winfo_id()) # 获取窗口句柄
style = windll.user32.GetWindowLongPtrW(self.hwnd, GWL_STYLE)
style &= ~(WS_CAPTION | WS_THICKFRAME)
windll.user32.SetWindowLongPtrW(self.hwnd, GWL_STYLE, style)
'''标题栏'''
title_bar = Frame(self, name='title_bar', bg=self.bg_color, height=self.head_height)
title_bar.pack(fill='x', padx=self.margin, pady=5)
icon_canvas = Canvas(title_bar, name='icon_canvas_bar', highlightthickness=0, bg=self.bg_color,
width=self.head_height, height=self.head_height)
icon_canvas.pack(side='left', fill='y')
title_label = Label(title_bar, bg=self.bg_color, name='name_bar', text=name, font=("Microsoft YaHei", 10))
title_label.pack(side='left', fill='y')
button = Button(title_bar, text="关闭", command=self.destroy)
button.pack(side='right')
button = Button(title_bar, text="最大化", command=self.max_win)
button.pack(side='right')
button = Button(title_bar, text="最小化", command=self.min_win)
button.pack(side='right')
ico_h = 24
ico = Image.open(icon).resize((ico_h, ico_h))
ico = ImageTk.PhotoImage(ico)
icon_canvas.create_image((self.head_height - ico_h) / 2, (self.head_height - ico_h) / 2, anchor="nw", image=ico)
icon_canvas.image = ico
'''窗体事件'''
self.action = None
self.direction = None
self.bind("<Motion>", self.move)
self.bind("<B1-Motion>", self.on_motion)
def move(self, e):
if str(e.widget).endswith('.') or str(e.widget).endswith('bar'):
x = e.x_root - self.winfo_x()
y = e.y_root - self.winfo_y()
if x <= self.margin and y <= self.margin:
self.set_cursor('@C:/Windows/Cursors/aero_nwse.cur', SC_SIZE, WMSZ_TOPLEFT)
elif self.winfo_width() - 1 - self.margin > x > self.margin > y:
self.set_cursor('sb_v_double_arrow', SC_SIZE, WMSZ_TOP)
elif self.winfo_width() - 1 - self.margin <= x and y <= self.margin:
self.set_cursor('@C:/Windows/Cursors/aero_nesw.cur', SC_SIZE, WMSZ_TOPRIGHT)
elif self.winfo_width() - 1 - self.margin < x and self.margin < y < self.winfo_height() - 1 - self.margin:
self.set_cursor('sb_h_double_arrow', SC_SIZE, WMSZ_RIGHT)
elif self.winfo_width() - 1 - self.margin <= x and self.winfo_height() - 1 - self.margin <= y:
self.set_cursor('@C:/Windows/Cursors/aero_nwse.cur', SC_SIZE, WMSZ_BOTTOMRIGHT)
elif self.margin < x < self.winfo_width() - 1 - self.margin and self.winfo_height() - 1 - self.margin < y:
self.set_cursor('sb_v_double_arrow', SC_SIZE, WMSZ_BOTTOM)
elif x <= self.margin and self.winfo_height() - 1 - self.margin <= y:
self.set_cursor('@C:/Windows/Cursors/aero_nesw.cur', SC_SIZE, WMSZ_BOTTOMLEFT)
elif x < self.margin < y < self.winfo_height() - 1 - self.margin:
self.set_cursor('sb_h_double_arrow', SC_SIZE, WMSZ_LEFT)
else:
self.set_cursor('arrow', SC_MOVE, HTCAPTION)
else:
self.configure(cursor='arrow')
def set_cursor(self, cursor, action, direction):
self.configure(cursor=cursor)
self.action = action
self.direction = direction
def on_motion(self, e):
if str(e.widget).endswith('.') or str(e.widget).endswith('bar'):
windll.user32.ReleaseCapture()
windll.user32.SendMessageW(self.hwnd, WM_SYSCOMMAND, self.action | self.direction, 0)
def min_win(self):
self.state("icon")
def max_win(self):
if self.wm_state() == 'zoomed':
self.state('normal')
return
self.state('zoomed')
windll.user32.MoveWindow(self.hwnd, 0, 0, self.ww + 1, self.wh + 1, True)
if __name__ == '__main__':
root = WindowTk()
root.mainloop()
979

被折叠的 条评论
为什么被折叠?



