最近我像学习下图形的绘制,自己是学C/C++的,所以我就把目光放在了GDI上面。基本的win32编程和基本的GDI绘制我已经了解,接下来就进行实践环节。
最简单的GDI绘制图形那就是矩形了,所以我用基本的矩形来绘制进度条,今天写的是最基本的,之后我会把相关操作写成类,代码如下(代码里面有很详细的注释,所以我就不过多介绍了)
#include <windows.h>
#include <atlstr.h> //因为wsprintf不能进行浮点型转换,所以加上这个用CString
//自绘一个进度条
//定义一个定时器宏
#define ID_TIMER 1
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int cxClient, cyClient; //客户区的高和宽
RECT rect;
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
static TCHAR szAppName[] = TEXT("ProgressBar");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_INFORMATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
RegisterClass(&wndclass);
hwnd = CreateWindow(szAppName, L"自绘一个进度条",
WS_OVERLAPPEDWINDOW,
100, 200, 800, 600, NULL, NULL, hInstance, NULL
);
ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
void RenderProgressBar(HWND hwnd) //重绘进度条
{
RECT RenderRect;
RenderRect.left = rect.left;
RenderRect.top = rect.top;
RenderRect.right = cxClient;
RenderRect.bottom = rect.bottom;
InvalidateRect(hwnd, &RenderRect, TRUE); //只是让进度条和显示文字的矩形无效就行了
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdcClient;
PAINTSTRUCT ps;
//画笔画刷
HBRUSH hBrush;
HPEN hPen,hOldPen;
TCHAR temp[40];
static float right;
float tempD;
CString str;
int x;
switch (message)
{
case WM_TIMER: //定时器消息
RenderProgressBar(hwnd);
return 0;
case WM_CREATE:
SetTimer(hwnd, ID_TIMER, 100, NULL); //每隔10秒触发
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam); //获取客户区的大小
cyClient = HIWORD(lParam);
rect.left = cxClient / 2 - 300;
rect.top = cyClient / 2;
rect.right = cxClient / 2 - 300;
rect.bottom = cyClient / 2 + 50;
right = cxClient / 2 + 300;
return 0;
case WM_PAINT:
hPen = CreatePen(PS_NULL, 0, 0); //创建一个新画笔(这个画笔在绘制矩形的时候是没有边框的)
hBrush = (HBRUSH)GetStockObject(BLACK_BRUSH); //取得黑色的画刷
hdcClient = BeginPaint(hwnd, &ps);
hOldPen = (HPEN)SelectObject(hdcClient, hPen); //取得原来的画笔并将自己创建的画笔放入hdc中
//创建一个长600,宽50的矩形,位置在客户区中央
Rectangle(hdcClient, cxClient / 2-300, cyClient / 2, cxClient / 2 + 300, cyClient / 2 + 50);
if (rect.right <= right) //如果还没到头
{
FillRect(hdcClient, &rect, hBrush);
tempD = (float)(rect.right - rect.left) / 600.0;
str.Format(TEXT("进度:%.2f%%"), tempD*100.0);
TextOut(hdcClient, right, rect.top + 25, temp, wsprintf(temp, L"%s", str.GetBuffer(str.GetLength())));
rect.right++;
}
if (rect.right > right)//已经100%了
{
RECT tempRect;
tempRect.left = rect.left;
tempRect.top = rect.top;
tempRect.right = rect.right-1;
tempRect.bottom = rect.bottom;
FillRect(hdcClient, &tempRect, hBrush);
TextOut(hdcClient, right, rect.top + 25, temp, wsprintf(temp, L"进度:%d.00%%", 100));
}
DeleteObject(hPen);
SelectObject(hdcClient, hOldPen);//将原来的画笔还回去
DeleteObject(hBrush);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
KillTimer(hwnd, ID_TIMER);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
运行如下:
基本的进度条就这样了,之后我会将它进行改进,改成类的样子,这样的话可以自己设置宽高和进度条的值。