VC++
设计
领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计
简单图形编辑器
目录 一、项目设计目标和要求 ............................................. 1 1.1 设计目标 .................................................... 1
1.2 设计要求 .................................................... 1
1.2.1 基础图元绘制........................................... 1
1.2.2 编辑................................................... 1
1.2.3 保存................................................... 1
1.2.4 读取................................................... 1
1.2.5 界面友好的要求......................................... 2 二、项目概述 ....................................................... 2
2.1 项目开发方法简述 ............................................ 2 2.2 项目开发环境简述 ............................................ 2 2.3 相关基础知识介绍 ............................................ 3
2.3.1 Windows应用程序的消息处理
机制
综治信访维稳工作机制反恐怖工作机制企业员工晋升机制公司员工晋升机制员工晋升机制图
......................... 3
2.3.2 API.................................................... 3
2.3.3 MFC.................................................... 3
2.3.4 MFC消息映射机制 ....................................... 4
2.3.5 RGB.................................................... 4
2.3.6 图形处理密切相关类..................................... 5 三、程序设计过程和
分析
定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析
............................................. 6
3.1设计模块 ................................................. 6
3.2图元绘制方法 ............................................. 6
3.3 图元绘制过程............................................. 6
3.4 图元重绘方法............................................. 9
3.5 图元保存方法............................................ 11
3.6 图元编辑方法............................................ 12
3.7 文档序列化.............................................. 13
3.8 利用可串行化类Serialize函数保存和加载对象.............. 15
3.9 文档对象数据的销毁...................................... 19 四、主要功能描述 .................................................. 19
五、
总结
初级经济法重点总结下载党员个人总结TXt高中句型全总结.doc高中句型全总结.doc理论力学知识点总结pdf
.......................................................... 21
一、项目设计目标和要求
1.1 设计目标
设计一个简单的图形编辑器,该编辑器提供一些基本的标准图元库,可以用
这些标准图元很方便的生成目标图形。正如Windows 的画图程序(图1.1)就是一
个应用非常广泛的图形编辑器。使用VC开发平台,MFC框架实现一个画图程序,尽可能多的实现Windows自带的画图功能,并扩展其功能。
图1.1 画图
1.2 设计要求
1.2.1 基础图元绘制
要求基本图元包括点、直线、椭圆、矩形。绘制时先选择所绘制图元类型,
然后用鼠标完成绘制。
1.2.2 编辑
要求针对每个图元,可对其进行选中、删除操作,并且都可编辑其基本属性,
如颜色、线宽等。同时编辑时必须以选中状态才可进行编辑。
1.2.3 保存
要求能够将所绘制图元成功保存进文件。
1.2.4 读取
第 1 页 共 21 页
要求能够将所保存文件成功读取,并显示出来,并且实现对所读取图元的编
辑功能与再保存功能。
1.2.5 界面友好的要求:
, 有画点、直线、矩形、椭圆的工具箱。
, 有颜色选择工具箱。
, 对于当前选中的绘图工具,以“下沉”的形式显示。 , 在鼠标移向一个工具不动时,有工具的功能提示。 , 在菜单上有当前选中的菜单项标识(即前面有小钩)
二、项目概述
2.1 项目开发方法简述
采用面向对象方法,针对不同的图元,封装到不同的类中,但同时必须
继承同一个基类。绘制时,采用消息响应方法来完成图元的绘制。保存时,
采用索引的形式,分别保存每个对象的结构数据与点坐标数据到不同的文件
中。
2.2 项目开发环境简述
本程序采用编程语言C++语言实现的,使用Visual C++ 6.0 MFC可视化
开发环境。
C++语言是一种计算机程序设计语言。C++语言是在C语言上扩充了面向对象机制而形成的一种面向对象程序设计语言它除了继承C语言的全部优点和功能外,还支持面向对象程序设计。与C语言相比的优点主要体现在封装
性、继承性、和多态性。封装性把数据与操作数据的函数组织在一起,不仅
使程序结构更加紧凑,并且提高了类内数据的安全性;继承性增加了软件的
可扩充性及代码的重用性;多态性使设计人员设计程序时可以对问
题
快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题
进行更
好的抽象,有利于代码的维护和重用。C++语言具有绘图能力强,可移植性,
并具备很强的数据处理能力,因此适于编写绘图软件。
Visual C++是一个功能强大的可视化软件开发工具. Visual C++6.0不
仅是一个C++编译器,而且是一个基于Windows操作系统的可视化集成开发环境。
第 2 页 共 21 页
2.3 相关基础知识介绍
下面主要介绍与本项目相关联的概念、运行机制、原理、技术信息以及
使用最频繁的、与图形处理密切相关的组件及其属性和方法。 2.3.1 Windows应用程序的消息处理机制
操作系统接收到应用程序的窗口消息,将窗口消息投递到应用程序的消
息队列中。应用程序在消息循环中调用GetMessage函数从消息队列中取出一
条一条的消息。取出消息后,应该程序可以对消息进行一些预处理,例如,
放弃对某些消息的响应,或者调用TranslateMessage产生新的消息。应用程序调用DispatchMessage,将消息回传给操作系统。消息是由MSG结构体对象来表示的,其中就包含了接收消息的窗口的句柄。系统利用WNDCLASS结构体的lpfnWndProc成品保存的窗口过程函数的指针调用窗口过程,对消息进
行处理(即,系统给应用程序发送了消息)。所谓“发送信息”,实际上是操
作系统调用程序中一个专门负责处理消息的函数,这个函数称为窗口过程。
应用程序
窗口过程 操作系统 消息队列
In/Out设备
图2.1 Windows应用程序的消息处理机制 2.3.2 API
应用程序是以函数调用的方式来通知操作系统执行相应的功能的。操作
系统所能够完成的每一个特殊功能通常都有一个函数与其对应,也就是说,
操作系统把它所能够完成的功能以函数的形式提供给应用程序使用,应用程
序对这些函数的调用就叫做系统调用,这些函数的集合就是Windows操作系统提供给应用程序编程的接口(Application Programming Interface),简称Windows API。
2.3.3 MFC
第 3 页 共 21 页
MFC(Microsoft Foundation Class,微软基础类库)是微软为了简化程序员的开发工作所开发的一套C++类的集合,是一套面向对象的函数库,以
类的方式提供给用户使用。利用这些类,可以有效地帮助程序员完成Windows
应用程序的开发。
2.3.4 MFC消息映射机制
MFC消息映射机制的具体实现方法是:在每个能接收和处理消息的类中,
定义一个消息和消息函数静态对照表,即消息映射。在消息映射表中,消息
与对应的消息处理函数指针是成对出现的。某个类能处理的所有消息及其对
应的消息处理函数的地址都列在这个类所对应的静态表中。当有消息需要处
理时,程序只要搜索该消息静态表,查看表中是否含有该消息,义可知道该
类能否处理此消息。如果能处理该消息,则同样依照静态表能很很容易找到
并调用对应的消息处理函数。
AfxWndProc
AfxCallWndProc
WindowProc
OnWndMsg
OnCommand OnNotify
OnCmdMsg
图2.2 MFC消息映射机制 2.3.5 RGB
在计算机图形处理软件中,通常颜色是根据红、绿、蓝三种颜色的饱和
度来定义的,这种模型称为RGB模型。任何颜色都是红、绿、蓝三种基本色
的不同组合组成,因此每种颜色都可以用红、绿、蓝基本色来表示。Red、Green、
Blue用来表示基本色构成的三个分量,他们的取值为0-255,最小值表示没
有颜色,最大值255表示最高的饱和度。RGB即是代表红、绿、蓝三个通道
第 4 页 共 21 页
的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最
广的颜色系统之一。
2.3.6 图形处理密切相关类
1) CPen
CPen封装了Windows图形设备接口(GDI)的画笔功能。在用绘图的时候,
需要首先设置画笔的属性。对每一个画笔均可以选择不同的宽度,颜色,线
型等等。
2) CBrush
CBrush类封装了Windows图形设备接口(GDI)的画刷的API函数,包括画刷的实颜色、阴影、或模式。要使用CBrush,先用构造函数构造一个
CBrush对象,然后为需要用画刷的成员函籽传递一个指针或引用。
3) CDC
CDC类支持设备描述表,提供Windows API函数。CDC对象提供用于设备描述表如打印机或显示器的成员函数。CDC类提供一个包含Win32 API的成员函数的数组,它支持所有的设备描述表的操作,如使用各种绘画工具、GDI画刷和字体对象选择、对颜色和调色板的操作等,以及拥有本文中提到的画
线和画简单形状如多边形、矩形、椭圆的功能。
, 绘制直线
绘制直线涉及到两个方法:MoveTo和LineTo。MoveTo(int startx,int starty)的任务是设置当前画笔的位置到(startx,starty),而不进行任何绘图工作。然后可以调用LineTo(int endx,int endy)来画直线。它从当前画笔的位置画一条直线到点(endx,endy),并将当前的画笔位置改变为
(endx,endy)。
, 绘制椭圆
原型:BOOL Ellipse(int x1,int y1,int x2,int y2);
用途:画一个椭圆。其中心为限定矩形的中心。该限定矩形不包括右边
和底部的坐标。用当前画刷填充它的内部区域,并用当前画笔画此椭圆。
, 绘制矩形
原型:BOOL Rectangle(int x1, int y1, int x2, int y2);
第 5 页 共 21 页
用途:用当前画笔画一个矩形,并用当前画刷填充该矩形内部。
三、程序设计过程和分析
3.1设计模块
用户
基本图元绘制 基本图元的编辑 保存与读取 点直圆矩图图修文文的线的形元元改件件绘的绘的选删属保读制 中 除 性 存 取 绘制 绘
制 制 图3.1 基本模块图
3.2图元绘制方法
直线的绘制:确定两点坐标后,开始绘制。方法为调用MoveTo,LineTo
函数。
椭圆的绘制:确定椭圆心坐标后,开始绘制。方法为调用Ellipse函数。 矩形的绘制:确定矩形坐标后,开始绘制。方法为调用Rectangle函数。 文字的编写:捕获鼠标点击处,添加要输入的文字。方法为调用Onchar
函数。
图元绘制的效果图
图3.2图元绘制的效果图
3.3 图元绘制过程
第 6 页 共 21 页
采用消息响应方式,先选择一种图元类型后,由鼠标负责在视图窗口
中确定每个图元的点坐标位置,然后完成图元绘制,并自动存储到内存。主要
消息事件为WM_LBUTTONDOWN,WM_MOUSEMOVE,WM_RBUTTONDOWN。当选择一种图
元类型后,在客户区点击左键后,判断图元类型,?若为点,则完成绘制与存
储。?若为直线,则开始响应WM_MOUSEMOVE事件,绘制鼠标移动期间直线,
当再次点击鼠标左键完成绘制与存储。?椭圆,则开始响应WM_MOUSEMOVE事
件,绘制鼠标移动期间的动态椭圆,当再次点击左键后,完成绘制与存储?若
为矩形,则方法同椭圆,只是绘制时采用绘制椭圆的方法并存储。
实现代码如下:
void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
CPen pen(m_nLineStyle,m_nLineWidth,m_clr);
dc.SelectObject(&pen);
CBrush
*pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
dc.SelectObject(pBrush);
CBrush brush(m_brushclr);
dc.SelectObject(&brush);
switch(m_nDrawType)
{
case 1://画点
dc.SetPixel(point,m_clr);
break;
case 2://画直线
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
break;
case 3://画矩形
第 7 页 共 21 页
dc.FillRect(CRect(m_ptOrigin,point),&brush);
dc.Rectangle(CRect(m_ptOrigin,point));
break;
case 4://画椭圆
dc.Ellipse(CRect(m_ptOrigin,point));
break;
}
CGraph *pGraph= new CGraph(m_nDrawType,m_ptOrigin,point);
m_ptrArray.Add(pGraph);
CView::OnLButtonUp(nFlags, point);
}
void CGraphicView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) {// 文字编辑
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
CFont *pOldFont=dc.SelectObject(&m_font);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
CreateSolidCaret(tm.tmAveCharWidth/8,tm.tmHeight);
ShowCaret();
if(0x0d==nChar)
{ m_strline.Empty();
m_ptOrigin.y+=tm.tmHeight;
}
else if(0x08==nChar)
{
COLORREF clr=dc.SetTextColor(dc.GetBkColor());
dc.TextOut(m_ptOrigin.x,m_ptOrigin.y,m_strline);
m_strline=m_strline.Left(m_strline.GetLength()-1);
第 8 页 共 21 页
dc.SetTextColor(clr);
}
else
{m_strline+=nChar;
}
CSize sz=dc.GetTextExtent(m_strline);
CPoint pt;
pt.x=m_ptOrigin.x+sz.cx;
pt.y=m_ptOrigin.y;
SetCaretPos(pt);
dc.SetTextColor(m_fontclr);
dc.TextOut(m_ptOrigin.x,m_ptOrigin.y,m_strline);
dc.SelectObject (pOldFont);
CView::OnChar(nChar, nRepCnt, nFlags);
}
3.4 图元重绘方法
在运行这个简单图形编辑器Graphic程序,并利用相应菜单命令在窗口中绘制一些图形,当窗口尺寸发生变化时,将会发现窗口中绘制的图形都消失
了。这是因为当窗口尺寸发生变化时,引起窗口重绘,会发送WM_PAINT消息,
这时首先会擦除窗口的背景,然后再进行重绘操作,这样就把窗口中先前绘制
的图形擦除掉了。如果希望所绘制的图形始终在窗口中呈现出来,就是需要将
这些图形保存起来,然后当窗口尺寸发生变化引起窗口重绘时,将这些图形再
次在窗口中输出。当窗口重绘时,在CGraphicView类的OnDraw函数中,根据
每一个已保存的图形绘制类型,利用其起点和终点将该图形在窗口中重新输
出。由于这三个要素的数据类型不同,因而在C++中用结构体来保存不同类型的对象。本程序是用一个集合类:CPtrArray来存储多个对象。增加一个成员,可以调用Add方法,来增加一个void 指针所指向的对象;取得这个集合类中的某个元素,调用其GetAt 方法;获得这个集合类的元素数目,调用GetSize
方法。
第 9 页 共 21 页
在OnDraw函数中将保存的图形元素再次显示出来,具体代码如下:
void CGraphicView::OnDraw(CDC* pDC)
{
CGraphicDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CBrush
*pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
pDC->SelectObject(pBrush);
for(int i=0;i
m_nDrawType)
{
case 1:
pDC->SetPixel(((CGraph*)m_ptrArray.GetAt(i))->m_ptEnd,RGB(0,0,0);
break;
case 2:
pDC->MoveTo(((CGraph*)m_ptrArray.GetAt(i))->m_ptOrigin);
pDC->LineTo(((CGraph*)m_ptrArray.GetAt(i))->m_ptEnd);
break;
case 3:
pDC->Rectangle(CRect(((CGraph*)m_ptrArray.GetAt(i))->m_ptOrigin,
((CGraph*)m_ptrArray.GetAt(i))->m_ptEnd));
break;
case 4:
pDC->Ellipse(CRect(((CGraph*)m_ptrArray.GetAt(i))->m_ptOrigin,
((CGraph*)m_ptrArray.GetAt(i))->m_ptEnd));
break;
}
第 10 页 共 21 页
}
3.5 图元保存方法
在这里,我们采用数组的方式保存图元对象。声明为:
CTypedPtrArray m_ptrArray;因每个图元
继承自同一个基类,并且基类拥有图元的基本结构信息,因此存储时完全可按
基类来存储。
绘制时,若已完成图元坐标个数与位置的确定,则开始构造图元,并
存储,算法如下:
if(m_nDrawType == 1)//画点
{
Point.x=LOWORD (lParam);
Point.y=HIWORD (lParam);
CGraphicsEditSystemDoc * pDoc=GetDocument();
CClientDC *pDC=new CClientDC(this);
sGrapElemHeader geHdr;
sGrapElemFormat geFmt;
sPointPosition * psPstn;
psPstn=new sPointPosition[1];
CVNormPoint * VNPoint;
//初始化点图形的数据格式
geFmt=pDoc->beginElemFormat;
//初始化点图形的数据头
geHdr.GrapElemType=0;
geHdr.SaveType = 3;
pDoc->MaxNumElemId = pDoc->MaxNumElemId + 1;
geHdr.m_ID=pDoc->MaxNumElemId;
geHdr.m_PointsNumber=1;
psPstn[0].x = Point.x;
psPstn[0].y = Point.y;
第 11 页 共 21 页
//构造该点图形对象
VNPoint=new CVNormPoint(geFmt,geHdr,psPstn);
//绘制该点图形对象,Draw函数将根据该图元的格式成员函数,
//选择不同的方式绘制该对象
VNPoint->Draw(pDC);
//保存该点对象
pDoc->m_ptrArray.Add(VNPoint);}
3.6 图元编辑方法
首先选出中一个图元,并将该图元的状态显示为选中状态,然后才可进行
图元的编辑。
?若要判断是否点中图元,可循环所有对象依次判断是否点中,若点中则
该图元显示选中状态。代码如下:
for(int i=0;im_ptrArray.GetSize();i++)
{
if ((pDoc->m_ptrArray.GetAt(i)->Pointed(Point.x,Point.y,2) ==
true) && (pDoc->m_ptrArray.GetAt(i)->bSelected == false))
{
SelectedId=pDoc->m_ptrArray.GetAt(i)->geHeader.m_ID;
pDoc->m_ptrArray.GetAt(i)->bSelected = true;
CSeletedGE * sge=new CSeletedGE();
sge->Index=i;
if (select)
{
for (int j = 0;jSelectedGE.GetSize();j++)
pDoc->m_ptrArray.GetAt(pDoc->SelectedGE.GetAt(j)->Index)->bSelect
ed = false;
InvalidateRect(NULL,TRUE);
}
第 12 页 共 21 页
pDoc->SelectedGE.RemoveAll();
pDoc->SelectedGE.Add(sge);
}
else
{
pDoc->SelectedGE.Add(sge);
}
pDoc->m_ptrArray.GetAt(i)->Draw(pDC);
selected = true;
}
}
?若要删除图元对象,则在选中基础上获得其位置,然后在数组中将其删
除。方法为:
//在整个数据存储中删除该图形元素
pDoc->m_ptrArray.RemoveAt(selectnum);
?若要编辑图元属性,则在选中基础上打开图元属性对话框(如图3),将
选中图元的结构信息,调入对话框,完成修改后,将修改后结构信息重新存入
数组,完成编辑。
图3.3 图元属性设置 3.7 文档序列化
第 13 页 共 21 页
MFC提供了良好的序列化机制,只要在类定义时加入DECLARE_SERIAL宏,在类构造函数的实现前加入IMPLEMENT_SERIAL宏,然后实现Serialize方法即可。为了使用CArchive对象保存CGraph对象,首先要使CGraph类成为一个可串行化的类,再进行序列化的实现。本程序即使用该方法序列化: void CGraph::Serialize(CArchive& ar)
{
if(ar.IsStoring())
{
ar<>m_nDrawType>>m_ptOrigin>>m_ptEnd;
}
}
Debug追踪的时候会发现,容器类会自动序列化容器内的元素数量,并调用每个
元素的序列化方法序列化,所以还需要对每个图形元素实现序列化。 CGraph 类支持串行化了,然后为此类再增加一个图形绘制函数:Draw,从而将图形数据和图形绘制封装在一个类中,这也符合面向对象的思想。增加的Draw 函数的实现代码如下:
void CGraph::Draw(CDC *pDC)
{
CBrush
*pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
CBrush *pOldBrush=pDC->SelectObject(pBrush);
switch(m_nDrawType)
{
case 1:
pDC->SetPixel(m_ptEnd,RGB(0,0,0));
第 14 页 共 21 页
break;
case 2:
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(m_ptEnd);
break;
case 3:
pDC->Rectangle(CRect(m_ptOrigin,m_ptEnd));
break;
case 4:
pDC->Ellipse(CRect(m_ptOrigin,m_ptEnd));
break;
}
pDC->SelectObject(pOldBrush);
}
3.8 利用可串行化类Serialize函数保存和加载对象
文档序列化实现以后,程序的打开和保存功能就已经完成了。但是从序列化
方法可以看出,打开和保存的都是矢量图形,所以这里实现了一个导出为BMP
图像的方法,导出:
//保存文件对话框,选择导出路径
CFileDialog dlg(FALSE, "bmp","graphic.bmp");
if(dlg.DoModal() != IDOK){
return ;
}
CString filePath = dlg.GetPathName();
CClientDC client(this);
CDC cdc;
CBitmap bitmap;
RECT rect;CRect r;
GetClientRect(&rect);
第 15 页 共 21 页
int cx = rect.right - rect.left;
int cy = rect.bottom - rect.top;
bitmap.CreateCompatibleBitmap(&client, cx, cy);
cdc.CreateCompatibleDC(NULL);
//获取BMP对象
CBitmap * oldbitmap = (CBitmap* ) cdc.SelectObject(&bitmap);
//白色画布
cdc.FillRect(&rect,
CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
//画图
for(int i = 0; i < GetDocument()->m_obArray.GetSize(); i ++){
GetDocument()->m_obArray.GetAt(i)->DrawStroke(&cdc);
}
cdc.SelectObject(oldbitmap);
::OpenClipboard(this->m_hWnd);
::EmptyClipboard();
::SetClipboardData(CF_BITMAP, bitmap);
::CloseClipboard();
HBITMAP hBitmap = (HBITMAP)bitmap;
HDC hDC;
int iBits;
WORD wBitCount;
DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;
BITMAP Bitmap;
BITMAPFILEHEADER bmfHdr;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
HANDLE fh, hDib, hPal,hOldPal=NULL;
第 16 页 共 21 页
hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
DeleteDC(hDC);
if (iBits <= 1) wBitCount = 1;
else if (iBits <= 4) wBitCount = 4;
else if (iBits <= 8) wBitCount = 8;
else wBitCount = 24;
GetObject(hBitmap, sizeof(Bitmap), (LPSTR)&Bitmap);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap.bmWidth;
bi.biHeight = Bitmap.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = wBitCount;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrImportant = 0;
bi.biClrUsed = 0;
dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 *
Bitmap.bmHeight;
hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hDC = ::GetDC(NULL);
第 17 页 共 21 页
hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE);
RealizePalette(hDC);
}
GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)
+dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS);
if (hOldPal)
{
::SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
RealizePalette(hDC);
::ReleaseDC(NULL, hDC);
}
fh = CreateFile(filePath, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (fh == INVALID_HANDLE_VALUE)
return ;
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);
GlobalUnlock(hDib);
GlobalFree(hDib);
第 18 页 共 21 页
CloseHandle(fh);
3.9 文档对象数据的销毁
当新建一个文档对象时,或者打开一个文档对象时,先前文档所保存的数据
没有被销毁,这主要是指CGraphicView类OnLButtonUp函数中在堆上为CGraph
对象分配的内存没有被释放。当我们不断地新建文档和打开另一个文档时,实际
上就隐含的有内存泄漏的发生,因为有些对象的内存没有被释放。我们这里的解
决方法代码如下:
void CGraphicDoc::DeleteContents()
{
// TODO: Add your specialized code here and/or call the base class
int nCount;
nCount=m_obArray.GetSize();
for(int i=0;i线条设置,如图4.1,进行图元属性设置
第 19 页 共 21 页
图4.1 线条设置
点击右边工具箱填充按钮,可进行填充色的设置,如图4.2
4.2 填充颜色设置
点击菜单字体设置,如下图4.3,可以进行文字输入的设置。
第 20 页 共 21 页
4.3 字体设置 五、总结
本文实现了基本图形,如点、直线、椭圆、矩形的绘制与保存。
在绘制这些基本图元的过程中,直接调用了编程环境中自带的绘图函
数,并没有研究这些基本图形的绘制算法。在每种图元的绘制过程中,
都由消息来响应,通过鼠标的操作,完成了图元的绘制。
在图形交互方面,本文讨论较少,功能实现简单。仅可对图元进
行基本的删除,修改基本属性的操作。可以说,图形交互才是一个图
形软件的灵魂。因此,这方面,需要改进。
在文件保存方面,本文讨论比较多,也是功能比较强的一项,基
本上已经实现的一个软件的保存与读取操作。
总之,通过阅读大量文献资料,对图形与文件的操作有了较深的
认识。在了解编辑环境的基础上实现的图元的绘制,对编程环境有了
进一步的掌握。同时,对类的机制有了更进一步的了解。
第 21 页 共 21 页