Win32 使用 CreateWindowEx 创建进度条
什么是 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;
注意:GetClientRect
在 ShowWindow
之前调用,也是能拿到客户端区域范围的
创建进度条
创建进度条之前需要先调用 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
即可)
添加线程,执行动画
要添加线程,首先要添加 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;
}
实际测试发现,只有3种样式有效,其他样式无效
- 分段进度条样式(默认)
- 平滑进度条样式
- 垂直进度条样式
- 点赞
- 收藏
- 关注作者
评论(0)