深入浅出MFC笔记.docx
《深入浅出MFC笔记.docx》由会员分享,可在线阅读,更多相关《深入浅出MFC笔记.docx(30页珍藏版)》请在冰点文库上搜索。
深入浅出MFC笔记
深入浅出MFC笔记
用AppWizard产生一个MDI工程T(无OLE等支持),AppWizard创建了一系列文件,构成了一个应用程序框架。
这些文件分四类:
头文件(.h),实现文件(.cpp),资源文件(.rc),模块定义文件(.def),等。
构成应用程序的对象
图1-1解释了该应用程序的结构,箭头表示信息流向。
从CWinApp、CDocument、CView、CMDIFrameWnd、CMDIChildWnd类对应地派生出CTApp、CTDoc、CTView、CMainFrame、CChildFrame五个类,这五个类的实例分别是应用程序对象、文档对象、视对象、主框架窗口对象和文档边框窗口对象。
主框架窗口包含了视窗口、工具条和状态栏。
表1-1AppWizard所生成的头文件
头文件
用途
stdafx.h
标准AFX头文件
resource.h
定义了各种资源ID
t.h
#include"resource.h"
定义了从CWinApp派生的应用程序对象CTApp
childfrm.h
定义了从CMDIChildWnd派生的文档框架窗口对象CTChildFrame
mainfrm.h
定义了从CMDIFrameWnd派生的框架窗口对象CMainFrame
tdoc.h
定义了从CDocument派生的文档对象CTDoc
tview.h
定义了从CView派生的视图对象CTView
表1-2AppWizard所生成的实现文件
实现文件
所包含的头文件
实现的内容和功能
stdafx.cpp
#include"stdafx.h"
用来产生预编译的类型信息。
t.cpp
#include"stdafx.h"
#include"t.h"
#include"MainFrm.h"
#include"childfrm.h"
#include"tdoc.h"
#include"tview.h"
定义CTApp的实现,并定义CTApp类型的全局变量theApp。
childfrm.cpp
#inlcude"stdafx.h"
#include"t.h"
#include“childfrm.h”
实现了类CChildFrame
childfrm.cpp
#inlcude"stdafx.h"
#include"t.h"
#include"childfrm.h"
实现了类CMainFrame
tdoc.cpp
#include"stdafx.h"
#include"t.h"
#include"tdoc.h"
实现了类CTDoc
tview.cpp
#include"stdafx.h"
#include"t.h"
#include"tdoc.h"
#include"tview.h"
实现了类CTview
从表1-2中的包含关系一栏可以看出:
CTApp的实现用到所有的用户定义对象,包含了他们的定义;CView的实现用到CTdoc;其他对象的实现只涉及自己的定义;
构成应用程序的对象之间的关系
图1-2所示的类都是从CObject类派生出来的;所有处理消息的类都是从CCmdTarget类派生的。
如果是多文档应用程序,文档模板使用CMultiDocTemplae,主框架窗口从CMdiFarmeWnd派生,它包含工具条、状态栏和文档框架窗口。
文档框架窗口从CMdiChildWnd派生,文档框架窗口包含视,视从CView或其派生类派生。
表2-1MFCObject和WindowsObject的对应关系
描述
Windows句柄
MFCObject
窗口
HWND
CWndandCWnd-derivedclasses
设备上下文
HDC
CDCandCDC-derivedclasses
菜单
HMENU
CMenu
笔
HPEN
CGdiObject类,CPen和CPen-derivedclasses
刷子
HBRUSH
CGdiObject类,CBrush和CBrush-derivedclasses
字体
HFONT
CGdiObject类,CFont和CFont-derivedclasses
位图
HBITMAP
CGdiObject类,CBitmap和CBitmap-derivedclasses
调色板
HPALETTE
CGdiObject类,CPalette和CPalette-derivedclasses
区域
HRGN
CGdiObject类,CRgn和CRgn-derivedclasses
图像列表
HimageLIST
CimageList和CimageList-derivedclasses
套接字
SOCKET
CSocket,CAsynSocket及其派生类
表2-1中的OBJECT分以下几类:
1.Windows对象,
2.设备上下文对象,
3.GDI对象(BITMAP,BRUSH,FONT,PALETTE,PEN,RGN),
4.菜单,
5.图像列表,
6.网络套接字接口
MFC窗口类CWnd
(1)窗口创建函数:
主要讨论函数Create和CreateEx。
它们封装了Win32窗口创建函数:
:
CreateWindowEx。
Create的原型如下:
BOOLCWnd:
:
Create(LPCTSTRlpszClassName,
LPCTSTRlpszWindowName,DWORDdwStyle,
constRECT&rect,
CWnd*pParentWnd,UINTnID,
CCreateContext*pContext)
Create是一个虚拟函数,用来创建子窗口(不能创建桌面窗口和POPUP窗口)。
CWnd的基类可以覆盖该函数,例如边框窗口类等覆盖了该函数以实现边框窗口的创建,视类则使用它来创建视窗口。
Create调用了成员函数CreateEx。
CWnd:
:
CreateEx的原型如下:
BOOLCWnd:
:
CreateEx(DWORDdwExStyle,LPCTSTRlpszClassName,
LPCTSTRlpszWindowName,DWORDdwStyle,
intx,inty,intnWidth,intnHeight,
HWNDhWndParent,HMENUnIDorHMenu,LPVOIDlpParam)
CreateEx有11个参数,它将调用:
:
CreateWindowEx完成窗口的创建,这11个参数对应地传递给:
:
CreateWindowEx。
参数指定了窗口扩展风格、“窗口类”、窗口名、窗口大小和位置、父窗口句柄、窗口菜单和窗口创建参数。
2)窗口销毁函数
例如:
DestroyWindow函数销毁窗口
PostNcDestroy(),销毁窗口后调用,虚拟函数
3)用于设定、获取、改变窗口属性的函数,例如:
SetWindowText(CStringtiltle)设置窗口标题
GetWindowText()得到窗口标题
SetIcon(HICONhIcon,BOOLbBigIcon);设置窗口像标
GetIcon(BOOLbBigIcon);得到窗口像标
GetDlgItem(intnID);得到窗口类指定ID的控制子窗口
GetDC();得到窗口的设备上下文
SetMenu(CMenu*pMenu);设置窗口菜单
GetMenu();得到窗口菜单
…
4)用于完成窗口动作的函数
用于更新窗口,滚动窗口,等等。
一部分成员函数设计成或可重载(Overloaded)函数,或虚拟(Overridden)函数,或MFC消息处理函数。
这些函数或者实现了一部分功能,或者仅仅是一个空函数。
如:
∙有关消息发送的函数:
SendMessage(UINTmessage,WPARAMwParam=0,LPARAMlParam=0);
给窗口发送发送消息,立即调用方式
PostMessage((UINTmessage,WPARAMwParam=0,LPARAMlParam=0);
给窗口发送消息,放进消息队列
…
∙有关改变窗口状态的函数
MoveWindow(LPCRECTlpRect,BOOLbRepaint=TRUE);
移动窗口到指定位置
ShowWindow(BOOL);显示窗口,使之可见或不可见
….
∙实现MFC消息处理机制的函数:
virtualLRESULTWindowProc(UINTmessage,WPARAMwParam,LPARAMlParam);窗口过程,虚拟函数
virtualBOOLOnCommand(WPARAMwParam,LPARAMlParam);处理命令消息
…
∙消息处理函数:
OnCreate(LPCREATESTRUCTlpCreateStruct);MFC窗口消息处理函数,窗口创建时由MFC框架调用
OnClose();MFC窗口消息处理函数,窗口创建时由MFC框架调用
…
∙其他功能的函数
CWnd的导出类是类型更具体、功能更完善的窗口类,它们继承了CWnd的属性和方法,并提供了新的成员函数(消息处理函数、虚拟函数、等等)。
在MFC下创建一个窗口对象
MFC下创建一个窗口对象分两步,首先创建MFC窗口对象,然后创建对应的Windows窗口。
在内存使用上,MFC窗口对象可以在栈或者堆(使用new创建)中创建。
具体表述如下:
∙创建MFC窗口对象。
通过定义一个CWnd或其派生类的实例变量或者动态创建一个MFC窗口的实例,前者在栈空间创建一个MFC窗口对象,后者在堆空间创建一个MFC窗口对象。
∙调用相应的窗口创建函数,创建Windows窗口对象。
例如:
在前面提到的AppWizard产生的源码中,有CMainFrame(派生于CMDIFrame(SDI)或者CMDIFrameWnd(MDI))类。
它有两个成员变量定义如下:
CToolBarm_wndToolBar;
CStatusBarm_wndStatusBar;
当创建CMainFrame类对象时,上面两个MFCObject也被构造。
CMainFrame还有一个成员函数
OnCreate(LPCREATESTRUCTlpCreateStruct),
它的实现包含如下一段代码,调用CToolBar和CStatusBar的成员函数Create来创建上述两个MFC对象对应的工具栏HWND窗口和状态栏HWND窗口:
intCMainFrame:
:
OnCreate(LPCREATESTRUCTlpCreateStruct)
{
…
if(!
m_wndToolBar.Create(this)||
!
m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failedtocreatetoolbar\n");
return-1;//failtocreate
}
if(!
m_wndStatusBar.Create(this)||
!
m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failedtocreatestatusbar\n");
return-1;//failtocreate
}
…
}
在Windows窗口的创建过程中,将发送一些消息,如:
在创建了窗口的非客户区(Nonclientarea)之后,发送消息WM_NCCREATE;
在创建了窗口的客户区(clientarea)之后,发送消息WM_CREATE;
窗口的窗口过程在窗口显示之前收到这两个消息。
如果是子窗口,在发送了上述两个消息之后,还给父窗口发送WM_PARENATNOTIFY消息。
其他类或风格的窗口可能发送更多的消息,具体参见SDK开发文档
在MFC下窗口的销毁
窗口对象使用完毕,应该销毁。
在MFC下,一个窗口对象的销毁包括HWND窗口对象的销毁和MFC窗口对象的销毁。
一般情况下,MFC编程框架自动地处理了这些。
(1)对CFrameWnd和CView的派生类
这些窗口的关闭导致销毁窗口的函数DestroyWindow被调用。
销毁Windows窗口时,MFC框架调用的最后一个成员函数是OnNcDestroy函数,该函数负责Windows清理工作,并在最后调用虚拟成员函数PostNcDestroy。
CFrameWnd和CView的PostNcDestroy调用deletethis删除自身这个MFC窗口对象。
所以,对这些窗口,如前所述,应在堆(Heap)中分配,而且,不要对这些对象使用delete操作。
(2)对WindowsControl窗口
在它们的析构函数中,将调用DestroyWidnow来销毁窗口。
如果在栈中分配这样的窗口对象,则在超出作用范围的时候,随着析构函数的调用,MFC窗口对象和它的Windowswindow对象都被销毁。
如果在堆(Heap)中分配,则显式调用delete操作符,导致析构函数的调用和窗口的销毁。
所以,这种类型的窗口应尽可能在栈中分配,避免用额外的代码来销毁窗口。
如前所述的CMainFrame的成员变量m_wndStatusBar和m_wndToolBar就是这样的例子。
(3)对于程序员直接从CWnd派生的窗口
程序员可以在派生类中实现上述两种机制之一,然后,在相应的规范下使用。
设备描述表
设备描述表概述:
当一个应用程序使用GDI函数时,必须先装入特定的设备驱动程序,然后为绘制窗口准备设备描述表,比如指定线的宽度和颜色、刷子的样式和颜色、字体、剪裁区域等等。
不像其他Win32结构,设备描述表不能被直接访问,只能通过系列Win32函数来间接地操作。
如同Windows“窗口类”一样,设备描述表也是一种Windows数据结构,用来描述绘制窗口所需要的信息。
它定义了一个坐标映射模式、一组GDI图形对象及其属性。
这些GDI对象包括用于画线的笔,绘图、填图的刷子,位图,调色板,剪裁区域,及路径(Path)。
表2-2列出了设备描述表的结构和各项缺省值,表2-3列出了设备描述表的类型,表2-4显示设备描述表的类型。
表2-2设备描述表的结构
属性
缺省值
Backgroundcolor
BackgroundcolorsettingfromWindowsControlPanel(typically,white)
Backgroundmode
OPAQUE
Bitmap
None
Brush
WHITE_BRUSH
Brushorigin
(0,0)
Clippingregion
Entirewindoworclientareawiththeupdateregionclipped,asappropriate.Childandpop-upwindowsintheclientareamayalsobeclipped
Palette
DEFAULT_PALETTE
Currentpenposition
(0,0)
Deviceorigin
Upperleftcornerofthewindowortheclientarea
Drawingmode
R2_COPYPEN
Font
SYSTEM_FONT(SYSTEM_FIXED_FONTforapplicationswrittentorunwithWindowsversions3.0andearlier)
Intercharacterspacing
0
Mappingmode
MM_TEXT
Pen
BLACK_PEN
Polygon-fillmode
ALTERNATE
Stretchmode
BLACKONWHITE
Textcolor
TextcolorsettingfromControlPanel(typically,black)
Viewportextent
(1,1)
Viewportorigin
(0,0)
Windowextent
(1,1)
Windoworigin
(0,0)
表2-3设备描述表的分类
Display
显示设备描述表,提供对视频显示设备上的绘制操作的支持
Printer
打印设备描述表,提供对打印机、绘图仪设备上的绘制操作的支持
Memory
内存设备描述表,提供对位图操作的支持
Information
信息设备描述表,提供对操作设备信息获取的支持
表2-4显示设备描述表的分类
名称
特点
功能
ClassDevice
Contexts
提供对Win16的向后兼容
Common
Device
Contexts
在Windows系统的高速缓冲区,数量有限
Applicaion获取设备描述表时,Windows用缺省值初始化该设备描述表,Application使用它完成绘制操作,然后释放
Private
Device
Contexts
没有数量限制,用完不需释放一次获取,多次使用
多次使用过程中,每次设备描述表属性的任何修改或变化都会被保存,以支持快速绘制
(1)使用设备描述表的步骤
要使用设备描述表,一般有如下步骤:
∙获取或者创建设备描述表;
∙必要的话,改变设备描述表的属性;
∙使用设备描述表完成绘制操作;
∙释放或删除设备描述表。
Common设备描述表通过:
:
GetDC,:
:
GetDCEx,:
:
BeginPaint来获得一个设备描述表,用毕,用:
:
ReleaseDC或:
:
EndPaint释放设备描述表;
Printer设备描述表通过:
:
CreateDC创建设备描述表,用:
:
DeleteDC删除设备描述表。
Memory设备描述表通过:
:
CreateCompatibleDC创建设备描述表,用:
:
DeleteDC删除。
Information设备描述表通过:
:
CreateIC创建设备描述表,用:
:
DeleteDC删除。
(2)改变设备描述表属性的途径
要改变设备描述表的属性,可通过以下途径:
用:
:
SelectObject选入新的除调色板以外的GDIObject到设备描述表中;
对于调色板,使用:
:
SelectPalette函数选入逻辑调色板,并使用:
:
RealizePalette把逻辑调色板的入口映射到物理调色板中。
用其他API函数改变其他属性,如:
:
SetMapMode改变映射模式。
设备描述表在MFC中的实现
MFC提供了CDC类作为设备描述表类的基类,它封装了Windows的HDC设备描述表对象和相关函数。
1.CDC类有两个成员变量:
m_hDC,m_hAttribDC,它们都是Windows设备描述表句柄。
CDC的成员函数作输出操作时,使用m_Hdc;要获取设备描述表的属性时,使用m_hAttribDC。
2.在创建一个CDC类实例时,缺省的m_hDC等于m_hAttribDC。
如果需要的话,程序员可以分别指定它们。
例如,MFC框架实现CMetaFileDC类时,就是如此:
CMetaFileDC从物理设备上读取设备信息,输出则送到元文件(metafile)上,所以m_hDC和m_hAttribDC是不同的,各司其责。
还有一个类似的例子:
打印预览的实现,一个代表打印机模拟输出,一个代表屏幕显示。
3.CDC封装:
:
SelectObject(HDChdc,HGDIOBJECThgdiobject)函数时,采用了重载技术,即它针对不同的GDI对象,提供了名同而参数不同的成员函数:
SelectObject(CPen*pen)用于选入笔;
SelectObject(CBitmap*pBitmap)用于选入位图;
SelectObject(CRgn*pRgn)用于选入剪裁区域;
SelectObject(CBrush*pBrush)用于选入刷子;
SelectObject(CFont*pFont)用于选入字体;
至于调色板,使用SelectPalette(CPalette*pPalette,BOOLbForceBackground)选入调色板到设备描述表,使用RealizePalletter()实现逻辑调色板到物理调色板的映射。
∙
从CDC派生出四个功能更具体的设备描述表类。
层次如图2-3所示。
∙CCientDC
代表窗口客户区的设备描述表。
其构造函数CClientDC(CWnd*pWin)通过:
:
GetDC获取指定窗口的客户区的设备描述表HDC,并且使用成员函数Attach把它和CClientDC对象捆绑在一起;其析构函数使用成员函数Detach把设备描述表句柄HDC分离出来,并调用:
:
ReleaseDC释放设备描述表HDC。
∙CPaintDC
仅仅用于响应WM_PAINT消息时绘制窗口,因为它的构造函数调用了:
:
BeginPaint获取设备描述表HDC,并且使用成员函数Attach把它和CPaintDC对象捆绑在一起;析构函数使用成员函数Detach把设备描述表句柄HDC分离出来,并调用:
:
EndPaint释放设备描述表HDC,而:
:
BeginPaint和:
:
EndPaint仅仅在响应WM_PAINT时使用。
∙CMetaFileDC
用于生成元文件。
∙CWindowDC
代表整个窗口区(包括非客户区)的设备描述表。
其构造函数CWindowDC(CWnd*pWin)通过:
:
GetWindowDC获取指定窗口的客户区的设备描述表HDC,并使用Attach把它和CWindowDC对象捆绑在一起;其析构函数使用Detach把设备描述表HDC分离出来,调用:
:
ReleaseDC释放设备描述表HDC。
MFC设备描述表类的使用
1.使用CPaintDC、CClientDC、CWindowDC的方法
首先,定义一个这些类的实例变量,通常在栈中定义。
然后,使用它。
例如,MFC中CView对WM_PAINT消息的实现方法如下:
voidCView:
:
OnPaint()
{
//standardpaintroutine
CPaintDCdc(this);
OnPrepareDC(&dc);
OnDraw(&dc);
}
在栈中定义了CPaintDC类型的变量dc,随着构造函数的调用获取了设备描述表;设备描述表使用完毕,超出其有效范围就被自动地清除,随着析构函数的调用,其获取的设备描述表被释放。
如果希望在堆中创建,例如
CPain