之前做过对矩形的分段填充,这个操作就类似于进度条。这次对三角形区域进行分段填充。
我们可以将这个操作想象为从左到右拿着一根线一点一点的进行扫描,要记录每一个瞬间的图形,然后通过CreatePolygonRgn函数将扫描过程中的图形创建出来,然后用FillRgn上色填充。具体代码如下:
#include <windows.h>
//GDI分段绘制区域
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
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);
RECT rect;
GetClientRect(hwnd, &rect);
while (1)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
}
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
HRGN hRgn,hRgn2;
HBRUSH hBrush, hBrush2;
POINT point[4] = { 100,300,100,400,200,350,100,300 }; //三角形区域,第一个点100,300和第二个点100,400构成一条直线
static int line = 100; //从x=100开始扫描 //第二个点100,400和第三个点200,350构成一条直线
static int x1 = 0, y1 = 0,x2=0,y2=0;//变化的两个点 //第三个点200,350和100,300构成最后一条直线
RECT rect;
POINT p[4] = { 100,300,100,400,0,0,0,0 };//前两个点是一样的,就变化两个点
//因为在扫描三角形的过程中,图形会变成一个梯形,但变化的只有两个点
//分段填充三角形
//第一个点和第二个点是在x轴上,所以我们从x=100开始分段填充三角形区域
//就相当于拿根横穿三角形的直线,计算与两个斜边的交点,加上前两个点构成一个区域
//创建这个区域,然后用FillRgn进行填充,以此来达到分段填充的目的
//第一个点和第三个点的直线方程为:y=1/2x+250,第二个点与第三个点的直线方程为:y=-1/2x+450,可以用两点式方程算下
switch (message)
{
case WM_TIMER: //定时器消息
GetClientRect(hwnd, &rect);
InvalidateRect(hwnd, &rect, TRUE);//因为所重绘的图形不多,所以就无效整个客户区的矩形
return 0;
case WM_CREATE:
SetTimer(hwnd, 1, 100, NULL);
return 0;
case WM_SIZE:
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
hBrush = CreateSolidBrush(BLACK_BRUSH);
hRgn = CreatePolygonRgn(point, 4, ALTERNATE); //创建了一个三角形区域,这个区域用的是跟窗口背景
//一样的白色,所以看不出来
SelectObject(hdc, hRgn);
PaintRgn(hdc, hRgn); //使用当前的画刷,也就是窗口的的背景色
if (line < 200)
{
//计算与两条直线的交点
//第一条;y=1/2x+250
x1 = line;
y1 = 1.0 / 2.0 * line + 250;
//第二条:y=-1/2x+450
x2 = line;
y2 = -1.0 / 2.0 * line + 450;
p[2].x = x2;
p[2].y = y2;
p[3].x = x1;
p[3].y = y1;
hRgn2 = CreatePolygonRgn(p, 4, ALTERNATE);
SelectObject(hdc, hRgn2);
FillRgn(hdc, hRgn2, hBrush);
DeleteObject(hRgn2);
line++;
}
if (line == 200)
{
hRgn2 = CreatePolygonRgn(point, 4, ALTERNATE);
SelectObject(hdc, hRgn2);
FillRgn(hdc, hRgn2, hBrush);
DeleteObject(hRgn2);
}
DeleteObject(hRgn);
DeleteObject(hBrush);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
瞬间的结果如下:
三角形区域如下:
通过这次学习,我感觉搞图形研究数学很关键,我这次还是简单的三角形,在复杂点就要写好多方程了。