1、实现效果:
2、创建一个Win32工程:
3、介绍几个绘图的函数:
绘直线用到的函数:
1
2
3
4
5
6
7
8
9
|
MoveToEx
The MoveToEx
function
updates the current position
to the specified point and optionally returns the previous position.
BOOL MoveToEx(
HDC hdc,
// handle to device context
int X,
// x-coordinate of new current position
int Y,
// y-coordinate of new current position
LPPOINT lpPoint
// old current position
);
|
1
2
3
4
5
6
7
8
9
|
LineTo
The LineTo
function
draws a line from the current position up to,
but not including, the specified point.
BOOL LineTo(
HDC hdc,
// device context handle
int nXEnd,
// x-coordinate of ending point
int nYEnd
// y-coordinate of ending point
);
|
|
绘制矩形:
1
2
3
4
5
6
7
8
9
10
11
|
Rectangle
The Rectangle
function
draws a rectangle.
The rectangle is outlined by using the current pen and filled by using the current brush.
BOOL Rectangle(
HDC hdc,
// handle to DC
int nLeftRect,
// x-coord of upper-left corner of rectangle
int nTopRect,
// y-coord of upper-left corner of rectangle
int nRightRect,
// x-coord of lower-right corner of rectangle
int nBottomRect
// y-coord of lower-right corner of rectangle
);
|
|
绘制椭圆:
1
2
3
4
5
6
7
8
9
10
11
12
|
Ellipse
The Ellipse
function
draws an ellipse.
The center of the ellipse is the center of the specified bounding rectangle.
The ellipse is outlined by using the current pen and is filled by using the current brush.
BOOL Ellipse(
HDC hdc,
// handle to DC
int nLeftRect,
// x-coord of upper-left corner of rectangle
int nTopRect,
// y-coord of upper-left corner of rectangle
int nRightRect,
// x-coord of lower-right corner of rectangle
int nBottomRect
// y-coord of lower-right corner of rectangle
);
|
绘制图像需要两个点,即绘图的起始点和终止点,可以由鼠标左键按下时的坐标作为起始点,鼠标左键释放时的坐标作为终止点。那么,就要响应两个消息:WM_LBUTTONDOWN和WM_LBUTTONUP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
WM_LBUTTONDOWN Notification
--------------------------------------------------------------------------------
The WM_LBUTTONDOWN message is posted when the user
presses the left mouse button
while
the cursor is
in
the client area of a window.
If the mouse is not captured, the message is posted to the window beneath the cursor.
Otherwise, the message is posted to the window that has captured the mouse.
A window receives
this
message through its WindowProc
function
.
Syntax
WM_LBUTTONDOWN
WPARAM wParam
LPARAM lParam;
Parameters
wParam
Indicates whether various virtual keys are down.
lParam
The low-order word specifies the x-coordinate of the cursor.
The coordinate is relative to the upper-left corner of the client area.
The high-order word specifies the y-coordinate of the cursor.
The coordinate is relative to the upper-left corner of the client area.
|
重点是最后四句,它说:
lParam的低位(low-order)是鼠标光标的x坐标(x-coordinate),
lParam的高位(high-order)是鼠标光标的y坐标(y-coordinate)。
这样就构成了一个点(POINT)。
同理:消息WM_LBUTTONUP也是如此。
另外,参数还需要一个HDC,可以通过以下函数获得:
1
2
3
4
5
6
7
8
9
10
11
|
GetDC
The GetDC
function
retrieves a handle to a display device context (DC)
for
the client area of a specified window or
for
the entire screen.
You can use the returned handle
in
subsequent GDI functions to draw
in
the DC.
The GetDCEx
function
is an extension to GetDC,
which gives an application more control over how and whether clipping occurs
in
the client area.
HDC GetDC(
HWND hWnd
// handle to window
);
|
|
注意:GetDC用完后必须用ReleaseDC释放
1
2
3
4
|
After painting
with
a common DC, the ReleaseDC
function
must be called to release the DC.
Class and private DCs
do
not have to be released.
ReleaseDC must be called from the same thread that called GetDC.
The number of DCs is limited only by available memory.
|
4、在窗口回调函数中进行相应的操作:
LRESULT
CALLBACK
WndProc(
HWND
hWnd,
UINT
message,
WPARAM
wParam,
LPARAM
lParam)
{
// 绘图类型
enum
{
TYPE_LINE
,
TYPE_RECT
,
TYPE_ELLIPSE
};
int wmId, wmEvent;
PAINTSTRUCT
ps;
HDC
hdc;
static
POINT
ptBegin;
static
POINT
ptEnd;
static int nTypy =
TYPE_LINE
;
switch (message)
{
case
WM_LBUTTONDOWN
:
ptBegin.x =
LOWORD
(lParam);
ptBegin.y =
HIWORD
(lParam);
break
;
case
WM_LBUTTONUP
:
ptEnd.x =
LOWORD
(lParam);
ptEnd.y =
HIWORD
(lParam);
hdc = GetDC(hWnd);
switch (nTypy)
{
case
TYPE_LINE
:
MoveToEx(hdc, ptBegin.x, ptBegin.y,
NULL
);
LineTo(hdc, ptEnd.x, ptEnd.y);
break
;
case
TYPE_RECT
:
Rectangle(hdc, ptBegin.x, ptBegin.y, ptEnd.x, ptEnd.y);
break
;
case
TYPE_ELLIPSE
:
Ellipse(hdc, ptBegin.x, ptBegin.y, ptEnd.x, ptEnd.y);
break
;
default:
break
;
}
ReleaseDC(hWnd, hdc);
break
;
case
WM_COMMAND
:
wmId =
LOWORD
(wParam);
wmEvent =
HIWORD
(wParam);
// 分析菜单选择:
switch (wmId)
{
case
ID_TYPE_LINE
:
nTypy =
TYPE_LINE
;
break
;
case
ID_TYPE_RECT
:
nTypy =
TYPE_RECT
;
break
;
case
ID_TYPE_ELLIPSE
:
nTypy =
TYPE_ELLIPSE
;
break
;
case
IDM_ABOUT
:
DialogBox(hInst,
MAKEINTRESOURCE
(
IDD_ABOUTBOX
), hWnd, About);
break
;
case
IDM_EXIT
:
DestroyWindow(hWnd);
break
;
default:
return
DefWindowProc(hWnd, message, wParam, lParam);
}
break
;
case
WM_PAINT
:
hdc = BeginPaint(hWnd, &ps);
//
TODO
: 在此添加任意绘图代码...
TextOut(hdc,
0
,
0
,
_T
(
"Helllo World!"
), _tcslen(
_T
(
"Helllo World!"
)));
EndPaint(hWnd, &ps);
break
;
case
WM_DESTROY
:
PostQuitMessage(
0
);
break
;
default:
return
DefWindowProc(hWnd, message, wParam, lParam);
}
return
0
;
}
5、防止窗口刷新后绘制的图像丢失(用链表存储每次绘图的信息):
LRESULT
CALLBACK
WndProc(
HWND
hWnd,
UINT
message,
WPARAM
wParam,
LPARAM
lParam)
{
// 绘图类型
enum
{
TYPE_LINE
,
TYPE_RECT
,
TYPE_ELLIPSE
};
typedef struct tagPaintInfo
{
POINT
ptBegin;
POINT
ptEnd;
int nType;
tagPaintInfo *pNext;
}PInfo;
int wmId, wmEvent;
PAINTSTRUCT
ps;
HDC
hdc;
static
POINT
ptBegin;
static
POINT
ptEnd;
static int nTypy =
TYPE_LINE
;
static bool bFlag =
true
;
static PInfo *pHead =
NULL
;
static PInfo *pEnd =
NULL
;
static PInfo *pNew =
NULL
;
PInfo *pTemp =
NULL
;
switch (message)
{
case
WM_LBUTTONDOWN
:
ptBegin.x =
LOWORD
(lParam);
ptBegin.y =
HIWORD
(lParam);
break
;
case
WM_LBUTTONUP
:
ptEnd.x =
LOWORD
(lParam);
ptEnd.y =
HIWORD
(lParam);
hdc = GetDC(hWnd);
switch (nTypy)
{
case
TYPE_LINE
:
MoveToEx(hdc, ptBegin.x, ptBegin.y,
NULL
);
LineTo(hdc, ptEnd.x, ptEnd.y);
break
;
case
TYPE_RECT
:
Rectangle(hdc, ptBegin.x, ptBegin.y, ptEnd.x, ptEnd.y);
break
;
case
TYPE_ELLIPSE
:
Ellipse(hdc, ptBegin.x, ptBegin.y, ptEnd.x, ptEnd.y);
break
;
default:
break
;
}
if
(bFlag)
{
pNew = (PInfo *)malloc(sizeof(PInfo));
pNew->ptBegin = ptBegin;
pNew->ptEnd = ptEnd;
pNew->nType = nTypy;
pNew->pNext =
NULL
;
pHead = pNew; // 因为是第一个节点,所以新建的节点即是头结点
pEnd = pHead; // 因为是第一个节点,所以头结点即是尾节点
bFlag =
false
;
}
else
{
// 创建一个新节点
pNew = (PInfo *)malloc(sizeof(PInfo));
pNew->ptBegin = ptBegin;
pNew->ptEnd = ptEnd;
pNew->nType = nTypy;
pNew->pNext =
NULL
;
pEnd->pNext = pNew; // 将创建的新节点 连接到 链表末尾
pEnd = pNew; // 链表的尾节点改变(变为新节点)
}
break
;
case
WM_COMMAND
:
wmId =
LOWORD
(wParam);
wmEvent =
HIWORD
(wParam);
// 分析菜单选择:
switch (wmId)
{
case
ID_TYPE_LINE
:
nTypy =
TYPE_LINE
;
break
;
case
ID_TYPE_RECT
:
nTypy =
TYPE_RECT
;
break
;
case
ID_TYPE_ELLIPSE
:
nTypy =
TYPE_ELLIPSE
;
break
;
case
IDM_ABOUT
:
DialogBox(hInst,
MAKEINTRESOURCE
(
IDD_ABOUTBOX
), hWnd, About);
break
;
case
IDM_EXIT
:
DestroyWindow(hWnd);
break
;
default:
return
DefWindowProc(hWnd, message, wParam, lParam);
}
break
;
case
WM_PAINT
:
hdc = BeginPaint(hWnd, &ps);
//
TODO
: 在此添加任意绘图代码...
TextOut(hdc,
0
,
0
,
_T
(
"Helllo World!"
), _tcslen(
_T
(
"Helllo World!"
)));
pTemp = pHead;
while
(pTemp)
{
ptBegin = pTemp->ptBegin;
ptEnd = pTemp->ptEnd;
switch (pTemp->nType)
{
case
TYPE_LINE
:
MoveToEx(hdc, ptBegin.x, ptBegin.y,
NULL
);
LineTo(hdc, ptEnd.x, ptEnd.y);
break
;
case
TYPE_RECT
:
Rectangle(hdc, ptBegin.x, ptBegin.y, ptEnd.x, ptEnd.y);
break
;
case
TYPE_ELLIPSE
:
Ellipse(hdc, ptBegin.x, ptBegin.y, ptEnd.x, ptEnd.y);
break
;
default:
break
;
}
pTemp = pTemp->pNext;
}
EndPaint(hWnd, &ps);
break
;
case
WM_DESTROY
:
while
(pHead)
{
pTemp = pHead->pNext;
free(pHead);
pHead = pTemp;
}
PostQuitMessage(
0
);
break
;
default:
return
DefWindowProc(hWnd, message, wParam, lParam);
}
return
0
;
}
|