我們今天繼續涂鴉,實踐證明,涂鴉是人生一大樂趣。
首先,我們寫一個程序骨架子,以便做實驗。
~~~
#include <Windows.h>
LRESULT CALLBACK MainWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(
HINSTANCE hThisApp,
HINSTANCE hPrevApp,
LPSTR lpsCmdln,
int iShow)
{
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = CreateSolidBrush(RGB(0,0,0));
// 默認光標類型為箭頭
wc.hCursor = LoadCursor(hThisApp, IDC_ARROW);
// 默認應用程序圖標
wc.hIcon = LoadIcon(hThisApp, IDI_APPLICATION);
wc.hInstance = hThisApp;
wc.lpfnWndProc = MainWinProc;
wc.lpszClassName = L"MyAppTest";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
// 注冊窗口類
RegisterClass(&wc);
// 創建窗口
HWND hwnd = CreateWindow(
L"MyAppTest",
L"繪畫課",
/* 使用 WS_VISIBLE 就不用調用ShowWindow了 */
WS_VISIBLE | WS_OVERLAPPEDWINDOW,
100,
45,
500,
380,
NULL,
NULL,
hThisApp,
NULL);
// 消息循環
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK MainWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
/*
待實現
*/
EndPaint(hwnd, &ps);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
~~~
### ?CreatePen函數
我們要進行素描畫創作,所以我們必須想清楚要使用什么樣的鋼筆,畫出什么樣的線條。故,畫圖之前得創建一支鋼筆,不然,巧婦難為無米之炊。
~~~
HPEN CreatePen(
int iStyle, //鋼筆的樣式,如虛線、實線
int cWidth, //線條寬度
COLORREF color //線條是啥顏色的
);
~~~
第一個參數指定線條的樣式,如
~~~
/* Pen Styles */
#define PS_SOLID 0
#define PS_DASH 1 /* ------- */
#define PS_DOT 2 /* ....... */
#define PS_DASHDOT 3 /* _._._._ */
#define PS_DASHDOTDOT 4 /* _.._.._ */
#define PS_NULL 5
#define PS_INSIDEFRAME 6
#define PS_USERSTYLE 7
#define PS_ALTERNATE 8
~~~
函數成功創建鋼筆后就會返回HPEN,H開頭的你就要知道它表示句柄。Pen也是系統資源,所以創建筆后系統要為它一個標識。
### SelectObject函數
上過美術課,你會知道,有了用于進行素描創作的鋼筆還不能動手干活,我們還需要有紙。接下來,調用SelectObject函數,把剛才創建的鋼筆與繪圖紙關聯,就等于把我們創建的繪圖資源放進DC工具箱中,
~~~
HGDIOBJ WINAPI SelectObject(
HDC hdc, //設備描述表的句柄
HGDIOBJ h //要放到DC中的資源的句柄
);
~~~
調用成功后,返回原先的資源句柄。
### MoveToEx和LineTo
MoveToEx是設置繪制的起點,下次繪圖將從這個點開始。它的最后一個參數將被設置為當前點,即Move后的坐標。LineTo從當前坐標開始,到指定坐標之間繪制一條線段。
~~~
// 創建鋼筆
HPEN pen = CreatePen(PS_DASH, 1, RGB(0,255,50));
// 把筆選到DC中
SelectObject(ps.hdc, pen);
// 設定線段的起點
MoveToEx(ps.hdc, 15, 25, NULL);
// 繪制線條
LineTo(ps.hdc, 65, 49);
LineTo(ps.hdc, 12, 120);
LineTo(ps.hdc, 250, 78);
LineTo(ps.hdc, 312, 185);
DeleteObject(pen);
~~~
記住,只要是我們創建的句柄,用完后調用DeleteObject函數將其銷毀。

### PolyBezier函數和PolyBezierTo函數
兩個函數都是用來繪制貝塞爾曲線的,不同的是,PolyBezier函數包含指定的起點和終點,PolyBezierTo是從當前點開始繪制貝塞爾曲線。
~~~
// 繪制貝塞爾曲線
pen = CreatePen(PS_DOT, 1, RGB(0,3,255));
SelectObject(ps.hdc, pen);
POINT* pts = new POINT[4];
pts[0].x = 421;
pts[0].y = 16;
pts[1].x = 7;
pts[1].y = 197;
pts[2].x = 480;
pts[2].y = 320;
pts[3].x = 30;
pts[3].y = 350;
PolyBezier(ps.hdc, pts, 4);
delete [] pts;
// 第二段貝塞爾曲線
POINT* pts2 = new POINT[3];
pts2[0].x = 176;
pts2[0].y = 84;
pts2[1].x = 17;
pts2[1].y = 247;
pts2[2].x = 400;
pts2[2].y = 490;
// 移動當前點
MoveToEx(ps.hdc, 395, 270, NULL);
PolyBezierTo(ps.hdc, pts2, 3);
delete [] pts2;
~~~

### ?
### ?PolyPolyline繪制復合線條
PolyPolyline函數可以繪制多段復合線條。它的聲明如下:
~~~
BOOL PolyPolyline(
HDC hdc,
const POINT *lppt,
const DWORD *lpdwPolyPoints,
DWORD cCount
);
~~~
lppt參數指向一個POINT的數組,它包含繪制復合線條所需的所有點;lpdwPolyPoints指向一個數組,這個數字數組指明如何分配點數組。
例如,lppt有7個點,我計劃,前2個點繪制第一條線,接著3個點繪制第二條線,最后2個點繪制第三條線,這樣一來,lpdwPolyPolyPoints得值應為:
{??2, 3, 2?}
nCount里包含lpdwPolyPolyPoints中的數量,我們上面的例子是3.
由于兩點決定一條線段,因此,lpdwPolyPolyPoints里面的值記得要>=2。
~~~
// 復雜圖形
pen = CreatePen(PS_DASHDOTDOT, 1, RGB(80,20,160));
SelectObject(ps.hdc, pen);
POINT plpts[10] =
{
{47,3}, {11,46}, {28,199}, {203,305}, {94,22},
{402,377}, {21,45}, {237,7}, {300,398}, {175,25}
};
DWORD arr[4] = { 2, 3, 3, 2};
PolyPolyline(ps.hdc, &plpts[0], &arr[0], 4);
~~~
上面的代碼將畫出以下圖形。

完整的代碼清單如下:
~~~
#include <Windows.h>
LRESULT CALLBACK MainWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(
HINSTANCE hThisApp,
HINSTANCE hPrevApp,
LPSTR lpsCmdln,
int iShow)
{
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = CreateSolidBrush(RGB(0,0,0));
// 默認光標類型為箭頭
wc.hCursor = LoadCursor(hThisApp, IDC_ARROW);
// 默認應用程序圖標
wc.hIcon = LoadIcon(hThisApp, IDI_APPLICATION);
wc.hInstance = hThisApp;
wc.lpfnWndProc = MainWinProc;
wc.lpszClassName = L"MyAppTest";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
// 注冊窗口類
RegisterClass(&wc);
// 創建窗口
HWND hwnd = CreateWindow(
L"MyAppTest",
L"繪畫課",
/* 使用 WS_VISIBLE 就不用調用ShowWindow了 */
WS_VISIBLE | WS_OVERLAPPEDWINDOW,
100,
45,
500,
380,
NULL,
NULL,
hThisApp,
NULL);
// 消息循環
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK MainWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
// 創建鋼筆
HPEN pen = CreatePen(PS_DASH, 1, RGB(0,255,50));
// 把筆選到DC中
SelectObject(ps.hdc, pen);
// 設定線段的起點
MoveToEx(ps.hdc, 15, 25, NULL);
// 繪制線條
LineTo(ps.hdc, 65, 49);
LineTo(ps.hdc, 12, 120);
LineTo(ps.hdc, 250, 78);
LineTo(ps.hdc, 312, 185);
// 繪制貝塞爾曲線
pen = CreatePen(PS_DOT, 1, RGB(0,3,255));
SelectObject(ps.hdc, pen);
POINT* pts = new POINT[4];
pts[0].x = 421;
pts[0].y = 16;
pts[1].x = 7;
pts[1].y = 197;
pts[2].x = 480;
pts[2].y = 320;
pts[3].x = 30;
pts[3].y = 350;
PolyBezier(ps.hdc, pts, 4);
delete [] pts;
// 第二段貝塞爾曲線
POINT* pts2 = new POINT[3];
pts2[0].x = 176;
pts2[0].y = 84;
pts2[1].x = 17;
pts2[1].y = 247;
pts2[2].x = 400;
pts2[2].y = 490;
// 移動當前點
MoveToEx(ps.hdc, 395, 270, NULL);
PolyBezierTo(ps.hdc, pts2, 3);
delete [] pts2;
// 復雜圖形
pen = CreatePen(PS_DASHDOTDOT, 1, RGB(80,20,160));
SelectObject(ps.hdc, pen);
POINT plpts[10] =
{
{47,3}, {11,46}, {28,199}, {203,305}, {94,22},
{402,377}, {21,45}, {237,7}, {300,398}, {175,25}
};
DWORD arr[4] = { 2, 3, 3, 2};
PolyPolyline(ps.hdc, &plpts[0], &arr[0], 4);
DeleteObject(pen);
EndPaint(hwnd, &ps);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
~~~
- 前言
- (1):關于C++的幾個要點
- (2):完整的開發流程
- (3):窗口的重繪
- (4):創建菜單
- (5):具有單選標記的菜單
- (6):創建右鍵菜單
- (7):多邊形窗口
- (8):繪圖(A)
- (9):繪圖(B)
- (10):繪圖(C)
- (11):使用控件——先來耍一下按鈕
- (12):使用控件——單選按鈕
- (13):握手對話框
- (14):用對話框作為主窗口
- (15):ListView控件
- (16):ListView的多個視圖
- (17):啟動和結束進程
- (18):使用對話框的兩個技巧
- (19):瀏覽和打開文件
- (20):瀏覽文件夾
- (21):復制&amp;粘貼&amp;剪貼板操作
- (22):抓取屏幕
- (23):漸變顏色填充
- (24):計時器
- (25):監視剪貼板