【即是过客】看不惯自带的进度条指令?教你创建一个自己的执行进度条,美观大气上档次~还支持自定义修改样式
评论
收藏

【即是过客】看不惯自带的进度条指令?教你创建一个自己的执行进度条,美观大气上档次~还支持自定义修改样式

经验分享
即是过客
2025-09-24 09:15·浏览量:1517
即是过客
影刀专家
影刀认证工程师
发布于 2025-09-23 16:21更新于 2025-09-24 09:151517浏览

💨指令名称:进度条

💫支持子指令:

【创建进度条】输入参数:进度条标题、迭代对象(支持数字、列表、字典对象)

【更新进度条】无输入参数,执行后使进度条进度+1

【更新进度条描述】输入参数:进度描述

【强制关闭进度条】无输入参数,执行后强制关闭进度条

支持鼠标穿透点击,不影响流程正常运行

不扯废话了,直接看效果:


python代码:

# 使用提醒:
# 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



创建进度条:

流程参数:指令信息:


更新进度条:



更新进度条描述:

流程参数:


强制关闭进度条:


收藏36
全部评论1
最新
发布评论
评论