

发布于 2025-09-23 16:21更新于 2025-09-24 09:151517浏览支持鼠标穿透点击,不影响流程正常运行
不扯废话了,直接看效果:

# 使用提醒:
# 1. xbot包提供软件自动化、数据表格、Excel、日志、AI等功能
# 2. package包提供访问当前应用数据的功能,如获取元素、访问全局变量、获取资源文件等功能
# 3. 当此模块作为流程独立运行时执行main函数
# 4. 可视化流程中可以通过"调用模块"的指令使用此模块
import xbot
from xbot import print, sleep
from .package import variables as glv
import time
import win32gui
import win32con
import win32api
from ctypes import windll
import sys
_global_progress_bar = None
class BeautifulProgressBar:
def __init__(self, title="Progress", width=500, height=100, x=None, y=None, total=100):
"""
初始化美化的进度条窗口
Args:
title: 窗口标题
width: 窗口宽度
height: 窗口高度
x, y: 窗口位置,None 表示居中
total: 总进度值,默认为100
"""
self.title = title
self.width = width
self.height = height
self.x = x
self.y = y
self.hwnd = None
self.total = total
self.current = 0
self.task_desc = "处理中..."
self._is_created = False
# 字体大小配置
self.font_size_title = 18
self.font_size_desc = 15
self.font_size_text = 15
# 颜色配置
self.colors = {
'bg': win32api.RGB(0, 0, 0), # 背景色(深色)
'border': win32api.RGB(242, 242, 242), # 边框色
'progress_bg': win32api.RGB(230, 230, 230), # 进度条背景色
'progress': win32api.RGB(50, 150, 255), # 进度条颜色
'text': win32api.RGB(0, 0, 0), # 文本颜色
'title': win32api.RGB(255, 92, 51) # 标题颜色
}
# 注册窗口类
self.wc = win32gui.WNDCLASS()
self.wc.lpfnWndProc = self.wnd_proc # 消息处理函数
self.wc.lpszClassName = "BeautifulProgressBarClass"
self.wc.hbrBackground = win32gui.GetStockObject(win32con.BLACK_BRUSH)
self.wc.hCursor = win32gui.LoadCursor(0, win32con.IDC_ARROW)
try:
try:
self.wc.hInstance = windll.kernel32.GetModuleHandleW(None)
except:
import sys
self.wc.hInstance = win32api.GetModuleHandle(sys.executable)
except:
self.wc.hInstance = 0
try:
win32gui.UnregisterClass(self.wc.lpszClassName, None)
except:
pass
self.class_atom = win32gui.RegisterClass(self.wc)
# 创建窗口
self.create_window()
def create_window(self):
if self.x is None or self.y is None:
desktop_rect = win32gui.GetWindowRect(win32gui.GetDesktopWindow())
self.x = (desktop_rect[2] - self.width) // 2
self.y = (desktop_rect[3] - self.height) * 2 // 3 #进度条在屏幕的位置
# 创建窗口
self.hwnd = win32gui.CreateWindow(
self.class_atom,
self.title,
win32con.WS_POPUP | win32con.WS_VISIBLE,
self.x, self.y, self.width, self.height,
0, 0, self.wc.hInstance, None
)
radius = 15
h_rgn = win32gui.CreateRoundRectRgn(0, 0, self.width, self.height, radius, radius)
win32gui.SetWindowRgn(self.hwnd, h_rgn, True)
# 始终置顶
win32gui.SetWindowPos(self.hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0,
win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)
hwnd_ex_style = win32gui.GetWindowLong(self.hwnd, win32con.GWL_EXSTYLE)
win32gui.SetWindowLong(self.hwnd, win32con.GWL_EXSTYLE,
hwnd_ex_style | win32con.WS_EX_TOOLWINDOW | win32con.WS_EX_LAYERED | win32con.WS_EX_TRANSPARENT)
win32gui.SetLayeredWindowAttributes(self.hwnd, 0, 180, win32con.LWA_ALPHA)
self._is_created = True
win32gui.UpdateWindow(self.hwnd)
def wnd_proc(self, hwnd, msg, wparam, lparam):
if msg == win32con.WM_PAINT:
try:
# 处理绘制消息
hdc, paint_struct = win32gui.BeginPaint(hwnd)
# 创建缓冲区以减少闪烁
mem_dc = win32gui.CreateCompatibleDC(hdc)
bmp = win32gui.CreateCompatibleBitmap(hdc, self.width, self.height)
win32gui.SelectObject(mem_dc, bmp)
# 绘制背景
brush = win32gui.CreateSolidBrush(self.colors['bg'])
rect = (0, 0, self.width, self.height)
win32gui.FillRect(mem_dc, rect, brush)
win32gui.DeleteObject(brush)
# 绘制边框
pen = win32gui.CreatePen(win32con.PS_SOLID, 1, self.colors['border'])
old_pen = win32gui.SelectObject(mem_dc, pen)
radius = 15
win32gui.RoundRect(mem_dc, 5, 5, self.width-5, self.height-5, radius, radius)
win32gui.SelectObject(mem_dc, old_pen)
win32gui.DeleteObject(pen)
# 创建字体
def create_font(height):
lf = win32gui.LOGFONT()
lf.lfHeight = -height
lf.lfWeight = win32con.FW_NORMAL
lf.lfItalic = False
lf.lfUnderline = False
lf.lfStrikeOut = False
lf.lfCharSet = win32con.DEFAULT_CHARSET
lf.lfOutPrecision = win32con.OUT_TT_PRECIS
lf.lfClipPrecision = win32con.CLIP_DEFAULT_PRECIS
lf.lfQuality = win32con.ANTIALIASED_QUALITY # 抗锯齿
lf.lfPitchAndFamily = win32con.DEFAULT_PITCH
lf.lfFaceName = "Microsoft YaHei UI"
return win32gui.CreateFontIndirect(lf)
font_title = create_font(self.font_size_title)
font_desc = create_font(self.font_size_desc)
font_text = create_font(self.font_size_text)
# 绘制标题
old_font = win32gui.SelectObject(mem_dc, font_title)
win32gui.SetTextColor(mem_dc, self.colors['title'])
win32gui.SetBkMode(mem_dc, win32con.TRANSPARENT)
title_rect = (15, 8, self.width-15, 30)
win32gui.DrawText(mem_dc, str(self.title), -1, title_rect, win32con.DT_LEFT | win32con.DT_VCENTER)
# 绘制任务描述
win32gui.SelectObject(mem_dc, font_desc)
win32gui.SetTextColor(mem_dc, self.colors['text'])
desc_rect = (15, 35, self.width-15, 55)
win32gui.DrawText(mem_dc, str(self.task_desc), -1, desc_rect, win32con.DT_LEFT | win32con.DT_VCENTER)
# 绘制进度条背景
progress_height = 25
progress_top = self.height - 40
progress_bg_rect = (15, progress_top, self.width-15, progress_top + progress_height)
brush = win32gui.CreateSolidBrush(self.colors['progress_bg'])
win32gui.FillRect(mem_dc, progress_bg_rect, brush)
win32gui.DeleteObject(brush)
# 绘制进度条
if self.total > 0:
progress_width = int((self.current / self.total) * (self.width - 30))
progress_rect = (15, progress_top, 15 + progress_width, progress_top + progress_height)
brush = win32gui.CreateSolidBrush(self.colors['progress'])
win32gui.FillRect(mem_dc, progress_rect, brush)
win32gui.DeleteObject(brush)
# 绘制进度文本 (百分比)
percentage = (self.current / self.total) * 100 if self.total > 0 else 0
progress_text = f"{percentage:.1f}%"
win32gui.SelectObject(mem_dc, font_text)
win32gui.SetTextColor(mem_dc, self.colors['text'])
win32gui.SetBkMode(mem_dc, win32con.TRANSPARENT)
text_rect = (15, progress_top, self.width-15, progress_top + progress_height)
win32gui.DrawText(mem_dc, progress_text, -1, text_rect, win32con.DT_CENTER | win32con.DT_VCENTER)
# 绘制进度计数 (当前/总)
count_text = f"{self.current}/{self.total}"
win32gui.DrawText(mem_dc, count_text, -1, text_rect, win32con.DT_RIGHT | win32con.DT_VCENTER)
# 清理字体资源
win32gui.SelectObject(mem_dc, old_font)
win32gui.DeleteObject(font_title)
win32gui.DeleteObject(font_desc)
win32gui.DeleteObject(font_text)
# 将缓冲区内容复制到屏幕
win32gui.BitBlt(hdc, 0, 0, self.width, self.height, mem_dc, 0, 0, win32con.SRCCOPY)
# 清理资源
win32gui.DeleteObject(bmp)
win32gui.DeleteDC(mem_dc)
win32gui.EndPaint(hwnd, paint_struct)
except Exception as e:
print(f"Error in WM_PAINT: {e}")
return 0
elif msg == win32con.WM_DESTROY:
# 窗口销毁
win32gui.PostQuitMessage(0)
return 0
else:
# 默认消息处理
return win32gui.DefWindowProc(hwnd, msg, wparam, lparam)
def update_progress(self, progress=None, increment=None):
"""
Args:
progress: 设置当前进度值(0到total之间)
increment: 增加的进度值
Returns:
bool: 是否更新成功
"""
if not self._is_created or not self.hwnd:
return False
# 更新当前进度值
if progress is not None:
self.current = max(0, min(self.total, progress))
elif increment is not None:
self.current = max(0, min(self.total, self.current + increment))
else:
return False
try:
# 请求重绘
win32gui.InvalidateRect(self.hwnd, None, True)
# 强制重绘
win32gui.UpdateWindow(self.hwnd)
# 处理窗口消息
win32gui.PumpWaitingMessages()
return True
except Exception as e:
return False
def update_task_desc(self, task_desc):
"""
修改任务描述
Args:
task_desc: 新的任务描述文本
"""
if not self._is_created or not self.hwnd:
return
self.task_desc = task_desc
try:
# 请求重绘
win32gui.InvalidateRect(self.hwnd, None, True)
# 强制重绘
win32gui.UpdateWindow(self.hwnd)
except:
pass
def close(self):
"""
立即关闭进度条窗口
"""
if self.hwnd:
try:
# 立即销毁窗口,不显示完成动画
win32gui.DestroyWindow(self.hwnd)
except:
pass
self.hwnd = None
self._is_created = False
def close_with_animation(self):
"""
带完成动画关闭进度条窗口
"""
if self.hwnd:
# 完成动画效果(闪烁几次)
if self.current >= self.total:
try:
for _ in range(3):
win32gui.SetLayeredWindowAttributes(self.hwnd, 0, 150, win32con.LWA_ALPHA)
time.sleep(0.1)
win32gui.SetLayeredWindowAttributes(self.hwnd, 0, 230, win32con.LWA_ALPHA)
time.sleep(0.1)
except:
pass
try:
win32gui.DestroyWindow(self.hwnd)
except:
pass
self.hwnd = None
self._is_created = False
TextProgressBar = BeautifulProgressBar
def create(title, total:int):
"""
创建一个进度条
Args:
title: 进度条标题
total: 总进度数量
"""
global _global_progress_bar
# 如果已有进度条,先关闭
if _global_progress_bar:
_global_progress_bar.close()
# 创建新的进度条(初始进度为0)
_global_progress_bar = BeautifulProgressBar(title=title, width=550, height=120, total=total)
# 初始显示0进度
_global_progress_bar.update_progress(progress=0)
return _global_progress_bar
def update():
"""
将进度条进度加1
"""
global _global_progress_bar
if _global_progress_bar:
result = _global_progress_bar.update_progress(increment=1)
# 如果进度已完成,自动关闭进度条
if result and _global_progress_bar.current >= _global_progress_bar.total:
# 使用带动画的关闭方式
_global_progress_bar.close_with_animation()
return result
def update_msg(msg):
"""
修改进度条描述
Args:
msg: 新的描述消息
"""
global _global_progress_bar
if _global_progress_bar:
_global_progress_bar.update_task_desc(msg)
def close():
"""
立即关闭进度条
"""
global _global_progress_bar
if _global_progress_bar:
_global_progress_bar.close()
_global_progress_bar = None流程参数:
指令信息:

流程参数:
