1、为了便于管理,创建一个新类用于执行绘图的相关操作,另外用list容器保存每次的绘图信息,最后添加一个保存和读取文件的内容。
头文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#pragma once
class CGraph
{
public:
CGraph(void);
CGraph(int nType, POINT ptBegin, POINT ptEnd);
~CGraph(void);
int m_nType;
// 绘图类型
POINT m_ptBegin;
// 起始点
POINT m_ptEnd;
// 终止点
// 绘图
int DrawGraph(HDC hdc);
};
|
CPP文件(重载了类的构造函数):
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
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#include "StdAfx.h"
#include "Graph.h"
CGraph::CGraph(void)
{
}
CGraph::CGraph(int nType, POINT ptBegin, POINT ptEnd)
:m_nType(nType)
,m_ptBegin(ptBegin)
,m_ptEnd(ptEnd)
{
}
CGraph::~CGraph(void)
{
}
int CGraph::DrawGraph(HDC hdc)
{
switch
(m_nType)
{
case
TYPE_LINE:
MoveToEx(hdc, m_ptBegin.x, m_ptBegin.y, NULL);
LineTo(hdc, m_ptEnd.x, m_ptEnd.y);
break
;
case
TYPE_RECT:
Rectangle(hdc, m_ptBegin.x, m_ptBegin.y, m_ptEnd.x, m_ptEnd.y);
break
;
case
TYPE_ELLIPSE:
Ellipse(hdc, m_ptBegin.x, m_ptBegin.y, m_ptEnd.x, m_ptEnd.y);
break
;
default
:
break
;
}
return
0;
}
|
另外,还定义了一个绘图类型的枚举:
1
2
3
4
5
6
7
|
// 绘图类型
enum
{
TYPE_LINE,
TYPE_RECT,
TYPE_ELLIPSE
};
|
2、首先实现list容器保存绘图信息的功能:
1
2
|
#include <list>
using namespace std;
|
1
2
|
list <CGraph*> g_data;
list <CGraph*>::iterator it;
// 迭代器
|
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
static POINT ptBegin;
static POINT ptEnd;
static int nType = TYPE_LINE;
CGraph *pGraph = 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);
pGraph =
new
CGraph(nType, ptBegin, ptEnd);
if
(pGraph != NULL)
{
g_data.push_back(pGraph);
}
InvalidateRect(hWnd, NULL,
true
);
break
;
case
WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意绘图代码...
pGraph = NULL;
for
(it = g_data.begin(); it != g_data.end(); it++)
{
pGraph = *it;
if
(pGraph != NULL)
{
pGraph->DrawGraph(hdc);
}
}
EndPaint(hWnd, &ps);
break
;
省略……
}
|
3、接着,添加文件操作,将list中的数据保存到一个txt文本文件中:
(1)定义两个函数,分别用于保存和读取数据:
1
2
|
BOOL SaveDrawInfo();
// 保存绘图信息
BOOL OpenDrawInfo();
// 读取绘图信息
|
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
27
28
29
30
31
32
33
34
35
|
BOOL SaveDrawInfo()
{
ofstream ofs;
for
(it = g_data.begin(); it != g_data.end(); it++)
{
ofs.write((const char*)*it, sizeof(CGraph));
}
ofs.close();
return
TRUE;
}
BOOL OpenDrawInfo()
{
DestroyList();
g_data.clear();
ifstream ifs;
while
(!ifs.eof())
{
CGraph *pGraph =
new
CGraph;
ifs.read((char*)pGraph, sizeof(CGraph));
g_data.push_back(pGraph);
}
ifs.close();
fstream fs;
return
TRUE;
}
|
(3)因为使用了C++中的文件操作函数,所以需要包含相应的头文件:
1
|
#include <fstream>
|
(4)为这两个函数添加两个菜单,用于确定让 用户选择何时保存与读取:
(5)在两个菜单的响应消息中调用保存和读取函数(通过菜单的ID):
具体在窗口的回调函数WinProc中,WM_COMMAND后面:
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
27
28
29
30
31
32
33
34
35
36
|
case
WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择:
switch
(wmId)
{
// 绘图类型(3种)
case
ID_TYPE_LINE:
nType = TYPE_LINE;
break
;
case
ID_TYPE_RECT:
nType =TYPE_RECT;
break
;
case
ID_TYPE_ELLIPSE:
nType = TYPE_ELLIPSE;
break
;
// 保存 和 读取
case
ID_DATA_SAVE:
SaveDrawInfo();
break
;;
case
ID_DATE_READ:
OpenDrawInfo();
InvalidateRect(hWnd, NULL, TRUE);
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
;
|
4、最后,new的东西别忘了释放:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
BOOL DestroyList()
{
CGraph *pGraph = NULL;
for
(it = g_data.begin(); it != g_data.end(); it++)
{
pGraph = *it;
if
(pGraph != NULL)
{
delete
pGraph;
pGraph = NULL;
}
}
return
TRUE;
}
|
在WM_DESTROY中调用它:
1
2
3
4
|
case
WM_DESTROY:
DestroyList();
PostQuitMessage(0);
break
;
|
5、注意:new 和 delete配对使用,但是与list的clear函数无关,调用clear只是清除list中的数据,而new分配的空间并没有释放,而且由于list中存储的是每次new对象的指针,故delete之前不能clear,或者说:在list调用clear之前应该先delete(调用 DestroyList )。
6、运行截图:
此时,点击保存菜单,会在D盘下生成一个a.txt文件,记事本打开后是一串乱码:
这是正常的,因为我们保存的内容并不是字符集中的字符,记事本无法还原内容,关闭绘图程序后再打开点击读取菜单,你会发现上次的图形又被绘制出来了,说明绘图程序正确地处理了a.txt中的内容。当然,这个a.txt的后缀其实没什么意义,任意修改都行。
例如:我改成a.dgi
保存后生成文件:
7、源码:http://download.csdn.net/detail/wwkaven/7722917