万花筒
简要介绍一下调用Win API实现万花筒的过程:
首先假想一个圆,在其边界上有25个等分点,将其坐标存进数组,等分点的数据结构如下:
typedef struct DOT
{
POINT point[DOTNUM]; //存储点的x,y坐标
COLORREF color[DOTNUM]; //每个点的颜色,假设第1个点向第2个点划线,则这条线的颜色是第2个点的颜色
}DOT;
可以看到每个点还有对应的一个颜色,这是因为我们的万花筒是由各种颜色不一的线绘制出来的,因此给每个点设置了一个颜色。假设从a点向b点画一条直线,那么这条直线的颜色就是b点存储的颜色。
代码如下:
#include <Windows.h>
#include <math.h>
#define PI 3.1415926
#define DOTNUM 25 //等分点的个数
#define R 200 //半径
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL InitWindowsClass(HINSTANCE);
BOOL InitWindows(HINSTANCE, int);
TCHAR lpszClassName[] = L"作业";
TCHAR sizeTitle[] = L"万花筒";
//-------等分点的结构体-------//
typedef struct DOT
{
POINT point[DOTNUM]; //存储点的x,y坐标
COLORREF color[DOTNUM]; //每个点的颜色,假设第1个点向第2个点划线,则这条线的颜色是第2个点的颜色
}DOT;
DOT dot;
int j = 0; //画线时用到
int WINAPI WinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
{
MSG Msg;
//--------------------设置25个等分点的坐标和每个点的颜色--------------------//
for (int i = 0; i < DOTNUM; ++i)
{
dot.point[i].x = (long)(R * cos((360.0 / DOTNUM) * i * PI / 180.0));
dot.point[i].y = (long)(R * sin((360.0 / DOTNUM) * i * PI / 180.0));
switch (i % 4)
{
case 0:
dot.color[i] = RGB(255, 0, 0);
break;
case 1:
dot.color[i] = RGB(0, 255, 0);
break;
case 2:
dot.color[i] = RGB(0, 0, 255);
break;
case 3:
dot.color[i] = RGB(0, 0, 0);
break;
}
}
//-----------------------------------------------------------------------//
if (!InitWindowsClass(hInstance))
return 1;
if (!InitWindows(hInstance, nCmdShow))
return 1;
while (GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
HPEN hPen;
PAINTSTRUCT ps;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
SetWindowOrgEx(hdc, -400, -250, NULL);//设置原点坐标
//-----------------------------画图---------------------------------------//
for (int k = 0; k < DOTNUM; ++k)
{
for (int i = j; i < DOTNUM; ++i)
{
hPen = CreatePen(PS_SOLID, 1, dot.color[i]);//颜色是终点坐标的颜色
SelectObject(hdc, hPen);
MoveToEx(hdc, dot.point[j].x, dot.point[j].y, NULL);//画笔放到第1个点
LineTo(hdc, dot.point[i].x, dot.point[i].y); //画向第2个点
DeleteObject(hPen);
Sleep(10);
}
j++;
}
//-------------------------------两种画法---------------------------------//
//for (int i = j; i < DOTNUM; ++i)
//{
// hPen = CreatePen(PS_SOLID, 1, dot.color[i]);//颜色是终点坐标的颜色
// SelectObject(hdc, hPen);
// MoveToEx(hdc, dot.point[j].x, dot.point[j].y, NULL);
// LineTo(hdc, dot.point[i].x, dot.point[i].y);
// DeleteObject(hPen);
// Sleep(100);
// InvalidateRect(hWnd, NULL, TRUE);
//}
//j++;
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
BOOL InitWindowsClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbClsExtra = 0;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.cbWndExtra = 0;
wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wcex.hInstance = hInstance;
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
wcex.lpfnWndProc = WndProc;
wcex.lpszClassName = lpszClassName;
wcex.lpszMenuName = NULL;
wcex.style = 0;
return RegisterClassEx(&wcex);
}
BOOL InitWindows(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hWnd = CreateWindowEx(
WS_EX_OVERLAPPEDWINDOW,
lpszClassName,
sizeTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
结果图: