版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C++程序设计第6章MFC文档/视图应用程序第1节文档/视图结构第2节绘图与文字第3节定时器第4节鼠标与键盘消息处理第5节菜单*第6节工具栏第7节对话框第8节综合举例第1节文档/视图结构文档/视图结构应用程序的特点文档/视图程序的开发过程1.1文档/视图结构的特点文档:用于管理应用程序的数据视图:用户界面,用于显示、打印文档中的数据、管理与用户的交互。数据的管理与显示分离的思想简化了开发过程文档/视图结构应用程序:SDI:单文档MDI:多文档1.2文档/视图程序的开发过程(1)建立应用程序框架;(2)编辑资源(视需要可选);(3)添加、编写消息处理函数例6-1编写文档/视图程序,在视图中显示HelloDocView字样,如有图(1)创建基于文档视图的应用程序框架目前一句代码都还没写,就已经有一个可以运行的文档/视图程序了。VS为我们搭好了一个程序框架。如果我们想修改对话框和程序的功能,我们只需在这个框架中找到对应的地方加入或修改代码即可。文档视图框架中的类结构HelloDocView中,从类视图可看到以下五个类:CAboutDlg
——关于对话框CHelloDocViewApp(C***App)
——应用程序类,负责程序的启动、结束等进程管理事务。CHelloDocViewDoc(C***Doc)
——文档类,负责文档数据管理、储存、读取等事务。CHelloDocViewView(C***View)
——视图类,负责文档或程序数据的显示CMainFrame
——主框架类,负责视图和菜单、工具栏等界面元素的整合。(2)本程序无需编辑资源,该步省略。(3)添加、编写消息处理函数
本程序需对视图类已有的重绘函数OnDraw()进行修改,添加如下代码:voidCHelloDocViewView::OnDraw(CDC*pDC){CHelloDocViewDoc*pDoc=GetDocument();//取得文档指针ASSERT_VALID(pDoc);//检查文档指针是否有效if(!pDoc)//如果文档指针为空则返回return;//TODO:在此处为本机数据添加绘制代码
//绘制一个左上角为(100,100),右下角为(320,140)的矩形。
//注意屏幕坐标是左上角为原点,Y坐标向下
pDC->Rectangle(100,100,320,140);pDC->TextOutW(110,110,_T("HelloDoc-ViewProgram!"));//以(110,110)为起点输出字符串}OK!第2节绘图与文字相关消息处理函数与类OnDraw函数Graphics类Pen类Brush类Bitmap类Font类2.1与绘图与文字输出相关的消息处理函数与类1.相关消息处理函数OnDraw函数——视图重绘函数2.相关类
Graphics——提供绘制的方法Pen——画笔Brush——画刷
Bitmap——位图
Font——字体2.2OnDraw函数视图需要重绘时自动调用,例如客户区改变、最小化变最大化、程序自己申请重新绘制(调用Invalidate函数)等情形功能:重新绘制视图内容形式:voidC***View::OnDraw(CDC*pDC){…}参数:pDC——视图客户区设备描述表指针。2.3Graphics类DC——DeviceContext,有的书译成“设备上下文”,有的书译成“设备描述表”。它是一种与设备无关的图形设备环境数据结构。意思是程序员用户只管用这个设备描述表里面的函数画图,而不必关心硬件是何种显卡或何种打印机,请放心,设备描述表会帮你对接好所有这些显示设备硬件。Graphics——我们实际进行绘制时需要用到Graphics对象,Graphics类提供绘制线条、曲线、图形、图像和文本的方法。创建Graphics对象需要用到DC的句柄HDC。Graphics类的成员函数的返回值总是Status,其指示着函数调用的结果,调用成功返回Ok。1.文字输出StatusDrawString(
constWCHAR*string,//待绘制的字符串
INTlength, //指定绘制的字符数
constFont*font, //指定绘制的字体属性
constPointF&origin,//二维浮点型结构体,指定绘制的屏幕位置
constBrush*brush//指定用于填充颜色的笔刷);2.画线StatusDrawLine(
constPen*pen,//指定用于绘制线条的画笔
constPoint&pt1,//二维整型结构体,指定线段的起点
constPoint&pt2//指定线段的终点);3.画矩形StatusDrawRectangle(
constPen*pen,//指定绘制线条的画笔
constRect&rect//用于定义矩形的结构体,其中包含了矩形的左上
//角坐标、矩形的宽度和高度
);4.画椭圆/圆StatusDrawEllipse(
constPen*pen,//指定绘制线条的画笔
constRect&rect//指定圆/椭圆的外接矩形);5.画多边形StatusDrawPolygon( constPen*pen,//指定绘制线条的画笔 constPointF*points,//点数组,描述多边形每个顶点的坐标 INTcount
//指定实际需要绘制的顶点数);6.获取客户区的大小StatusGetVisibleClipBounds(Rect*rect)const;例6-2绘制-3~3之间的曲线(1)创建单文档的MFC程序框架方法参见6.1节例6-1步骤(1)。(2)引入GDI+,GDI+中包含了Graphics类的定义:
Ⅰ在程序中使用GDI+命名空间具体方法是修改pch.h文件,在该头文件的结尾处加入下列的代码:#include<GdiPlus.h>//引入GDI+头文件usingnamespaceGdiplus;//使用GDI+的命名空间#pragmacomment(lib,"gdiplus.lib")//引入静态库文件Ⅱ在CXPower3.cpp中增加一个全局变量,以表明对GDI+的一个引用,实现的代码如下…#ifdef_DEBUG#definenewDEBUG_NEW#endifULONG_PTRgdiplusToken;//全局变量,表明对GDI+的一个引用Ⅲ接着在CXPower3App的InitInstance()函数中增加GDI+函数的初始化操作:BOOLCXPower3App::InitInstance(){
……
InitCommonControlsEx(&InitCtrls);
//GDI+系统资源的初始化
GdiplusStartupInputgdiplusStartupInput;
GdiplusStartup(&gdiplusToken,&gdiplusStartupInput,NULL);
//GDI+系统资源的初始化的代码需要放在该代码前CWinApp::InitInstance();
……
returnTRUE;}Ⅳ最后,使用完GDI+后在CXPower3App::ExitInstance()函数中将其销毁:intCXPower3App::ExitInstance(){ //TODO:处理可能已添加的附加资源 AfxOleTerm(FALSE);
GdiplusShutdown(gdiplusToken);//销毁GDI+资源 returnCWinApp::ExitInstance();}(3)在OnDraw中添加和编写消息处理函数voidCXPower3View::OnDraw(CDC*pDC){CXPower3Doc*pDoc=GetDocument();ASSERT_VALID(pDoc);if(!pDoc)return;//TODO:在此处添加绘制代码
HDChdc=::GetDC(m_hWnd);//获取DC句柄Gdiplus::Graphicsgraphics(hdc);//创建Graphics对象
//创建画笔和画刷Penpen(Color(255,0,0,0),1);SolidBrushbrush(Color(255,0,0,0));
//取视图中心点,把原点画在那里Rectrect;graphics.GetVisibleClipBounds(&rect);intnOx=rect.Width/2;intnOy=rect.Height/2;//X轴PointxBegin(nOx-350,nOy);PointxEnd(nOx+350,nOy);graphics.DrawLine(&pen,xBegin,xEnd);//X轴箭头//定义箭头的三个点
PointFpoints1[3];
points1[0].X=nOx+350;
points1[0].Y=nOy-5;
points1[1].X=nOx+350;
points1[1].Y=nOy+5;
points1[2].X=nOx+370;
points1[2].Y=nOy;
//根据三个点组成箭头形状
graphics.DrawPolygon(&pen,points1,3);
graphics.DrawString(_T("X"),1,&Gdiplus::Font(L"Arial",8),
PointF(nOx+350,nOy-30),&brush);
//Y轴PointyBegin(nOx,nOy-150);PointyEnd(nOx,nOy+150);graphics.DrawLine(&pen,yBegin,yEnd);//Y轴箭头
PointFpoints2[3];points2[0].X=nOx-5;points2[0].Y=nOy-150;//注意屏幕坐标Y轴正方向向下,画图却要把正
//方向画成向上points2[1].X=nOx+5;points2[1].Y=nOy-150;points2[2].X=nOx;points2[2].Y=nOy-170;graphics.DrawPolygon(&pen,points2,3);graphics.DrawString(_T("Y"),1,&Gdiplus::Font(L"Arial",8),
PointF(nOx+10,nOy-170),&brush);
//X轴刻度inti;for(i=-3;i<=3;i++){ graphics.DrawLine(&pen,Point(nOx-100*i,nOy),
Point(nOx-100*i,nOy-10));}
//Y轴刻度for(i=-1;i<=1;i++){ graphics.DrawLine(&pen,Point(nOx,nOy-100*i),
Point(nOx-10,nOy-100*i));}//函数曲线brush.SetColor(Color(255,255,0,0));//设置画刷颜色为红色doubledX,dY;intnScreenX,nScreenY;for(dX=-3;dX<3;dX+=0.01){ dY=dX*dX*dX/27; nScreenX=int(nOx+100*dX+0.5);//将图形扩大100倍,计算屏幕
//位置并四舍五入 nScreenY=int(nOy-100*dY+0.5); graphics.FillEllipse(&brush,nScreenX,nScreenY,2,2);//画点}}OK!2.4画笔Pen类:为绘图提供多种线型、宽度和颜色。创建画笔函数voidPen(constColor&color,//封装了rgba的结构体引用,用于指定画笔的颜色
REALwidth //画笔宽度);设置画笔样式StatusSetDashStyle(DashStyledashStyle);dashStyle是一个枚举变量,其指定用WindowsGDI+笔绘制的线条的线条样式DashStyleSolid:指定实线。DashStyleDash:指定虚线。DashStyleDot:指定虚线。DashStyleDashDot:指定交替虚线。DashStyleDashDotDo:指定交替短划线点点线。DashStyleCustom:指定用户定义的自定义虚线。例:画一条3像素宽的红色实线可在OnDraw()中使用如下代码:HDChdc=::GetDC(m_hWnd);//获取DC句柄//创建Graphics对象Gdiplus::Graphicsgraphics(hdc);//创建颜色为红色,宽度为3的画笔Penpen(Color(255,255,0,0),3);//设置画笔样式为虚线pen.SetDashStyle(DashStyleDash);
Pointbegin(10,10);//线段起点Pointend(50,50);//线段终点graphics.DrawLine(&pen,begin,end);//调用DrawLine()画线OK!2.5画刷Brush类:代表一个画刷,为绘图中的封闭图形内部填充颜色或图案。(1)SolidBrush(constColor&color);创建纯色画刷,color为画刷的颜色。(2)HatchBrush( HatchStylehatchStyle, //阴影线样式 constColor&foreColor,//前景色 constColor&backColor=Color()//背景色);创建阴影线画刷,hatchStyle取值示例:Horizontal、ForwardDiagonal和Cross。例:使用一个颜色画刷和图案画刷填充圆在Ondraw中添加如下代码:HDChdc=::GetDC(m_hWnd);//获取DC句柄Gdiplus::Graphicsgraphics(hdc);//创建Graphics对象//创建纯色画刷SolidBrushsolidBrush(Color(255,0,255,0));//创建阴影线画刷HatchBrushhatchBrush(HatchStyleCross,Color(255,
255,0,0),Color(255,0,255,0));//画圆Rectrect1(50,50,100,100);Rectrect2(200,50,100,100);graphics.FillEllipse(&solidBrush,rect1);graphics.FillEllipse(&hatchBrush,rect2);OK!2.6位图Image类提供用于加载和显示光栅图像和矢量图像的基本方法。从Image类继承的Bitmap类提供了用于加载、显示和操作光栅图像的更专用的方法voidBitmap( constWCHAR*filename, //图像路径 BOOLuseEmbeddedColorManagement=0//可选参数);创建一个位图实例Graphics::DrawImage( Image*image, //指向图片实例的指针 INREALx, //绘制位置的左上角x坐标 INREALy //绘制位置的左上角y坐标);绘制图片2.6位图例6-3使用Bitmap在视图中显示位图(1)创建单文档的MFC程序框架并引入GDI+资源(参考例6-2)(2)准备好一张位图。(3)编写消息处理函数。绘制效果如下图所示。2.6位图voidCDisplayBmpView::OnDraw(CDC*pDC){ CDisplayBmpDoc*pDoc=GetDocument(); ASSERT_VALID(pDoc); if(!pDoc)
return;
//TODO:在此处为本机数据添加绘制代码
HDChdc=::GetDC(m_hWnd);
//获取DC句柄
Gdiplus::Graphicsgraphics(hdc);//创建Graphics对象
//根据位图的路径加载位图
BitmapbitMap(L"./res/位图.bmp"); graphics.DrawImage(&bitMap,0,0);}OK!2.7字体Font类:为程序数字文字提供字体主要函数:Font(constFontFamily*family, //FontFamily对象指针REALemSize, //字体大小INTstyle=FontStyleRegular, //字体样式Unitunit=UnitPoint //字号的度量单位);创建字体对象。voidFontFamily(
constWCHAR*name, //指定字体系列constFontCollection*fontCollection=NULL//指定字体系列所属的集合);创建FontFamily对象StatusDrawString( constWCHAR*string, //绘制的字符串
INTlength, constFont*font, constPointF&origin, constBrush*brush);基于字符串的字体和源绘制字符串。例6-4:使用字体输出文字voidCFontExampleView::OnDraw(CDC*pDC){CFontExampleDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!pDoc)
return;
//TODO:在此处为本机数据添加绘制代码
HDChdc=::GetDC(m_hWnd);//获取DC句柄
Gdiplus::Graphicsgraphics(hdc);//创建Graphics对象//创建FontFamily对象
Gdiplus::FontFamilyfontFamily(L"华文新魏");//根据FontFamily对象创建Font对象Gdiplus::Fontfont(&fontFamily,100,FontStyleRegular,UnitPixel);//创建画刷SolidBrushbrush(Color(255,0,0,0));//绘制字体graphics.DrawString(L"C++程序设计",-1,&font,PointF(100,100),&brush);}OK!第3节定时器定时器3.1定时器定时器是计算机内部的计时器,创建之后,会每隔一段时间发出一个定时器消息,以供程序处理。使用方法与步骤:(1)创建定时器(2)编写定时消息WM_TIMER的响应函数(3)程序结束前撤销定时器(1)创建定时器UINTSetTimer(UINTnIDEvent,UINTnElapse,void*lpfnTimer)说明:
nIDEvent:定时器标识,任何一个非0整数
nElapse:时间间隔,单位毫秒
lpfnTimer:一般设置为NULL(2)定时消息响应函数定时消息:WM_TIMER响应函数:voidXXXXX::OnTimer(UINT_PTRnIDEvent){//TODO:在此添加消息处理程序代码和/或调用默认值CDialogEx::OnTimer(nIDEvent);}说明:
nIDEvent——定时器的编号
XXXXX:程序中某个类,可以在类向导中选择,但一般选择文档类或视图类(3)撤销定时器程序结束前需撤销定时器BOOLKillTimer(intnIDEvent);
说明:nIDEvent为撤销的定时器标识。例6-5用定时器实现动画(1)创建单文档应用程序框架并引入GDI+资源(2)编辑资源
▶准备好动画序列帧图(bmp文件)
▶将准备好的位图放在项目文件夹res路径下:(3)添加、修改相关消息响应函数
▶为OnDraw()添加显示一张位图的代码voidCAnimateView::OnDraw(CDC*pDC){CAnimateDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);if(!pDoc)return;//TODO:在此处为本机数据添加绘制代码
HDChdc=::GetDC(m_hWnd);//获取DC句柄Gdiplus::Graphicsgraphics(hdc);//创建Graphics对象//根据位图的路径加载位图
BitmapbitMap(L"./res/图片素材--豹子/1.bmp");graphics.DrawImage(&bitMap,0,100);}▶要把各张图片轮播起来才能形成动画。为此要添加一个控制变量。在视图类头文件中视图类末尾直接添加即可。classCAnimateView:publicCview{
private:WCHAR*pictures[8]= { L"./res/图片素材--豹子/1.bmp", L"./res/图片素材--豹子/2.bmp", L"./res/图片素材--豹子/3.bmp", L"./res/图片素材--豹子/4.bmp", L"./res/图片素材--豹子/5.bmp", L"./res/图片素材--豹子/6.bmp", L"./res/图片素材--豹子/7.bmp", L"./res/图片素材--豹子/8.bmp" };//表示轮换的图片路径列表intm_nWhich;//表示当前要播放哪一张图片};▶并在视图类构造函数中进行初始化。CAnimateView::CAnimateView()noexcept{//TODO:在此处添加构造代码m_nWhich=0;}▶添加定时消息响应函数OnTimer()在视图类中可看到向导添加的代码:voidCAnimateView::OnTimer(
UINT_PTRnIDEvent){//TODO:在此添加消息处理程序代码CView::OnTimer(nIDEvent);}▶仿照上一步,继续在类向导中添加两个消息处理函数:
OnCreate()——视图类开始创建界面时,会向程序发出一个WM_CREATE消息。OnCreate()是该消息的响应函数。该函数可以用来做构造函数里不能做的初始化工作。
OnDestroy()——在程序结束前,视图类要销毁自己的窗口,在销毁之前,会向程序发出一个WM_DESTROY消息,OnDestroy()是该消息的响应函数。该函数可以用来做析构函数里不能做的清理工作。▶在OnCreate()和OnDestroy()中加入代码intCAnimateView::OnCreate(LPCREATESTRUCTlpCreateStruct){if(CView::OnCreate(lpCreateStruct)==-1)return-1;//TODO:在此添加您专用的创建代码
SetTimer(1,200,NULL);
//定时器编号为1,时间间隔为200毫秒
return0;}voidCAnimateView::OnDestroy(){CView::OnDestroy();//TODO:在此处添加消息处理程序代码
KillTimer(1);//撤销1号定时器}▶在OnTimer()中添加代码voidCAnimateView::OnTimer(UINT_PTRnIDEvent){//TODO:在此添加消息处理程序代码和/或调用默认值
m_nWhich=(m_nWhich+1)%8;//切换轮播Invalidate();//使得视图失效,激发重绘函数OnDraw()CView::OnTimer(nIDEvent);}▶修改OnDraw(),使其每次播放不同的图片voidCAnimateView::OnDraw(CDC*pDC){CAnimateDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!pDoc)
return;
//TODO:在此处为本机数据添加绘制代码HDChdc=::GetDC(m_hWnd);//获取DC句柄Gdiplus::Graphicsgraphics(hdc);//创建Graphics对象//根据位图的路径加载位图BitmapbitMap(pictures[m_nWhich]);graphics.DrawImage(&bitMap,0,100);}至此,动画已可以播放。但豹子只是在原地跑。▶为了让豹子真正跑起来,需要控制每次位图显示的位置。为此,再加入一个控制位图水平显示位置的变量:classCAnimateView:publicCView{private:WCHAR*pictures[8]= { L"./res/图片素材--豹子/1.bmp", L"./res/图片素材--豹子/2.bmp", L"./res/图片素材--豹子/3.bmp", L"./res/图片素材--豹子/4.bmp", L"./res/图片素材--豹子/5.bmp", L"./res/图片素材--豹子/6.bmp", L"./res/图片素材--豹子/7.bmp", L"./res/图片素材--豹子/8.bmp" };//表示轮换的图片路径列表intm_nWhich;//表示当前要播放哪一张图片intm_nX;
//控制位图显示的水平位置
};▶在视图类构造函数中修改代码:CAnimateView::CAnimateView()noexcept{ //TODO:在此处添加构造代码
m_nWhich=0;
m_nX=0;//此处为初始化豹子的起始位置}▶再次修改OnDraw()函数:voidCAnimateView::OnDraw(CDC*pDC){CAnimateDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);if(!pDoc)return;//TODO:在此处为本机数据添加绘制代码HDChdc=::GetDC(m_hWnd);//获取DC句柄Gdiplus::Graphicsgraphics(hdc);//创建Graphics对象
//计算位图应放置的位置
m_nX+=80;Rectrect;graphics.GetVisibleClipBounds(&rect);m_nX=m_nX>rect.Width?m_nX-rect.Width:m_nX;//根据位图的路径加载位图
BitmapbitMap(pictures[m_nWhich]);graphics.DrawImage(&bitMap,m_nX,100);}OK!作业例5-8中,点击了“启动提醒”按钮,程序会挂死,一直等待到时间到达。修改例5-8,使点击“启动提醒”按钮后不挂死,而可以进行其他操作。同时增加“取消提醒”按钮,以未到提醒时间时可以随时取消。第4节鼠标与键盘消息处理鼠标消息键盘消息4.1鼠标消息WM_LBUTTONDOWN 按下鼠标左键WM_LBUTTONUP
释放鼠标左键WM_LBUTTONDBLCLK
双击鼠标左键WM_RBUTTONDOWN
按下鼠标右键WM_RBUTTONUP
释放鼠标右键WM_RBUTTONDBLCLK
双击鼠标右键WM_MOUSEMOVE
鼠标移动可在类向导中设置各消息的响应函数例:设置鼠标左键单击消息响应函数在类向导中,设置WM_LBUTTONDOWN的响应函数OnLButtonDown()然后在视图类中就可看到生成的OnLButtonDown()函数voidCMousePntView::OnLButtonDown(UINTnFlags,//包含Shift、Ctrl和Alt键的状态信息
CPointpoint)//当前鼠标指针位置{//TODO:在此添加消息处理程序代码和/或调用默认值
CView::OnLButtonDown(nFlags,point);}nFlags取值含义MK_CONTROLCtrl键被按下MK_LBUTTON鼠标左键被按下MK_MBUTTON鼠标中键被按下MK_RBUTTON鼠标右键被按下MK_SHIFT只有Shift键被按下例6-6鼠标点击时显示鼠标指针的位置(1)创建单文档程序框架。程序起名MousePnt。(2)引入GDI+资源,详见例6-2。(3)添加和编辑消息处理函数。为记录鼠标位置数据,在文档类增加一个Point数据成员
classCMousePntDoc:publicCDocument{protected://仅从序列化创建CMousePntDoc()noexcept;DECLARE_DYNCREATE(CMousePntDoc)//特性public:
Pointm_ptPos;
……}添加WM_LBUTTONDOWN的响应函数OnLButtonDown(),增加代码:voidCMousePntView::OnLButtonDown(UINTnFlags,CPointpoint){//TODO:在此添加消息处理程序代码和/或调用默认值
CMousePntDoc*pDoc=GetDocument();//取得文档指针pDoc->m_ptPos={point.x,point.y};Invalidate();CView::OnLButtonDown(nFlags,point);}在OnDraw()函数中显示鼠标单击的位置voidCMousePntView::OnDraw(CDC*pDC){CMousePntDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);if(!pDoc)return;//TODO:在此处为本机数据添加绘制代码HDChdc=::GetDC(m_hWnd);Gdiplus::Graphicsgraphics(hdc);FontFamilyfontFamily(L"宋体");Gdiplus::Fontfont(&fontFamily,16,FontStyleRegular,UnitPixel);SolidBrushbrush(Color(255,0,0,0));CStrings;s.Format(_T("鼠标单击位置:x=%d,y=%d"),pDoc->m_ptPos.X,pDoc->m_ptPos.X);graphics.DrawString(s,-1,&font,PointF(10,10),&brush);}OK!例6-7鼠标左键自由画线,右键画圆形(1)创建单文档程序框架。程序起名MouseDraw。(2)引入GDI+资源,详见例6-2。(3)添加和编辑消息处理函数为记录画图数据,在文档类增加一个Point成员和Point数组classCMouseDrawDoc:publicCDocument{……//特性public:
Pointm_ptSqCen;//记录圆坐标CArray<Point,Point&>m_aCurvePnts;//自由曲线点数组……}在视图类中也加入一个成员变量,此为记录视图中是否正在画曲线classCMouseDrawView:publicCView{……//特性public:CMouseDrawDoc*GetDocument()const;
boolm_bCurveDrawing;……}并在视图类构造函数中对其进行初始化CMouseDrawView::CMouseDrawView()noexcept{//TODO:在此处添加构造代码
m_bCurveDrawing=false;}在类向导里对WM_LBUTTONDOWN、WM_LBUTTONUP、WM_MOUSEMOVE、WM_RBUTTONUP四个消息添加处理函数对四个鼠标消息响应函数添加代码。绘图的思路:<1>自由曲线:鼠标左键一按下,m_bCurveDrawing就标记为true;OnMouseMove就开始增加点;左键一弹起,m_bCurveDrawing就标记为false,OnMouseMove就不再增加点。<2>圆形:右键一按下,就更新圆的中心,重新画圆。voidCMouseDrawView::OnLButtonDown(UINTnFlags,CPointpoint){//TODO:在此添加消息处理程序代码和/或调用默认值
CMouseDrawDoc*pDoc=GetDocument();pDoc->m_aCurvePnts.RemoveAll();//清除上一次的曲线点集数据m_bCurveDrawing=true;CView::OnLButtonDown(nFlags,point);}voidCMouseDrawView::OnLButtonUp(UINTnFlags,CPointpoint){//TODO:在此添加消息处理程序代码和/或调用默认值
m_bCurveDrawing=false;CView::OnLButtonUp(nFlags,point);}voidCMouseDrawView::OnMouseMove(UINTnFlags,CPointpoint){//TODO:在此添加消息处理程序代码和/或调用默认值
CMouseDrawDoc*pDoc=GetDocument();if(m_bCurveDrawing){pDoc->m_aCurvePnts.Add(Point(point.x,point.y));;//点集数组中加入一点
Invalidate(false);}CView::OnMouseMove(nFlags,point);}voidCMouseDrawView::OnRButtonUp(UINTnFlags,CPointpoint){//TODO:在此添加消息处理程序代码和/或调用默认值
MouseDrawDoc*pDoc=GetDocument();
Doc->m_ptSqCen=Point(point.x,point.y);
Invalidate(true);CView::OnRButtonUp(nFlags,point);}在OnDraw()中画图voidCMouseDrawView::OnDraw(CDC*pDC){……//TODO:在此处为本机数据添加绘制代码HDChdc=::GetDC(m_hWnd);Gdiplus::Graphicsgraphics(hdc);Penpen(Color(255,0,0,0));//画右击的圆形Rectrect(pDoc->m_ptSqCen.X-20,pDoc->m_ptSqCen.Y-20,40,40);graphics.DrawEllipse(&pen,rect);//画左键的曲线SolidBrushbrush(Color(255,0,0,0));intnLen=pDoc->m_aCurvePnts.GetCount();Pointprev;if(nLen>0)prev=pDoc->m_aCurvePnts[0];for(inti=1;i<nLen;i++){graphics.DrawLine(&pen,prev,pDoc->m_aCurvePnts[i]);prev=pDoc->m_aCurvePnts[i];}}OK!4.2键盘消息WM_CHAR按键WM_KeyDown
按下键WM_KeyUp
释放键可在类向导中设置各消息的响应函数例:设置WM_KEYDOWN消息响应函数在类向导中,设置WM_KEYDOWN的响应函数OnKeyDown()然后在视图类中就可看到生成的OnKeyDown()函数voidCKeyTestView::OnKeyDown(UINTnChar,//键代码
UINTnRepCnt,//按键的重复次数
UINTnFlags)//扫描码、转换键码和按键组合状态{//TODO:在此添加消息处理程序代码和/或调用默认值CView::OnKeyDown(nChar,nRepCnt,nFlags);}nChar的一些特殊值含义VK_0~VK_90~9VK_A~VK_ZA~ZVK_F1~VK_F10F1~F10VK_CONTROLCTRLVK_DELETEDELETE例6-8键盘按下时显示按键值(1)创建单文档程序框架。程序起名KeyTest。(2)引入GDI+资源,详见例6-2。(3)添加和编辑消息处理函数为记录键盘值,在视图类增加一个CString数据成员classCKeyTestView:publicCView{……
//特性public:CKeyTestDoc*GetDocument()const;CStringm_sStr;
……}在类向导中对视图类添加WM_CHAR的消息响应函数OnChar()并对OnChar()添加代码:voidCKeyTestView::OnChar(UINTnChar,UINTnRepCnt,UINTnFlags){//TODO:在此添加消息处理程序代码和/或调用默认值
m_sStr.Format(_T(“%c”),nChar);//把信息按格式打印到CString里面,
//类似于printf()Invalidate();
CView::OnChar(nChar,nRepCnt,nFlags);}再修改OnDraw():voidCKeyTestView::OnDraw(CDC*pDC){CKeyTestDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);if(!pDoc)return;//TODO:在此处为本机数据添加绘制代码HDChdc=::GetDC(m_hWnd);Gdiplus::Graphicsgraphics(hdc);FontFamilyfontFamily(L"宋体");Gdiplus::Fontfont(&fontFamily,100,FontStyleRegular,UnitPixel);SolidBrushbrush(Color(255,0,0,0));//绘制字体graphics.DrawString(m_sStr,-1,&font,PointF(10,10),&brush);}OK!作业从网上任找一个图标,用画笔Pen和画刷Brush绘制,要求用鼠标点击确定图标的中心,即鼠标任点客户区一下,在该位置画图。注意屏幕坐标y轴是向下的。第5节菜单菜单资源编辑菜单响应函数5.1菜单资源编辑在资源视图里双击调出主菜单资源可在菜单资源中添加、删除、修改菜单和菜单项标题中的&在显示时会成为下划线,&后面的字母则成为快捷键,可用ALT加上该键快捷访问。5.2菜单响应函数每个菜单项都有ID,在类向导中可以找到该ID,为其添加消息响应函数voidCKeyTestView::OnMyMenu(){//TODO:在此添加新代码}例6-9点击菜单显示四人电话信息(1)创建单文档程序框架。程序起名MenuTelNote(2)引入GDI+资源。按下图编辑菜单在属性窗口对各菜单ID进行如下修改,以便记忆和识别菜单项ID张三ID_TEL_ZHANG李四ID_TEL_LI王五ID_TEL_WANG马六ID_TEL_MA(3)添加和编辑消息响应函数在视图类(MenuTelNoteView.h)增加一个字符串成员变量:classCMenuTelNoteView:publicCView{……//特性public:CMenuTelNoteDoc*GetDocument()const;
CStringm_sTelInfo;……}修改OnDraw()函数voidCMenuTelNoteView::OnDraw(CDC*pDC){……//TODO:在此处为本机数据添加绘制代码HDChdc=::GetDC(m_hWnd);Gdiplus::Graphicsgraphics(hdc);FontFamilyfontFamily(L"宋体");Gdiplus::Fontfont(&fontFamily,100,FontStyleRegular,UnitPixel);SolidBrushbrush(Color(255,0,0,0));//绘制字体graphics.DrawString(m_sTelInfo,-1,&font,PointF(20,20),&brush);}在类向导里为四个菜单项添加消息响应函数在四个菜单响应函数中增加代码:voidCMenuTelNoteView::OnTelZhang(){//TODO:在此添加命令处理程序代码m_sTelInfo=_T("张三);Invalidate();}voidCMenuTelNoteView::OnTelLi(){//TODO:在此添加命令处理程序代码m_sTelInfo=_T("李四);Invalidate();}voidCMenuTelNoteView::OnTelWang(){//TODO:在此添加命令处理程序代码
m_sTelInfo=_T("王五);Invalidate();}voidCMenuTelNoteView::OnTelMa(){//TODO:在此添加命令处理程序代码
m_sTelInfo=_T("马六);Invalidate();}OK!*第6节工具栏工具栏绘制工具栏消息响应6.1工具栏绘制在资源视图中,双击Toolbar—IDR_MAINFRAIN可以打开主工具栏进行编辑也可以通过新建资源新建一个工具栏6.2工具栏消息响应在属性窗口中修改其ID,若ID与某个菜单项ID相同,则该工具栏按钮与该菜单项共用同一个消息响应函数若工具栏按钮的ID为新的ID,则可以在类向导里对其添加消息响应函数。方法与添加菜单响应函数相同。例:修改菜单电话本程序,每个电话菜单对应一个工具栏(1)打开上一节的菜单电话本程序(2)编辑工具栏在资源视图中双击Toolbar--IDR_MAINFRAIN,打开主工具栏进行编辑在主工具栏后面新画上四个按钮(可以直接画,也可以从其他绘图软件中复制过来)修改四个工具栏的ID,使其与四个菜单项ID相同。这样四个菜单响应函数就同时成为四个工具栏按钮的响应函数编译运行。
OK!工具栏按钮ID3ID_TEL_ZHANG4ID_TEL_LI5ID_TEL_WANG6ID_TEL_MA第7节对话框自定义对话框模态与非模态通用对话框7.1自定义对话框可以像第六章那样设计对话框资源,并在视图文档程序中使用。这种自己设计的对话框称为“自定义对话框”。对于一些常用的对话框,如文件对话框、颜色对话框、字体对话框、查找/替换对话框、打印对话框、页面设置对话框,MFC已经对他们设计好资源和写好类。程序员可以直接使用。这些对话框称为“通用对话框”。7.2模态与非模态无论是自定义对话框还是通用对话框,都可以有两种使用方式:模态方式用户想要对对话框以外的应用程序进行操作时,必须首先对该对话框进行响应。即对话框出现时,用户除了可以对对话框进行操作,对程序的其他内容暂时无法操作。以模态方式使用的对话框也称为“模态对话框”。
模态对话框使用DoModal()函数来弹出对话框。非模态方式用户在对话框弹出时,用户即可对对话框进行操作,也可以对程序的其他内容进行操作。以非模态方式使用的对话框也称为“非模态对话框”。
非模态对话框需先用Create()创建,在用ShowWindow()显示。例6-10使用模态对话框输入6门课分数,并在视图上显示平均分(1)新建文档视图程序框架。
程序起名为AvrModal(2)编辑资源<1>编辑对话框资源在资源视图中新建一个对话框,按图放置好控件修改对话框控件的属性。按下表修改各控件ID。为对话框添加类。类名起名为ScoreInputDlg。然后在类
视图中可看到ScoreInputDlg
类(若看不见请重启一下VS)控件ID高等数学文本框IDC_EDT_MATH线型代数文本框IDC_EDT_ALGEBRA大学英语文本框IDC_EDT_ENGLISH大学物理文本框IDC_EDT_PHYSICS程序设计文本框IDC_EDT_PROGRAM在类向导里为对话框的控件添加变量
完成后在对话框类
头文件中可看到新
增的成员变量public:intm_nEnglish;intm_nAlgebra;intm_nMath;intm_nPhysics;intm_nProgram;<2>编辑菜单资源从资源视图里打开主菜单,添加一个菜单项“成绩输入”在属性窗口修改其ID为“ID_EDIT_INPUT”(3)添加变量和消息响应函数在文档类添加一个记录平均分的成员变量classCAvrModalDoc:publicCDocument{……//特性public:doublem_dAverage;……}并在构造函数中初始化CAvrModalDoc::CAvrModalDoc()noexcept{//TODO:在此添加一次性构造代码
m_dAverage=0;}为菜单添加消息响应函数OnEditInput()为OnEditInput()添加代码:voidCAvrModalView::OnEditInput(){//TODO:在此添加命令处理程序代码
CAvrModalDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);ScoreInputDlgDlg;if(IDOK==Dlg.DoModal())//弹出模态对话框,并检查是否按了OK返回{pDoc->m_dAverage=(Dlg.m_nMath+Dlg.m_nAlgebra+Dlg.m_nEnglish+
Dlg.m_nPhysics+Dlg.m_nProgram)/5.0;}Invalidate();}virtualintDoModal()——以模态形式弹出对话框返回值:IDOK
——用户点击了OK(确定)按钮返回IDCANCEL——用户点击了Cancel(取消)按钮返回在视图类cpp文件前面添加头文件#include"AvrModalDoc.h"#include"AvrModalView.h"#include"ScoreInputDlg.h“修改OnDraw()函数voidCAvrModalView::OnDraw(CDC*pDC){CAvrModalDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);if(!pDoc)return;//TODO:在此处为本机数据添加绘制代码CStringsOut;sOut.Format(_T("平均分为:%.1f"),pDoc->m_dAverage);pDC->TextOutW(20,20,sOut);}OK!例6-11把例6-10改为非模态对话框打开例6-10工程,作如下修改:把ScoreInputDlg对象变成视图类的成员变量classCAvrNonModalView:publicCView{……//特性public:CAvrNonModalDoc*GetDocument()const;
ScoreInputDlgm_dlgInput;
……}在例6-10中,
ScoreInputDlg对象是菜单响应函数OnEditInput()的临时变量。使用模态对话框时,函数停在DoModal语句,等待对话框操作返回,没有问题。但若使用非模态对话框时,OnEditInput()不会等待而会立即返回。而当OnEditInput()结束时,其所有临时变量,包括对话框,都会被解除释放。所以用户只会看到对话框闪了一下,然后还来不及操作,对话框就不见了。因此,对话框对象不能作为临时变量,而要作为成员变量。视图类
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 公司租赁吊车合同范本
- 出租房委托转让协议书
- 厂内生产分包合同范本
- 农田劳务分包合同范本
- 代工装修设计合同范本
- 农村房屋互换协议合同
- 农资球阀销售合同范本
- 免除赡养义务协议合同
- 借调协议解除劳动合同
- 保管合同终止协议范本
- 2025年学条令条例心得体会范文
- 2025至2030全球及中国越野车散热风扇行业产业运行态势及投资规划深度研究报告
- AI赋能社会保障数字化转型升级可行性分析
- 2025黑龙江绥化市公安局招聘辅警104人考试参考试题及答案解析
- 小学二年级奥数思维训练100题
- 第六课週末は何をしますか语法课件-高中日语华东理工版新编日语教程1
- 棕熊奇遇自然启示
- 课堂评课标准及方法指导手册
- 慧蓓口服液课件
- DB44-T+2720-2025高速公路养护作业交通组织管理技术规范
- 幼儿园小班语言儿歌《秋妈妈与果娃娃》课件
评论
0/150
提交评论