Win32下绘图程序(二)保存绘图信息至文件

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();   // 读取绘图信息
(2)函数实现:

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;
     ofs.open( "D://a.txt" );
 
     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;
     ifs.open( "D://a.txt" );
 
     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


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值