不使用 MFC,純 Win32 API + GDI 繪製一個持續旋轉的三葉風車動畫。展示 WM_PAINT、InvalidateRect、Sleep 簡易動畫迴圈、三角函數計算葉片座標、Pie 繪製扇形等基礎技術。
#include
#include
#include
#include
#define PI 3.1415926
int nNum = 0, nMaxNum = 20;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {
WNDCLASS wc = {0};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = _T("WindmillClass");
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
RegisterClass(&wc);
HWND hwnd = CreateWindow(_T("WindmillClass"), _T("旋轉的風車"),
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 600, 450, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
MSG msg;
while (GetMessage(&msg, hwnd, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
static HDC hdc;
static HBRUSH hBrush;
static HPEN hp;
PAINTSTRUCT ps;
int nCenterX, nCenterY;
double fAngle;
switch (uMsg) {
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
// 設定各向異性映射模式:邏輯座標 400x300 對應用戶區 600x450,原點置中
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, 400, 300, NULL);
SetViewportExtEx(hdc, 600, 450, NULL);
SetViewportOrgEx(hdc, 300, 200, NULL);
// 外圓
hp = CreatePen(PS_SOLID, 1, RGB(255,0,255));
SelectObject(hdc, hp);
Ellipse(hdc, -100, -100, 100, 100);
// 葉片 1 (紅)
hBrush = CreateSolidBrush(RGB(255,0,0));
SelectObject(hdc, hBrush);
fAngle = 2*PI/nMaxNum*nNum;
nCenterX = (int)(50*cos(fAngle));
nCenterY = (int)(50*sin(fAngle));
Pie(hdc, nCenterX-50, nCenterY-50, nCenterX+50, nCenterY+50,
(int)(nCenterX+50*cos(fAngle)), (int)(nCenterY+50*sin(fAngle)),
(int)(nCenterX+50*cos(fAngle+PI)), (int)(nCenterY+50*sin(fAngle+PI)));
// 葉片 2 (藍) - 相位差 120°
hBrush = CreateSolidBrush(RGB(0,0,255));
SelectObject(hdc, hBrush);
nCenterX = (int)(50*cos(fAngle+2*PI/3));
nCenterY = (int)(50*sin(fAngle+2*PI/3));
Pie(hdc, nCenterX-50, nCenterY-50, nCenterX+50, nCenterY+50,
(int)(nCenterX+50*cos(fAngle+2*PI/3)), (int)(nCenterY+50*sin(fAngle+2*PI/3)),
(int)(nCenterX+50*cos(fAngle+PI+2*PI/3)), (int)(nCenterY+50*sin(fAngle+PI+2*PI/3)));
// 葉片 3 (青) - 相位差 240°
hBrush = CreateSolidBrush(RGB(0,255,255));
SelectObject(hdc, hBrush);
nCenterX = (int)(50*cos(fAngle+4*PI/3));
nCenterY = (int)(50*sin(fAngle+4*PI/3));
Pie(hdc, nCenterX-50, nCenterY-50, nCenterX+50, nCenterY+50,
(int)(nCenterX+50*cos(fAngle+4*PI/3)), (int)(nCenterY+50*sin(fAngle+4*PI/3)),
(int)(nCenterX+50*cos(fAngle+PI+4*PI/3)), (int)(nCenterY+50*sin(fAngle+PI+4*PI/3)));
nNum++;
Sleep(100); // 簡易幀率控制 (10 FPS)
InvalidateRect(hwnd, NULL, TRUE); // 觸發下一幀
EndPaint(hwnd, &ps);
return 0;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
MM_ANISOTROPIC 映射模式:邏輯座標系固定 (400x300),自動適應視窗大小變化SetViewportOrgEx 將原點移至視窗中心,繪圖座標以中心為基準Pie 函數繪製扇形:由中心點、外接矩形、起始/結束射線決定sin/cos 計算葉片中心點軌跡 (半徑 50)Sleep(100) + InvalidateRect 形成簡易動畫迴圈 (生產環境建議用 SetTimer 或獨立渲染執行緒)CreateCompatibleDC + BitBlt) 消除閃爍SetTimer / WM_TIMER 替代 Sleep,不阻塞訊息迴圈Graphics, Matrix 旋轉) 簡化座標變換