MFC消息映射机制剖析.docx

上传人:b****5 文档编号:8571372 上传时间:2023-01-31 格式:DOCX 页数:11 大小:24.18KB
下载 相关 举报
MFC消息映射机制剖析.docx_第1页
第1页 / 共11页
MFC消息映射机制剖析.docx_第2页
第2页 / 共11页
MFC消息映射机制剖析.docx_第3页
第3页 / 共11页
MFC消息映射机制剖析.docx_第4页
第4页 / 共11页
MFC消息映射机制剖析.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

MFC消息映射机制剖析.docx

《MFC消息映射机制剖析.docx》由会员分享,可在线阅读,更多相关《MFC消息映射机制剖析.docx(11页珍藏版)》请在冰豆网上搜索。

MFC消息映射机制剖析.docx

MFC消息映射机制剖析

一,消息映射机制

      1,消息响应函数:

(例:

在CDrawView类响应鼠标左键按下消息)

1)在头文件(DrawView.h)中声明消息响应函数原型。

//{{AFX_MSG(CDrawView)  //注释宏

afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);

//}}AFX_MSG  //注释宏

说明:

在注释宏之间的声明在VC中灰色显示。

afx_msg宏表示声明的是一个消息响应函数。

2)在源文件(DrawView.cpp)中进行消息映射。

BEGIN_MESSAGE_MAP(CDrawView,CView)

//{{AFX_MSG_MAP(CDrawView)

ON_WM_LBUTTONDOWN()

//}}AFX_MSG_MAP

//Standardprintingcommands

ON_COMMAND(ID_FILE_PRINT,CView:

:

OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_DIRECT,CView:

:

OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW,CView:

:

OnFilePrintPreview)

END_MESSAGE_MAP()

说明:

在宏BEGIN_MESSAGE_MAP()与END_MESSAGE_MAP()之间进行消息映射。

宏ON_WM_LBUTTONDOWN()把消息WM_LBUTTONDOWN与它的响应函数OnLButtonDown()相关联。

这样一旦有消息的产生,就会自动调用相关联的消息响应函数去处理。

宏ON_WM_LBUTTONDOWN()定义如下:

#defineON_WM_LBUTTONDOWN()\

{WM_LBUTTONDOWN,0,0,0,AfxSig_vwp,\

 (AFX_PMSG)(AFX_PMSGW)(void(AFX_MSG_CALLCWnd:

:

*)(UINT,CPoint))&OnLButtonDown},

3)源文件中进行消息响应函数处理。

(DrawView.cpp中自动生成OnLButtonDown函数轮廓,如下)

voidCDrawView:

:

OnLButtonDown(UINTnFlags,CPointpoint)

{

//TODO:

Addyourmessagehandlercodehereand/orcalldefault

CView:

:

OnLButtonDown(nFlags,point);

}

说明:

可见当增加一个消息响应处理,在以上三处进行了修改。

可在消息响应函数里添加消息处理代码完成对消息的响应、处理。

2,消息响应的方式:

1)在基类中针对每种消息做一个虚函数,当子类对消息响应时候,只要在子类中重写这个虚函数即可。

缺点:

MFC类派生层次很多,如果在基类对每个消息进行虚函数处理,那么从基类派生的每个子类都将背负一个庞大的虚表,这样浪费内存,故MFC没有采取这中方式而采取消息映射方式。

2)消息映射方式:

MFC在后台维护了一个句柄和C++对象指针对照表,当收到一个消息后,通过消息结构里资源句柄(查对照表)就可找到与它对应的一个C++对象指针,然后把这个指针传给基类,基类利用这个指针调用WindowProc()函数对消息进行处理,WindowProc()函数中调用OnWndMsg()函数,真正的消息路由及处理是由OnWndMsg()函数完成的。

由于WindowProc()和OnWndMsg()都是虚函数,而且是用派生类对象指针调用的,由多态性知最总终调用子类的。

在OnWndMsg()函数处理的时候,根据消息种类去查找消息映射,判断所发的消息有没有响应函数,具体方式是到相关的头文件和源文件中寻找消息响应函数声明(从注释宏//{{AFX_MSG(CDrawView)...//}}AFX_MSG之间寻找),消息映射(从宏BEGIN_MESSAGE_MAP(...)....END_MESSAGE_MAP()之间寻找),最终找到对应的消息处理函数。

当然,如果子类中没有对消息进行处理,则消息交由基类处理。

说明:

virtualLRESULTWindowProc(UINTmessage,WPARAMwParam,LPARAMlParam);

virtualBOOLOnWndMsg(UINTmessage,WPARAMwParam,LPARAMlParam,LRESULT*pResult);

二,有关绘图

1,使用SDK获取DC句柄:

HDChdc;

hdc=:

:

GetDc(m_hWnd);//获取DC句柄

MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);

LineTo(hdc,point.x,point.y);

:

:

ReleaseDC(m_hWnd,hdc);//释放DC

2,利用CDC类指针和CWin类成员函数获取DC。

CDC*pDC=GetDC();

pDC->MoveTo(m_ptOrigin);

pDC->LineTo(point);

ReleaseDC(pDC);

3,利用CClientDC对象。

(CClientDC类从CDC类派生来的)

CClientDCdc(this);

dc.MoveTo(m_ptOrigin);

dc.LineTo(point);

说明:

TheCClientDCclassisderivedfromCDCandtakescareofcallingtheWindowsfunctionsGetDCatconstructiontimeandReleaseDCatdestructiontime.ThismeansthatthedevicecontextassociatedwithaCClientDCobjectistheclientareaofawindow.

4,利用CWindowDC对象。

(CWindowDC类从CDC类派生来的)

CWindowDCdc(this);//

dc.MoveTo(m_ptOrigin);

dc.LineTo(point);

说明:

TheCWindowDCclassisderivedfromCDC.ItcallstheWindowsfunctionsGetWindowDCatconstructiontimeandReleaseDCatdestructiontime.ThismeansthataCWindowDCobjectaccessestheentirescreenareaofaCWnd(bothclientandnonclientareas).

5,GetParent()得到父窗口指针;GetDesktopWindow()得到屏幕窗口指针。

6,利用画笔改变线条颜色和类型:

CPenpen(PS_DOT,1,RGB(0,255,0));//构造画笔对象

CClientDCdc(this);CPen*pOldPen=dc.SelectObject(&pen);//将画笔选入DC

dc.MoveTo(m_ptOrigin);

dc.LineTo(point);

dc.SelectObject(pOldPen);//恢复先前的画笔

7,使用画刷(通常利用画刷去填充矩形区域):

使用单色画刷

CBrushbrush(RGB(255,0,0));//构造画刷对象

CClientDCdc(this);

dc.FillRect(CRect(m_ptOrigin,point),&brush);//用指定的画刷去填充矩形区域

使用位图画刷

CBitmapbitmap;//构造位图对象(使用前需要初试化)

bitmap.LoadBitmap(IDB_BITMAP1);//初试化位图对象

CBrushbrush(&bitmap);//构造位图画刷

CClientDCdc(this);

dc.FillRect(CRect(m_ptOrigin,point),&brush);//用指定的位图画刷去填充矩形区域

使用透明画刷

CBrush*pBrush=CBrush:

:

FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//获取透明画刷对象指针

CClientDCdc(this);

CBrush*pOldBrush=dc.SelectObject(pBrush);//将透明画刷选入DC

dc.Rectangle(CRect(m_ptOrigin,point));

dc.SelectObject(pOldBrush);//释放透明画刷

说明:

TheGetStockObjectfunctionretrievesahandletooneofthepredefinedstockpens,brushes,fonts,orpalettes.

HGDIOBJGetStockObject(

 intfnObject  //typeofstockobject

);

ReturnsapointertoaCBrushobjectwhengivenahandletoaWindowsHBRUSHobject.

staticCBrush*PASCALFromHandle(HBRUSHhBrush);//FromHandle是一个静态方法,故可用CBrush:

:

FromHandle()形式调用。

注意点:

1)静态方法不属于某一个具体对象,而属于类本身,在类加载的时候就已经为类静态方法分配了代码去,故可用CBrush:

:

FromHandle()形式调用。

2)静态方法中,不能引用非静态的数据成员和方法。

3)静态数据成员需要在类外单独做初始化,形式如:

变量类型类名:

:

变量名=初始值;

8,CDC:

:

SetROP2方法:

intSetROP2(intnDrawMode);

Setsthecurrentdrawingmode.

(5)文本编程

1,创建插入符:

voidCreateSolidCaret(intnWidth,intnHeight);//创建插入符

voidCreateCaret(CBitmap*pBitmap);//创建位图插入符

voidShowCaret();//显示插入符

voidHideCaret();//隐藏插入符

staticvoidPASCALSetCaretPos(POINTpoint);//移动插入符号

说明:

1)创建插入符要在窗口创建完成之后,CreateSolidCaret函数创建的插入符被初始化为隐藏,所以需要调用ShowCaret()将其显示。

2)使用CreateCaret函数创建位图插入符的时候,不能使用局部的位图对象关联位图资源。

(与资源相关联的C++对象,当它析构的时候会同时把与它相关联的资源销毁。

2,获取当前字体信息的度量:

CDC:

:

GetTextMetrics

BOOLGetTextMetrics(LPTEXTMETRIClpMetrics)const;

说明:

typedefstructtagTEXTMETRIC{ /*tm*/

   int tmHeight;//字体高度。

Specifiestheheight(ascent+descent)ofcharacters.

   int tmAscent;//基线以上的字体高度

   int tmDescent;//基线以下的字体高度

   int tmInternalLeading;

   int tmExternalLeading;

   int tmAveCharWidth;//字符平均宽度

   int tmMaxCharWidth;

   int tmWeight;

   BYTEtmItalic;

   BYTEtmUnderlined;

   BYTEtmStruckOut;

   BYTEtmFirstChar;

   BYTEtmLastChar;

   BYTEtmDefaultChar;

   BYTEtmBreakChar;

   BYTEtmPitchAndFamily;

   BYTEtmCharSet;

   int tmOverhang;

   int tmDigitizedAspectX;

   int tmDigitizedAspectY;

}TEXTMETRIC;

3,OnDraw函数:

virtualvoidOnDraw(CDC*pDC)

当窗口(从无到有或尺寸大小改变等)要求重绘的时候,会发送WM_PAIN消息,调用OnDraw函数进行重绘。

4,获取字符串的高度和宽度(区别字符串的长度):

CDC:

:

GetTextExtent

CSizeGetTextExtent(LPCTSTRlpszString,intnCount)const;

CSizeGetTextExtent(constCString&str)const;

说明:

TheCSizeclassissimilartotheWindowsSIZEstructure。

typedefstructtagSIZE{

   intcx;//thex-extent

   intcy;//they-extent

}SIZE;

5,路径层:

BOOLBeginPath();

//在这作图定义路径层剪切区域

BOOLEndPath();

BOOLSelectClipPath(intnMode);//调用这个函数来使当前路径层剪切区域与新剪切区域进行互操作。

  

//在这覆盖作图(包含前定义的路径层区域)定义新的剪切区域

说明:

1)SelectClipPathSelectsthecurrentpathasaclippingregionforthedevicecontext,combiningthenewregionwithanyexistingclippingregionbyusingthespecifiedmode.Thedevicecontextidentifiedmustcontainaclosedpath.

////

nMode:

RGN_AND,RGN_COPY,RGN_DIFF,RGN_OR,RGN_XOR

RGN_AND  Thenewclippingregionincludestheintersection(overlappingareas)ofthecurrentclippingregionandthecurrentpath.

RGN_COPY  Thenewclippingregionisthecurrentpath.

RGN_DIFF  Thenewclippingregionincludestheareasofthecurrentclippingregion,andthoseofthecurrentpathareexcluded.

RGN_OR  Thenewclippingregionincludestheunion(combinedareas)ofthecurrentclippingregionandthecurrentpath.

RGN_XOR  Thenewclippingregionincludestheunionofthecurrentclippingregionandthecurrentpath,butwithouttheoverlappingareas.

2)应用:

当作图的时候,如果想要在整幅图形其中的某个部分和其它部分有所区别,我们可以把这部分图形放到路径层当中,然后指定调用指定互操作模式调用SelectClipPath(intnMode)函数来使路径层和覆盖在其上新绘图剪切区域进行互操作,达到特殊效果。

6,关于文本字符串一些函数:

COLORREFGetBkColor()const;//得到背景颜色

virtualCOLORREFSetBkColor(COLORREFcrColor);//设置背景颜色

BOOLSetTextBkColor(COLORREFcr);//设置文本背景颜色

virtualCOLORREFSetTextColor(COLORREFcrColor);//设置文本颜色

virtualBOOLTextOut(intx,inty,LPCTSTRlpszString,intnCount);//输出文本

BOOLTextOut(intx,inty,constCString&str);

CStringLeft(intnCount)const;//得到字符串左边nCount个字符

intGetLength()const;//得到字符串长度

7,字体CFont:

:

CFont

CFont();//构造函数

//ConstructsaCFontobject.TheresultingobjectmustbeinitializedwithCreateFont,CreateFontIndirect,CreatePointFont,orCreatePointFontIndirectbeforeitcanbeused.

选用字体事例代码组:

CClientDCdc(this);

CFontfont;//构造字体对象

font.CreatePointFont(300,"华文行楷",NULL);//初始化字体对象,与字体资源相关联

CFont*pOldFont=dc.SelectObject(&font);//将新字体选入DC

...

dc.SelectObject(pOldFont);//恢复原字体

说明:

1)构造字体对象时候,必须初始化。

(初始化是将字体对象与字体资源相关联)。

2)初始化对象时候,选用的字体也可以是系统字体,但不一定都有效,据测试选用。

8,在MFC中CEditView和cRichEditView类已经完成了初步的文字处理。

可以让应用程序的View类以CEditView和cRichEditView类为基类。

9,平滑变色

CDC:

:

TextOut()是一个字母一个字母的输出,达不到平滑效果。

CDC:

:

DrawText():

将文字的输出局限于一个矩形区域,超出矩形区域的文字都被截断。

利用这一特点,可每隔些时间增加矩形大小,从而可实现人眼中的平滑效果。

CWnd:

:

SetTimer():

设置定时器。

按设定的时间定时发送WM_TIMER消息。

说明:

UINTSetTimer(UINTnIDEvent,UINTnElapse,void(CALLBACKEXPORT*lpfnTimer)(HWND,UINT,UINT,DWORD));

//nIDEvent定时器标示,nElapse消息发送间隔时间,void(CALLBACKEXPORT*lpfnTimer)(HWND,UINT,UINT,DWORD)设置回调函数,如果设置则由设置的回调函数处理WM_TIMER消息,如果没有设置回调函数设为NULL,这发送的WM_TIMER消息压入消息队列,交由相关联的窗口处理(添加WM_TIMER消息处理函数OnTimer())。

afx_msgvoidOnTimer(UINTnIDEvent);

//响应WM_TIMER消息,nIDEvent为消息对应定时器标示(可以设置不同的定时器发送WM_TIMER消息)

 

问题:

1,在CCareView类中添加WM_CREATE消息响应函数OnCreate(),WM_CREATE消息是在什么时候被检查到而被响应的呢?

(猜测:

添加WM_CREATE消息后,消息被压入消息队列,然后经过消息循环进行分发到具体窗口,从而进行响应)

2,现有一文本文件内容已经读入串STR中,要求在视图客户区按原先文本文件中的格式输出。

问题是,利用CDC的TextOut()来在CView类派生类窗口中输出串时,忽略了串中的TAB、回车换行等格式,无论串有多长均在一行上输出。

这其中是CDC类成员函数TextOut()忽略串中格式的,还是CView类派生类窗口设置从中做怪呢?

怎么解决?

(6)菜单编程

1,弹出菜单(Pop-up)是不能用来作命令响应的。

2,MFC中菜单项消息如果利用ClassWizard来对菜单项消息分别在上述四个类中进行响应,则菜单消息传递顺序:

View类--Doc类--CMainFrame类--App类。

菜单消息一旦在其中一个类中响应则不再在其它类中查找响应函数。

具体:

当点击一个菜单项的时候,最先接受到菜单项消息的是CMainFrame框架类,CMainFrame框架类将会把菜单项消息交给它的子窗口View类,由View类首先进行恚蝗绻鸙iew类检测到没对该菜单项消息做响应,则View类把菜单项消息交由文档类Doc类进行处理;如果Doc类检测到Doc类中也没对该菜单项消息做响应,则Doc类又把该菜单项消息交还给View类,由View类再交还给CMainFrame类处理。

如果CMainFrame类查看到CMainFrame类中也没对该消息做响应,则最终交给App类进行处理。

3,消息的分类:

标准消息,命令消息,通告消息。

[标准消息]:

除WM_COMMAND之外,所有以WM_开头的消息。

[命令消息]:

来自菜单、加速键或工具栏按钮的消息。

这类消息都以WM_COMMAND呈现。

在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。

[通告消息]:

由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(通常是对话框)通知事件的发生。

这类消息也是以WM_COMMAND形式呈现。

说明:

1)从CWnd派生的类,都可以接收到[标准消息]。

2)从CCmdTarget派生的类,都可以接收到[命令消息]和[通告消息]。

4,一个菜单拦可以有若干个子菜单,一个子菜单又可以有若干个菜单项等。

对菜单栏的子菜单由左至右建立从0开始的索引。

对特定子菜单的菜单项由上至下建立了从0开始的索引。

访问子菜单和菜单项均可以通过其索引或标识(如果有标识的话)进行。

相关重要函数:

CMenu*GetMenu();//CWnd:

:

GetMenu

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 人文社科 > 设计艺术

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1