MFC实现简单画图形程序.docx
- 文档编号:23503129
- 上传时间:2023-05-17
- 格式:DOCX
- 页数:25
- 大小:26.03KB
MFC实现简单画图形程序.docx
《MFC实现简单画图形程序.docx》由会员分享,可在线阅读,更多相关《MFC实现简单画图形程序.docx(25页珍藏版)》请在冰豆网上搜索。
MFC实现简单画图形程序
《MFC编程及应用》课程设计报告
题目:
简单画图形程序
学号:
姓名:
指导老师:
时间:
评语:
程序设计步骤:
一、建立基于对话框的应用程序框架;
二、CMy0910200155Dlg类中关键新增变量的作用:
CPtrArraypta;//用于保存已绘图形的相关信息。
CMemoryNode*pmN;//指向CMemoryNode类的指针,程序运行过程中动态保存对象信息。
CMemoryNode*pmn;//指向CMemoryNode类的指针,从文件中读取信息时动态创建类的对象。
COLORREFm_CurrentBrushColor;//用于存放当前画刷的颜色。
COLORREFm_CurrentPenColor;//用于存放当前画笔的颜色。
intnum;//用于存放从"Index.txt"文件中读取的数字。
intflag=0;//用于标识:
当为1时,表示按下了”画图”按钮;当为2时,表示按下了”撤消”按钮;当为3时,表示按下了”加载历史”按钮,则从文件中读取信息。
intmark;//用于标识:
当为0时,表示刚画过矩形;当为1时,表示刚画过圆角矩形;当为2时,表示刚画过椭圆。
intindex;//用于存放pta数组的容量。
intflag1=0;//用于标识,和flag搭配,用来处理多种情况下的窗口重绘问题。
intButtonState=0;//用于标识,是类CShow和类CMy0910200155Dlg的一个接口,通过其值在1和0之间转换,来处理弹出式对话框的初次绘制和移动时的重绘问题。
三、CMemoryNode类中变量的作用:
COLORREFBrushColor;
COLORREFPenColor;
intMark;//以上三者为类CMemoryNode的成员变量,分别用来保存
绘图时画刷颜色,画笔颜色和形状。
四、与控件相关联的变量:
CComboBoxm_BrushColor;//指示画刷颜色组合框。
CComboBoxm_PenColor;//指示画笔颜色组合框。
CListBoxm_Shape;//指示形状列表框。
五、应用程序功能的具体实现:
1)初始化过程:
this->m_Shape.AddString("矩形");//给形状列表框添加一个项目。
this->m_PenColor.AddString("红色");//给画笔颜色框添加一个项目。
this->m_BrushColor.AddString("白色");//给画刷颜色框添加一个项目。
(剩余项目的添加方法完全相同,就不再赘述了)
m_PenColor.SetCurSel(0);
m_BrushColor.SetCurSel(4);
m_Shape.SetCurSel
(2);//设置光标初始定位。
m_CurrentBrushColor=RGB(0,0,255);//画刷颜色设置默认初值为蓝色。
m_CurrentPenColor=RGB(255,0,0);//画笔颜色设置默认初值为红色。
this->SetWindowText("简单画图形程序");//设置窗口标题。
RECTrect;
this->GetWindowRect(&rect);//得到窗体的大小。
CRgnrgn;
rgn.CreateRoundRectRgn(
rect.left+3,rect.top+5,rect.right-2,rect.bottom-2,40,40);
this->SetWindowRgn((HRGN)rgn.GetSafeHandle(),TRUE);
//按要求绘制圆角矩形的窗体。
ifstreaminfile1("Index.txt",ios:
:
nocreate);
if(!
infile1)this->GetDlgItem(IDC_BUTTON_LOAD)->EnableWindow(FALSE);
//通过"Index.txt"文件是否存在来决定”加载历史”按钮的状态,如果存在则可用,否则不可用。
2)窗口绘制过程:
此过程调用OnPaint()函数,涉及多种情况下的图形绘制和窗口重绘,是相对比较核心的部分,将在后面具体逐个分析。
六、从某一次程序运行的角度说明各个函数的功能:
首先打开应用程序,系统将自动创建窗体,在窗体弹出的一瞬间,你会发现窗体是圆角形的,其次感觉颜色比较柔和。
这归功于初始化中的:
RECTrect;
this->GetWindowRect(&rect);
CRgnrgn;
rgn.CreateRoundRectRgn(
rect.left+3,rect.top+5,rect.right-2,rect.bottom-2,40,40);
this->SetWindowRgn((HRGN)rgn.GetSafeHandle(),TRUE);
//绘制圆角矩形的窗体。
和应用类初始化中添加的:
SetDialogBkColor(RGB(80,80,180),RGB(0,0,0));//设置窗体颜色。
如果是第一次使用该程序,那么你将看到”加载历史”按钮是灰化的,不能使用,这是因为初始化中使用了该语句,
ifstreaminfile1("Index.txt",ios:
:
nocreate);
if(!
infile1)this->GetDlgItem(IDC_BUTTON_LOAD)->EnableWindow(FALSE);
没有创建过"Index.txt"文件,当然无法读取!
将已有的"Index.txt"文件删除,然后重新启动系统,会有相同的效果。
你会看到窗口中”形状”,”画笔颜色”,”填充颜色”分别默认为”圆角矩形”,”红色”,”蓝色”,这是因为在初始化过程中,已经对相应的变量赋值,而且设置了光标选择:
m_PenColor.SetCurSel(0);
m_BrushColor.SetCurSel(4);
m_Shape.SetCurSel
(2);//设置光标初始定位。
m_CurrentBrushColor=RGB(0,0,255);//画刷颜色设置默认初值为蓝色。
m_CurrentPenColor=RGB(255,0,0);//画笔颜色设置默认初值为红色。
如果我们想画一个边框为洋红色,填充色为青色的圆角矩形,那么当鼠标点击”画笔颜色”下的”洋红”时,将触发组合框IDC_COMBO_PEN_COLOR的CBN_SELENDOK消息,将调用,
voidCMy0910200155Dlg:
:
OnSelendokComboPenColor()
{
intn=m_PenColor.GetCurSel();
switch(n)
{
case0:
m_CurrentPenColor=RGB(255,0,0);break;
case1:
m_CurrentPenColor=RGB(0,255,0);break;
case2:
m_CurrentPenColor=RGB(0,0,255);break;
case3:
m_CurrentPenColor=RGB(255,255,0);break;
case4:
m_CurrentPenColor=RGB(255,0,255);break;
case5:
m_CurrentPenColor=RGB(0,255,255);break;
default:
m_CurrentPenColor=RGB(0,0,0);break;
}
}
同理可知,当鼠标点击”填充颜色”下的”青色”时,将触发组合框IDC_COMBO_BRUSH_COLOR的CBN_SELENDOK消息,将调用,
voidCMy0910200155Dlg:
:
OnSelendokComboBrushColor()
{
intn=m_BrushColor.GetCurSel();
switch(n)
{
case6:
m_CurrentBrushColor=RGB(255,0,0);break;
case5:
m_CurrentBrushColor=RGB(0,255,0);break;
case4:
m_CurrentBrushColor=RGB(0,0,255);break;
case3:
m_CurrentBrushColor=RGB(255,255,0);break;
case2:
m_CurrentBrushColor=RGB(255,0,255);break;
case1:
m_CurrentBrushColor=RGB(0,255,255);break;
default:
m_CurrentBrushColor=RGB(255,255,255);break;
}
}
这两个函数能将光标的选择转换为画笔或画刷的颜色。
不过,当然必须先给组合框添加过一个CBN_SELENDOK消息!
然后点击”形状”下的”圆角矩形”,这时this->m_Shape.GetSel
(1)其值为TRUE,表明”圆角矩形”被选中了,当然,其它两个m_Shape.GetSel(0)和m_Shape.GetSel
(2)都为FALSE。
在画图前,如果你足够细心,你会注意到刚才在选颜色时,如果颜色还没有选定,它周围就会有一个当前颜色的色圈,而当颜色已选定时,色圈就会变为彩色背景,这是因为之前给类CMy0910200155Dlg添加了WM_CTLCOLOR消息,因此当触发该消息时,会调用,
HBRUSHCMy0910200155Dlg:
:
OnCtlColor(CDC*pDC,CWnd*pWnd,UINTnCtlColor)
{
HBRUSHhbr=CDialog:
:
OnCtlColor(pDC,pWnd,nCtlColor);
if(pWnd->GetDlgCtrlID()==IDC_COMBO_PEN_COLOR)
{
hbr=:
:
CreateSolidBrush(this->m_CurrentPenColor);
pDC->SetBkColor(this->m_CurrentPenColor);
}
if(pWnd->GetDlgCtrlID()==IDC_COMBO_BRUSH_COLOR)
{
hbr=:
:
CreateSolidBrush(this->m_CurrentBrushColor);
pDC->SetBkColor(this->m_CurrentBrushColor);
}
returnhbr;
}
该方法可以实现控件颜色的改变,考虑到界面的简洁(不是简单)和色彩协调,其它控件的颜色就不必改变了。
做好了这些准备工作,现在我们开始绘图,点击”绘图”按钮,就触发了IDC_BUTTON_DRAW的BN_CLICKED消息,会调用,
voidCMy0910200155Dlg:
:
OnButtonDraw()
{
flag=1;
flag1=1;
OnPaint();
this->GetDlgItem(IDC_BUTTON_LOAD)->EnableWindow(FALSE);
}
在这里,我们只将flag=1和flag1=1条件下的OnPaint()函数展开(系统自己生成的代码我们略去),
if(index<=0)
{
this->GetDlgItem(IDC_BUTTON_CLEAN)->EnableWindow(FALSE);
}//根据判断确定”撤消”按钮的状态,若绘图区没有图形,则其失效。
if(flag==1||flag==2||flag==3)
{
CClientDCdc(this);
{
CPenpNewPen1;
pNewPen1.CreatePen(PS_SOLID,2,RGB(80,80,180));
CPen*pOldPen1=dc.SelectObject(&pNewPen1);
CBrushpNewBrush1;
pNewBrush1.CreateSolidBrush(RGB(80,80,180));
CBrush*pOldBrush1=dc.SelectObject(&pNewBrush1);
CRectrect1;
this->GetDlgItem(IDC_DRAW_PLACE)->GetWindowRect(&rect1);
this->ScreenToClient(&rect1);
CRectdraw1(rect1.left+3,rect1.top+9,rect1.right-2,rect1.bottom-2);
dc.Rectangle(draw1);
dc.SelectObject(pOldPen1);
dc.SelectObject(pOldBrush1);
}//此为所有情况下的公用部分,将绘图区绘为背景色。
if((flag==1||flag==3))
{
if(flag==3)
{
this->m_CurrentPenColor=pmn->PenColor;
this->m_CurrentBrushColor=pmn->BrushColor;
intmark=pmn->Mark;
}
CPenpNewPen;
pNewPen.CreatePen(PS_SOLID,2,this->m_CurrentPenColor);
CPen*pOldPen=dc.SelectObject(&pNewPen);
CBrushpNewBrush;
pNewBrush.CreateSolidBrush(this->m_CurrentBrushColor);
CBrush*pOldBrush=dc.SelectObject(&pNewBrush);
CRectrect;
this->GetDlgItem(IDC_DRAW_PLACE)->GetWindowRect(&rect);
this->ScreenToClient(&rect);
CRectdraw(rect.left+3,rect.top+9,rect.right-2,rect.bottom-2);this->GetDlgItem(IDC_DRAW_PLACE)->GetWindowRect(&rect);
this->ScreenToClient(&rect);
CRectdraw(rect.left+3,rect.top+9,rect.right-2,rect.bottom-2);
if(flag==1)
{
if(this->m_Shape.GetSel(0))
{dc.Rectangle(draw);mark=0;}
elseif(this->m_Shape.GetSel
(1))
{dc.RoundRect(draw,CPoint(100,100));mark=1;}
else{dc.Ellipse(draw);mark=2;}
}
if(flag==3)
{
switch(mark)
{case0:
dc.Rectangle(draw);break;
case1:
dc.RoundRect(draw,CPoint(100,100));break;
default:
dc.Ellipse(draw);break;
}
}
dc.SelectObject(pOldPen);
dc.SelectObject(pOldBrush);
this->GetDlgItem(IDC_BUTTON_CLEAN)->EnableWindow(TRUE);
if(flag==1&&flag1==1)
{
pmN=newCMemoryNode(
m_CurrentPenColor,m_CurrentBrushColor,mark);
pta.Add(pmN);
OnFileWrite();
flag1=0;
}//用当前所选画笔,画刷和图形绘图。
}
其实,当点击”绘图”按钮时,只是先用背景色的画笔和刷子把绘图区重绘一遍,然后再用当前所选画笔,刷子和图形绘图,同时将当前的绘图信息保存在pta数组中和写入到文件中。
现在,请仔细看一下最后一句flag1=0;,它的作用很大,它解决了当点击绘图按钮,绘出图形后,移动窗口时图形信息的重复保存和文档的重复书写问题。
没有它,程序虽然可以正常运行,但当从文件中读取信息后,运行结果和预想很有出入!
点击”绘图按钮”后,”载入历史”按钮将不能使用,这就限定了这个按钮只能在程序的开始使用,而且只能使用一次。
在上面提到了将绘图信息写入到文件中,那么下面看看这个写文件的函数,
voidCMy0910200155Dlg:
:
OnFileWrite()
{
intsum=pta.GetSize();//已画图形的个数,即点击”绘图”按钮的次数。
ofstreamoutfile;
ofstreamoutfile1;
outfile.open("Histories.txt",ios:
:
app);//添加式书写。
outfile1.open("Index.txt");//覆盖式书写。
if(!
outfile||!
outfile1)
{MessageBox("数据无法保存!
");}
else
{
outfile< outfile< outfile< outfile1< } outfile.close(); outfile1.close(); } 上面是用C++的输出流来写文件的,分别建立两个文件"Histories.txt"和"Index.txt",分别用来保存绘图的历史和绘图的个数,即点击n次鼠标时绘图的n个状态和次数n。 画好图形后,点击”撤消”按钮,会调用, voidCMy0910200155Dlg: : OnButtonClean() { flag=2; flag1=2; index=this->pta.GetUpperBound(); OnPaint(); } 仿照前面的方式,为了更好表现出函数的功能,将flag=2和flag1=2条件下的OnPaint()函数完全地展开(和其它情况的公用部分省略), if(flag==2) { if(index==0) { CPenpNewPen; pNewPen.CreatePen(PS_SOLID,2,RGB(80,80,180)); CPen*pOldPen=dc.SelectObject(&pNewPen); CBrushpNewBrush; pNewBrush.CreateSolidBrush(RGB(80,80,180)); CBrush*pOldBrush=dc.SelectObject(&pNewBrush); CRectrect;this->GetDlgItem(IDC_DRAW_PLACE)->GetWindowRect(&rect); this->ScreenToClient(&rect); CRectdraw(rect.left+3,rect.top+9,rect.right-2,rect.bottom-2); dc.Rectangle(draw); dc.SelectObject(pOldPen); dc.SelectObject(pOldBrush); }//当撤消完全时,只需重绘绘图区即可。 if(index>0) { CMemoryNode*pmN; pmN=(CMemoryNode*)pta.GetAt(index-1); CPenpNewPen1; pNewPen1.CreatePen(PS_SOLID,2,RGB(80,80,180)); CPen*pOldPen1=dc.SelectObject(&pNewPen1); CBrushpNewBrush1; pNewBrush1.CreateSolidBrush(RGB(80,80,180)); CBrush*pOldBrush1=dc.SelectObject(&pNewBrush1); CRectrect1; this->GetDlgItem(IDC_DRAW_PLACE)->GetWindowRect(&rect1); this->ScreenToClient(&rect1); CRectdraw1(rect1.left+3,rect1.top+9,rect1.right-2,rect1.bottom-2); dc.Rectangle(draw1); dc.SelectObject(pOldPen1); dc.SelectObject(pOldBrush1); CPenpNewPen; pNewPen.CreatePen(PS_SOLID,2,pmN->PenColor); CPen*pOldPen=dc.SelectObject(&pNewPen); CBrushpNewBrush; pNewBrush.CreateSolidBrush(pmN->BrushColor); CBrush*pOldBrush=dc.SelectObject(&pNewBrush); CRectrect; this->GetDlgItem(IDC_DRAW_PLACE)->GetWindowRect(&rect); this->ScreenToClient(&rect); CRectdraw(rect.left+3,rect.top+9,rect.right-2,rect.bottom-2); if(pmN->Mark==0) {dc.Rectangle(draw);} elseif(pmN->Mark==1) {dc.RoundRect(draw,CPoint(100,100));} else{dc.Ellipse(draw);} dc.SelectObject(pOldPen); dc.SelectObject(pOldBrush); if(flag1==2) { this->pta.RemoveAt(index-1); flag1=0; } } } 虽然有些冗长,但可以清晰地看出撤消的思路也是先用背景色的画笔和刷子把绘图区重绘一遍,然后调
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- MFC 实现 简单 画图 程序