Win32 使用 CreateWindowEx 创建进度条

举报
福州司马懿 发表于 2022/11/18 14:58:17 2022/11/18
【摘要】 什么是 Common ControlsWin32 API中本身提供了Windows下许多常用的控件,称为Common Controls。 这些控件与Button、ComboBox等控件不同,不是在user32.dll中实现,而是在Comctrl32.dll中实现,相关的C++原型声明在commctrl.h中。 使用 Common Controls所以,在使用Win32 API编写Windo...

什么是 Common Controls

Win32 API中本身提供了Windows下许多常用的控件,称为Common Controls。 这些控件与Button、ComboBox等控件不同,不是在user32.dll中实现,而是在Comctrl32.dll中实现,相关的C++原型声明在commctrl.h中。

使用 Common Controls

所以,在使用Win32 API编写Windows窗口应用程序时,如果在界面上用到了Common Controls,则必须在链接选项中包含comctrl32.lib库,并在程序初始化时调用InitCommonControls()函数,确保控件被加载。

引入代码如下

#include <CommCtrl.h>
#pragma comment(lib, "Comctl32") //InitCommonControls

获取窗口大小

GetClientRect 函数用于获取窗口客户区的坐标,客户区坐标指的是客户区的左上角坐标和右下角坐标

由于客户区坐标是相对窗口客户区的左上角而言的,因此左上角坐标为(0,0)。即 left 和 top 字段通常设定为0,而 right 和 bottom 字段设定为显示区域的宽度和高度(像素点数)

RECT rc;
GetClientRect(hWnd, &rc);
int width = rc.right - rc.left;
int height = rc.bottom - rc.top;

注意:GetClientRectShowWindow 之前调用,也是能拿到客户端区域范围的

创建进度条

创建进度条之前需要先调用 InitCommonControls函数,确保进度条控件被加载。代码如下

void CreateProgress(HINSTANCE hInstance, HWND hWnd, int x = 0, int y = 0, int width = 0, int height = 0, long additionStyle = 0)
{
    //册并初始化通用控件窗口类。包括进度条类PROGRESS_CLASS
    InitCommonControls();

    //创建进度条
    HWND hwndPB = CreateWindowEx(
        0,
        PROGRESS_CLASS,
        NULL,
        WS_CHILD | WS_VISIBLE | additionStyle,
        x, y, width, height,
        hWnd,
        nullptr,
        hInstance,
        nullptr);
}

创建进度条和创建窗口一样,用的都是 CreateWindowEx 函数,之所以这样,原因是控器和窗口对于window其实是等价的,其实每一个控件都是一个窗口,并且它还是可移动的 (想要看到这个效果,只需去掉进度条样式里的 WS_CHILD 即可)

图片.png

图片.png

添加线程,执行动画

要添加线程,首先要添加 thread 的头文件 #include <thread>

然后定义线程函数 PBThreadProc,每次改变进度后,需要停顿一会,然后再改变(模拟执行任务耗时)

#define PROGRESS_STEP   0.05     //进度条每一步的步长
#define PROGRESS_SLEEP  100      //进度条每走一下,休息的时间(单位毫秒)

DWORD WINAPI PBThreadProc(LPVOID lpParameter)
{
    HWND hwndPB = (HWND)lpParameter;    //进度条的窗口句柄
    PBRANGE range;                        //进度条的范围

    SendMessage(hwndPB, PBM_SETRANGE,    //设置进度条的范围
        (WPARAM)0, (LPARAM)(MAKELPARAM(0, 100)));

    SendMessage(hwndPB, PBM_GETRANGE,    //获取进度条的范围
        (WPARAM)TRUE,                    //TRUE 表示返回值为范围的最小值,FALSE表示返回最大值
        (LPARAM)&range);

    while (TRUE)
    {
        SendMessage(hwndPB, PBM_DELTAPOS, //设置进度条的新位置为当前位置加上范围的1/20
            (WPARAM)((range.iHigh - range.iLow) * PROGRESS_STEP), (LPARAM)0);
        if (SendMessage(hwndPB, PBM_GETPOS, (WPARAM)0, (LPARAM)0) //取得进度条当前位置
            == range.iHigh)
        {
            Sleep(PROGRESS_SLEEP); //当前进度要保留一定时间
            SendMessage(hwndPB, PBM_SETPOS, (WPARAM)range.iLow, (LPARAM)0); //将进度条复位(复位后会立即改变进度条位置)
        }
        Sleep(PROGRESS_SLEEP); //每次更改进度后,停留一定时间
    }
}

最后创建并启动线程

 CreateThread(            //操作进度条的线程
        NULL,
        0,
        (LPTHREAD_START_ROUTINE)PBThreadProc,
        hwndPB,
        0,
        0
);

进度条样式

进度条的样式在微软API文档 https://learn.microsoft.com/zh-cn/windows/win32/controls/progress-bar-control-styles

样式 说明
PBS_MARQUEE 版本 6.0 或更高版本。 进度指示器的大小不会增大,而是在条形的长度上重复移动,指示活动而不指定进度完成的比例。[!注意] Comctl32.dll版本 6 不可再发行,但它包含在 Windows 或更高版本中。 若要使用Comctl32.dll版本 6,请在清单中指定它。 有关清单的详细信息,请参阅 “启用视觉样式”。
PBS_SMOOTH 版本 4.70 或更高版本。 进度栏在平滑滚动条而不是默认分段条中显示进度状态。[!注意] 此样式仅在Windows经典主题中受支持。 所有其他主题都覆盖此样式。
PBS_SMOOTHREVERSE 版本 6.0 或更高版本,Windows Vista。确定将进度栏从较高值向低 (向后移动时应使用的动画行为) 。 如果已设置此项,则会发生“平滑”转换,否则控件将“跳转”到较低的值。
PBS_VERTICAL 版本 4.70 或更高版本。 进度栏从下到上垂直显示进度状态。

测试代码

测试代码还是放在构造窗体的 InitInstance 函数上

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // 将实例句柄存储在全局变量中

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, 500, 500, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   //获取窗口大小
   RECT rc;
   GetClientRect(hWnd, &rc);
   int width = rc.right - rc.left;
   int height = rc.bottom - rc.top;

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   int progressSize = 20;
   int progressPosY = 0;

   //默认分段显示进度状态
   CreateProgress(hInstance, hWnd, 0, 0, width, progressSize);
   progressPosY += 2 * progressSize;

   CreateProgress(hInstance, hWnd, 0, progressPosY, width, progressSize, PBS_MARQUEE);
   progressPosY += 2 * progressSize;

   //进度栏在平滑滚动条而不是默认分段条中显示进度状态
   CreateProgress(hInstance, hWnd, 0, progressPosY, width, progressSize, PBS_SMOOTH);
   progressPosY += 2 * progressSize;

   CreateProgress(hInstance, hWnd, 0, progressPosY, width, progressSize, PBS_SMOOTHREVERSE);
   progressPosY += 2 * progressSize;

   //进度栏从下到上垂直显示进度状态
   CreateProgress(hInstance, hWnd, 0, progressPosY, progressSize, height / 2, PBS_VERTICAL);

   return TRUE;
}

图片.png

实际测试发现,只有3种样式有效,其他样式无效

  • 分段进度条样式(默认)
  • 平滑进度条样式
  • 垂直进度条样式
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。