null第2章 MFC基础与编程
第2章 MFC基础与编程方法Visual C++ 6.0开发平台
MFC类的组织结构
MFC向导的主要功能
MFC程序框架
Windows消息机制
Visual C++ 6.0平台(1)Visual C++ 6.0平台(1)编辑区工作区输出区Visual C++ 6.0平台(2)Visual C++ 6.0平台(2)ClassView面板
列出项目中的所有类
FileView面板
显示项目中的所有文件
ResourceView面板
显示项目中的所有资源,例如Bitmap、Cursor、 Dialog、Icon、Menu、Accelerator、String Table、Toolbar与Version等Visual C++ 6.0平台(3)Visual C++ 6.0平台(3)可创建的项目类型Visual C++ 6.0平台(4)Visual C++ 6.0平台(4)可创建的项目类型Visual C++ 6.0平台(5)Visual C++ 6.0平台(5)可创建的文件类型Visual C++ 6.0平台(6)Visual C++ 6.0平台(6)可创建的文件类型Visual C++ 6.0平台(7)Visual C++ 6.0平台(7)MFC ClassWizard程序调试与运行(1)程序调试与运行(1)编译(Compile)
链接(Link)
执行(Execute)
调试(Debug)工具按钮程序调试与运行(2)程序调试与运行(2)Debugger可以完成的工作:
设置断点
单步执行代码
监视变量、寄存器和内存
查看汇编代码和调用堆栈
修改代码和变量值程序调试与运行(3)程序调试与运行(3)Start Debug
Go
Step Into
Step Over
Step Out
Break Point程序调试与运行(4)程序调试与运行(4)例2-1项目的概念(1)项目的概念(1)项目(Project)由多个源、头文件组成,以及系统提供的函数支持,编译时有很多特殊选择,例如版本、优化、链接库等
项目内容存在项目文件中,由它对整个程序进行统一管理。不同版本文件后缀不同,Visual C++ 5.0以上为“.dsp”项目的概念(2)项目的概念(2)版本类型
Debug版本产生调试信息,便于程序调试与运行
Release版本不产生调试信息,代码简短且经过优化,程序执行效率较高项目的概念(3)项目的概念(3)Build菜单→Batch Build项目的概念(4)项目的概念(4)项目文件类型
*.dsp 项目中所有内容
*.dsw 工作区中所有项目
*.clw ClassWizard信息
*.rc 资源描述信息
Resource.h 所有资源符号定义
StdAfx.h和.cpp 建立预编译头文件
/res 各种资源存放的
MFC类的组织结构(1)MFC类的组织结构(1)MFC是C++语言的安全子集,也是一个应用程序框架,简化Windows编程难度
MFC类是以层次结构组织,封装大部分Windows API和控件
当前MFC版本包含100多个类,可实现应用程序的大部分功能MFC类的组织结构(2)MFC类的组织结构(2)根类(CObject)
应用程序结构类(CCmdTarget、CWinThread、 CWinApp、CDocument)
可视对象类(CWnd、CView、CMenu、CDialog、控件类、CControlBar、CGdiObject)
通用类(CFile、CException、CArray)根类与应用程序类(1)根类与应用程序类(1)根类CObject
CObject是MFC抽象基类,多数MFC类与用户自定义类的根类,提供编程所需的公共操作,例如对象建立与删除
应用程序类CWinApp
CWinApp是MFC应用程序基类,每个程序只有一个程序对象,该类是从CWinApp派生,提供程序相关操作,例如初始化、运行与终止根类与应用程序类(2)根类与应用程序类(2)CWinApp类的继承关系
CCmdTarget:MFC消息映射基类
CWinThread:MFC线程操作基类根类与应用程序类(3)根类与应用程序类(3)CWinApp类的公有成员函数根类与应用程序类(4)根类与应用程序类(4)文档与视图
文档对象由文档模板创建,管理应用程序的数据,包括文档创建、打开与保存
文档模板及基类:
CDocTemplate:文档模板基类
CSingleDocTemplate:SDI文档模板
CMultiDocTemplate:MDI文档模板
CDocument:专用文档基类可视对象类(1)可视对象类(1)窗口类CWnd
CWnd类是MFC窗口基类,实现不同类型窗口
CWnd派生类
CFrameWnd:单文档框架窗口类
CMIDFrameWnd:多文档主框架窗口类
CMIDChildWnd:多文档子框架窗口类可视对象类(2)可视对象类(2)视图类CView
CView类是MFC视图基类,实现框架窗口中的客户区可视对象类(3)可视对象类(3)CView派生类可视对象类(4)可视对象类(4)菜单类CMenu
CMenu类是MFC菜单类,实现菜单界面
对话框类CDialog
CFileDialog:文件存取对话框
CColorDialog:颜色选择对话框
CFontDialog:字体选择对话框
CPrintDialog:文件打印对话框
CFindReplaceDialog:文本查找对话框可视对象类(5)可视对象类(5)控件类可视对象类(6)可视对象类(6)控件条类CControlBar
CControlBar是控件栏基类,实现工具条、状态条与浮动对话框
CControlBar派生类
CStatusBar:状态条
CToolBar:带位图按钮的工具条
CDialogBar:控件条形式的浮动对话框可视对象类(7)可视对象类(7)绘图对象类CGdiObject
CGdiObject是GDI基类,实现绘图对象
CGdiObject派生类
CBitmap:位图操作接口
CBrush:画刷
CFont:字体
CPalette:调色板
CPen:画笔
CRgn:椭圆或多边型域可视对象类(8)可视对象类(8)设备描述环境类CDC
主要用来实现窗口绘制
CDC派生类
CPaintDC:绘图设备描述环境
CClientDC:客户区的设备描述环境
CWindowDC:窗口的设备描述环境
CMetaFileDC:元文件的设备描述环境通用类(1)通用类(1)文件类CFile
CFile类是文件访问基类,实现文件输入与输出操作
CFile派生类
CMemFile:驻内存文件访问接口
CStdioFile:缓存流式文件访问接口
CArchive类
CFile类通常由CArchive间接访问通用类(2)通用类(2)异常类CException
CNotSupportException:不支持异常
CMemoryException:内存异常
CFileException:文件异常
CResourceException:资源异常
COleException:OLE异常
CDBException:数据库异常
CUserException:用户操作异常通用类(3)通用类(3)模板收集类
CArray:将数据存储到数组
CList:将数据存储到链
CMap:关键字与数据的映射OLE类OLE类OLE是对象链接与嵌入,对象服务体系结构
普通类:COleDocument、COleItem
客户类:COleClientDoc、COleClientItem
服务类:COleServer、COleTemplate
可视编辑容器类:COleLinkingDoc
数据传输类:COleDropSource、COleTarget、COleDataSource、COleDataObject
对话类:COleInsertDialogODBC类ODBC类ODBC类是MFC数据库访问类,可访问支持ODBC的数据库系统,完成查询、更新等操作
CDatabase:连接数据源
CRecordset:数据源的一组记录
CRecordView:记录的表单视图
CFieldExchange:支持记录字段交换
CLongBinary:存储二进制对象句柄MFC全局函数MFC全局函数以Afx为前缀的函数MFC向导功能(1)MFC向导功能(1)第1步:应用程序类型 第2步:数据库支持例2-2MFC向导功能(2)MFC向导功能(2)第3步:OLE与ActiveX 第4步:用户界面MFC向导功能(3)MFC向导功能(3)第5步:应用程序风格 第6步:MFC类选择MFC向导功能(4)MFC向导功能(4)Single Document
No Database
No OLE
Tool Bar
Status Bar
System Button MFC程序框架分析(1)MFC程序框架分析(1)Windows程序核心是CWinApp例2-3MFC程序框架分析(2)MFC程序框架分析(2)Test.cpp
CTestApp theApp
BOOL CTestApp::InitInstance()
WinMain.cpp
pThread->InitInstance()
nReturnCode=pThread->Run()
AfxWinTerm()MFC程序框架分析(3)MFC程序框架分析(3)MFC程序框架分析(4)MFC程序框架分析(4)每次启动新的应用程序,WinMain函数都调用InitInstance()
创建并注册文档模板 CSingleDocTemplate* pDocTemplate;
pDocTemplate=new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CTestView));
AddDocTemplate(pDocTemplate);MFC程序框架分析(5)MFC程序框架分析(5)装载标准文件选项
创建主边框窗口 CMainFrame* pMainFrame=new CMainFrame;
if(!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd=pMainFrame;pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();MFC程序框架分析(6)MFC程序框架分析(6)InitInstance():初始化应用程序
Run():启动消息循环
OnIdle():空闲处理
ExitInstance():终止应用程序文档模板(1)文档模板(1)文档模板用于存放与文档、视图和边框窗口相关的信息
CSingleDocTemplate 单文档模板
CMultiDocTemplate 多文档模板
传递给C*DocTemplate的资源符号串,包括7个参数,每个参数用\n隔开,用GetDocString可获得每个参数文档模板(2)文档模板(2)资源符号串窗口类与窗口对象窗口类与窗口对象消息的概念消息的概念消息处理机制是Windows核心,它是应用程序运行的动力来源
消息是系统定义的32位值,它唯一定义一个事件,向Windows系统发出一个通知,告诉应用程序某个事件发生消息循环消息循环PeekMessage:查看消息队列,只起检测作用
GetMessage:查看消息队列,将消息移走
PreTranslateMessage:TranslateMessage的预处理函数
TranslateMessage:将虚拟键转化为字符码,例如Shift+8→*
DispatchMessage:消息分发到消息处理函数消息映射表消息映射表//TestView.h
class CTestView : public CView
{ protected:
//{{AFX_MSG(CTestView)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnEditPaste();
//}}AFX_MSG
DECLARE_MESSAGE_MAP() };
//TestView.cpp
BEGIN_MESSAGE_MAP(CTestView, CView)
//{{AFX_MSG_MAP(CTestView)
ON_WM_LBUTTONDOWN()
ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()消息控制机制(1)消息控制机制(1)在CTestView::OnDraw()中例2-4 pDC->TextOut(20,20,"Hello World!");
pDC->SelectStockObject(GRAY_BRUSH);
pDC->Ellipse(20,50,100,130);消息控制机制(2)消息控制机制(2)鼠标控制消息
CDC *pDC=GetDC();
pDC->TextOut(point.x,point.y,"Mouse Clicked!");
ReleaseDC(pDC);消息控制机制(3)消息控制机制(3)鼠标控制消息
CClientDC cDC(this);
cDC.TextOut(point.x,point.y,"Mouse Clicked!");消息控制机制(4)消息控制机制(4)菜单控制消息 CDC *pDC=GetDC();
pDC->TextOut(20,120,"Menu Clicked!");
ReleaseDC(pDC);趣味性例子(1)趣味性例子(1)绘制一片绿色的叶子例2-5趣味性例子(2)趣味性例子(2)void CMyTreeView::OnDraw(CDC* pDC)
{
int nTotalPoints=32000; //打印nTotalPoints个点
CRect rect;
GetClientRect(&rect);
int nX=rect.right/2; //(nX,nY)记录树的根坐标
int nY=rect.bottom*5/6;
int nScale=(rect.right>rect.bottom?rect.bottom:rect.right)/15;
COLORREF crColor=0x00FF00;
double dX=0, dY=0;
double dP;
for(int i=0;i
0.01 && dP<=0.86)
{
dX=0.85*dX+0.04*dY;
dY=-0.04*dX+0.85*dY+1.60;
}
if(dP>0.86 && dP<=0.93)
{
dX=0.20*dX-0.26*dY;
dY=0.44*dX+0.12*dY+1.60;
}
if(dP>0.93)
{
dX=-0.20*dX+0.26*dY;
dY=0.44*dX+0.12*dY+1.00;
}
pDC->SetPixel(nX+int(dX*nScale),nY-int(dY*nScale),crColor);
}
}消息的种类(1)消息的种类(1)Windows系统将各种事件以消息形式发送给目标,目标根据消息内容进行处理
目标窗口
消息类型
参数wParam
参数lParam消息的种类(2)消息的种类(2)标准Windows消息
窗口消息(WM_CREATE、WM_PAINT等)、鼠标消息(WM_LBUTTONDOWN、WM_MOUSEMOVE等)、键盘消息(WM_KEYDOWN、WM_CHAR等)、WM_TIMER
控件消息
从控件传送给父窗口的消息
命令消息
用户界面对象(包括菜单、工具栏、加速键等)的WM_COMMAND消息消息处理过程(1)消息处理过程(1)标准Windows消息不通过命令目标链,由发送消息的窗口处理,处理函数在相应类中定义,通过AFX_MSG区分//{{AFX_MSG(CTestView)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg void OnLButtonDown(UINT nFlags,CPoint point);
//}}AFX_MSG消息处理过程(2)消息处理过程(2)WM_COMMAND能被更多的对象处理,包括应用程序、窗口、文档与视图等
命令消息通过命令目标链发送,每个目标都检查自己的消息映射,决定能否处理消息
命令目标链发送顺序:当前活动的子目标、自己、其它目标消息处理过程(3)消息处理过程(3)命令处理顺序窗口消息(1)窗口消息(1)WM_CREATE消息
当窗口对象生成后,系统发送WM_CREATE,完成窗口的初始化
WM_DESTROY消息
当应用程序退出时,系统发送WM_DESTROY,完成某些收尾工作
WM_PAINT消息
当窗口发生变化时,系统发送WM_PAINT,重绘窗口并显示数据窗口消息(2)窗口消息(2)添加WM_CREATE消息
ClassWizard→Message Maps→CTestView →WM_CREATE→Add Function
编写WM_CREATE的响应函数
CTestView::OnCreate()中
MessageBox("完成窗口初始化!");
添加WM_DESTROY消息
CTestView::OnDestory()中
MessageBox("完成窗口销毁!");例2-6窗口消息(3)窗口消息(3)窗口消息(4)窗口消息(4)在CTestView类定义中
在CTestView构造函数中
在CTestView::OnDraw()中m_Num=0; //初始化private: int m_Num;m_Num++;
CString str;
str.Format("窗口重绘次数:%d",m_Num);
pDC->TextOut(0,0,str);
pDC->SelectStockObject(GRAY_BRUSH);
pDC->Ellipse(0,20,200,220);窗口消息(5)窗口消息(5)WM_PAINT→CTestView消息循环→CView消息循环→CView::OnPaint()→CView::OnDraw()鼠标消息(1)鼠标消息(1)当用户对鼠标进行操作时,会产生对应的消息,系统将消息发送给对应窗口
鼠标消息主要包括:
WM_MOUSEMOVE 鼠标移动
WM_LBUTTONDOWN 鼠标左键按下
WM_RBUTTONDOWN 鼠标右键按下
WM_LBUTTONUP 鼠标左键释放
WM_RBUTTONUP 鼠标右键释放
WM_LBUTTONDBLCLK 鼠标左键双击鼠标消息(2)鼠标消息(2)鼠标消息处理函数的参数:nFlag和point
nFlag表示鼠标按钮状态,鼠标事件发生时的键盘某些键状态,每位由nFlag相应位表示
MK_CONTROL、MK_SHIFT、MK_LBUTTON、MK_MBUTTON、MK_RBUTTON
point表示鼠标事件发生时的光标位置鼠标消息(3)鼠标消息(3)在CTestView::OnLButtonDown()中
窗口最小化,然后最大化。哪些信息保留,哪些信息消失?为什么?如何保留最后一次鼠标单击信息?例2-7 CDC *pDC=GetDC();
pDC->TextOut(point.x,point.y,"Mouse Clicked!");
ReleaseDC(pDC);鼠标消息(4)鼠标消息(4)在CTestView类定义中
在CTestView::CTestView()中private:
CPoint m_Pos;
CString m_Des;m_Pos=CPoint(0,0);
m_Des.Empty();鼠标消息(5)鼠标消息(5)在CTestView::OnLButtonDown()中
在CTestView::OnDraw()中m_Pos=point;
if(nFlags & MK_CONTROL)
m_Des="CTRL+单击鼠标左键";
else
m_Des="单击鼠标左键";
Invalidate(true);pDC->TextOut(m_Pos.x,m_Pos.y,m_Des);鼠标消息(6)鼠标消息(6)窗口重绘的结果键盘消息(1)键盘消息(1)用户对键盘进行操作,产生相应的键盘消息,系统将消息发送给相应窗口
键盘消息主要包括:
WM_KEYDOWN:键盘按下
WM_KEYUP:键盘弹起
WM_CHAR:输入一个字符键盘消息(2)键盘消息(2)在CTestView::OnChar()中void CTestView::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
CString str;
str.Format("按下%c键!",nChar);
MessageBox(str,"键盘按键");
}例2-8键盘消息(3)键盘消息(3)特殊键处理,例如F1、F2、↑、↓等BOOL CTestView::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message==WM_KEYDOWN)
{
if(pMsg->wParam==VK_F1)
MessageBox("按下F1键");
if(pMsg->wParam==VK_UP)
MessageBox("按下↑键");
}
}菜单与工具栏消息(1)菜单与工具栏消息(1)添加菜单消息
ResourceView→Menu→IDR_MAINFRAME
一级菜单项MyMenu→二级菜单项Execute (ID_EXECUTE)
一级菜单项MyMenu→二级菜单项Font (ID_FONT)
在CTestView::OnExecute()中
MessageBox("菜单创建成功!");例2-9菜单与工具栏消息(2)菜单与工具栏消息(2)添加工具栏消息
ResourceView→ToolBar→IDR_MAINFRAME
添加按钮(ID_COLOR)
在CTestView::OnColor()中CColorDialog Dlg;
Dlg.DoModal();WM_TIMER消息(1)WM_TIMER消息(1)WM_TIMER消息是一种计时器消息
通过SetTimer()函数设置时钟,当预定的时间到达,系统产生WM_TIMER消息,并通过参数表明是哪个时钟
用户用于进行周期性处理WM_TIMER消息(2)WM_TIMER消息(2)WM_CREATE消息,在OnCreate()中
SetTimer(1,2000,NULL); //设置计时器,ID号为1,间隔2000ms,消息处理函数默认
WM_TIMER消息,在OnTimer()中
if(nIDEvent==1) ……
WM_DESTROY消息,在OnDestroy()中
KillTimer(1); //清除计时器1简单动画程序设计简单动画程序设计使用WM_TIMER消息
异或方式制作动画:SetROP2(R2_XORPEN)例2-10其他消息(1)其他消息(1)有些消息不常出现,ClassWizard中没有封装,因此找不到相应消息,但系统确实存在该消息,需要手工处理消息
典型的是热键消息WM_HOTKEY。用户可以定义一个热键,不论是前台或后台程序,只要用户按这个热键,程序立即切换到前台,并收到一个热键消息,参数表明哪个热键按下其他消息(2)其他消息(2)在CTestView类定义中
void OnHotkey(WPARAM wParam,LPARAM lParam);
在CTestView类中
ON_MESSAGE(WM_HOTKEY,OnHotkey)
在CTestView::OnCreate()中RegisterHotKey(m_hWnd,1001,MOD_CONTROL|MOD_ALT,'z');
RegisterHotKey(m_hWnd,1002,MOD_CONTROL|MOD_ALT,'Z');其他消息(3)其他消息(3)在CTestView::OnHotkey()中
在CTestView::OnDestroy()中if(wParam==1001||wParam==1002)
MessageBox("接收热键消息!");UnregisterHotKey(m_hWnd,1001);
UnregisterHotKey(m_hWnd,1002);自定义消息(1)自定义消息(1)用户有时需要定义内部消息,以区别系统定义的消息,完成用户自定义的处理
这些消息是用户定义,系统不知道消息存在,通过PostMessage()或SendMessage()发送
消息是一个整数,系统已使用一部分。小于WM_USER的整数保留,大于的供用户使用
用户自定义消息的方式
#define WM_MYMESSAGE WM_USER+N自定义消息(2)自定义消息(2)自定义消息的操作步骤
定义自己的窗口消息
在适当位置声明消息处理函数
将消息处理函数与消息对应
实现消息处理函数
向发送消息者提供窗口句柄自定义消息(3)自定义消息(3)声明用户自定义消息
#define WM_MYMESSAGE WM_USER+1
在CTestView类定义中
void OnMyMessage(WPARAM wParam,LPARAM lParam);
在CTestView类中,建立消息映射关系ON_MESSAGE(WM_MYMESSAGE,OnMyMessage)例2-11自定义消息(4)自定义消息(4)在CTestView::OnMyMessage()中void CTestView::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
CString str;
str.Format("消息参数%d和%d",wParam,lParam);
MessageBox(str);
}自定义消息(5)自定义消息(5)在CTestView::OnLButtonUp()中
PostMessage(WM_MYMESSAGE,1,2);
在CTestView::OnChar()中
SendMessage(WM_MYMESSAGE,3,4);有趣的分形理论(1)有趣的分形理论(1)分形理论建立于20世纪70年代末,它的出现震惊科学界,被列入20项重大科学发现
在欧几里得几何学无能为力的领域,分形理论脱颖而出。分形是对没有特征长度、具有一定意义的自相似图形或结构的总称例2-12有趣的分形理论(2)有趣的分形理论(2)void CTestView::OnDraw(CDC* pDC)
{
CRect rect; this->GetClientRect(&rect);
int iOx = rect.right/2; int iOy = rect.bottom/2;
int iWidth = rect.right-rect.left;
int iHeight = rect.bottom-rect.top;
int iR = (iWidth > iHeight ? iHeight : iWidth)/3;
CString str;
str.Format("单文档,View(%d,%d,%d,%d)",rect.left,rect.top,rect.right,rect.bottom);
pDC->TextOut(0,0, str);
pDC->Ellipse(iOx-iR, iOy-iR, iOx+iR, iOy+iR);
pDC->SetPixel(iOx, iOy, 0x000000);
CPoint A, B, C, D, E;
A.x = iOx; A.y = iOy-iR;
B.x = int(iOx + iR*cos(c_dPi/10)); B.y = int(iOy-iR*sin(c_dPi/10));
C.x = int(iOx + iR*cos(3*c_dPi/10)); C.y = int(iOy+iR*sin(3*c_dPi/10));
D.x = int(iOx - iR*cos(3*c_dPi/10)); D.y = int(iOy+iR*sin(3*c_dPi/10));
E.x = int(iOx - iR*cos(c_dPi/10)); E.y = int(iOy-iR*sin(c_dPi/10));
pDC->MoveTo(A); pDC->LineTo(C); pDC->LineTo(E);
pDC->LineTo(B); pDC->LineTo(D); pDC->LineTo(A);
}有趣的分形理论(3)有趣的分形理论(3)void CTestView::OnDraw(CDC* pDC)
{
m_pDC=pDC;
CRect rect;
this->GetClientRect(&rect);
int iOx=rect.right/2; int iOy=rect.bottom/2;
DrawRect(iOx, iOy, (iOx>iOy?iOy:iOx)/3);
}
void CTestView::DrawRect(int iX, int iY, int iR)
{
if(iR>0)
{
DrawRect(iX-iR, iY+iR, iR/2); DrawRect(iX+iR, iY+iR, iR/2);
DrawRect(iX-iR, iY-iR, iR/2); DrawRect(iX+iR, iY-iR, iR/2);
m_pDC->Rectangle(iX-iR, iY-iR, iX+iR, iY+iR);
}
}第2次作业第2次作业编程实现键盘鼠标测试程序,满足以下要求:
按下键盘任意键,屏幕显示按键信息
单击鼠标左键,屏幕显示鼠标信息
假设鼠标右键失灵,用Ctrl+鼠标左键代替
自定义WM_MY_MESSAGE消息,带50和100两个参数,由“?”键激活,屏幕显示相应信息
编程实现SmallBall程序谢谢大家谢谢大家