深入浅出MFC第2版(PDF格式)-第43部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
当窗口函数做消息的比对时,我们就可以想办法导引它沿着这条路走过去:
170
…………………………………………………………Page 233……………………………………………………………
第3章 MFC 六大關鍵技術之模擬
CObject
CObject
CCmdTarget
CCmdTarget
CWinThread
CWinThread
CWinApp
CWinApp
CMyWinApp
CMyWinApp
CWnd
CWnd
CView
CMyView
CMyView
CFrameWnd
CFrameWnd
CMyFrameWnd
CMyFrameWnd
CDocument
CDocument
CMyDoc
CMyDoc
但是,MFC 之中用来处理消息的C++ 类别,并不呈单鞭发展。作为application framework
的重要架构之一的document/view ,也具有处理消息的能力(你现在可能还不清楚什么是
document/view ,没有关系)。因此,消息藉以攀爬的路线应该有横流的机会:
CObject
CObject
CCmdTarget
CCmdTarget
CWinThread
CWinThread
CWinApp
CWinApp
CMyWinApp
CMyWinApp
CWnd
CWnd
CView
CMyView
CMyView
CFrameWnd
CFrameWnd
CMyFrameWnd
CMyFrameWnd
CDocument
CDocument
CMyDoc
CMyDoc
171
…………………………………………………………Page 234……………………………………………………………
第篇 勿在浮砂築高台
消息如何流动,我们暂时先不管。是直线前进,或是中途换跑道,我们都暂时不管,本
节先把这个攀爬路线网建立起来再说。这整个攀爬路线网就是所谓的消息映射表
(Message Map );说它是一张地图,当然也没有错。将消息与表格中的元素比对,然后
调用对应的处理例程,这种动作我们也称之为消息映射(Message Mapping)。
为了尽量降低对正常(一般)类别声明和定义的影响,我们希望,最好能够像RTTI 和
Dynamic Creation 一样,用一两个宏就完成这巨大蜘蛛网的构造。最好能够像
DECLARE_DYNAMIC 和IMPLEMENT_DYNAMIC 宏那么方便。
首先定义一个数据结构:
struct AFX_MSGMAP
{
AFX_MSGMAP* pBaseMessageMap;
AFX_MSGMAP_ENTRY* lpEntries;
};
其中的 AFX_MSGMAP_ENTRY 又是另一个数据结构:
struct AFX_MSGMAP_ENTRY // MFC 4。0 format
{
UINT nMessage; // windows message
UINT nCode; // control code or WM_NOTIFY code
UINT nID; // control ID (or 0 for windows messages)
UINT nLastID; // used for entries specifying a range of control id's
UINT nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
其中的AFX_PMSG 定义为函数指针:
typedef void (CCmdTarget::*AFX_PMSG)(void);
然后我们定义一个宏:
#define DECLARE_MESSAGE_MAP()
static AFX_MSGMAP_ENTRY _messageEntries'';
static AFX_MSGMAP messageMap;
virtual AFX_MSGMAP* GetMessageMap() const;
172
…………………………………………………………Page 235……………………………………………………………
第3章 MFC 六大關鍵技術之模擬
于是,DECLARE_MESSAGE_MAP 就相当于声明了这样一个数据结构:
pBaseMessageMap
_messageEntries''
lpEntries
nMessage; nCode; nID; nLastID; nSig; pfn
messageMap
这个数据结构的内容填塞工作由三个宏完成:
#define BEGIN_MESSAGE_MAP (theClass; baseClass)
AFX_MSGMAP* theClass::GetMessageMap() const
{ return &theClass::messageMap; }
AFX_MSGMAP theClass::messageMap =
{ &(baseClass::messageMap);
(AFX_MSGMAP_ENTRY*) &(theClass::_messageEntries) };
AFX_MSGMAP_ENTRY theClass::_messageEntries'' =
{
#define ON_MAND (id; memberFxn)
{ WM_MAND; 0; (WORD)id; (WORD)id; AfxSig_vv; (AFX_PMSG)memberFxn };
#define END_MESSAGE_MAP ()
{ 0; 0; 0; 0; AfxSig_end; (AFX_PMSG)0 }
};
其中的AfxSig_end 定义为:
enum AfxSig
{
AfxSig_end = 0; // 'marks end of message map'
AfxSig_vv;
};
AfxSig_xx 用来描述消息处理例程memberFxn 的类型(参数与回返值)。本例纯为仿真
与简化,所以不在这上面作文章。真正讲到MFC 时(第四篇p580 ),我会再解释它。
173
…………………………………………………………Page 236……………………………………………………………
第篇 勿在浮砂築高台
于是,以CView 为例,下面的源代码:
// in header file
class CView : public CWnd
{
public:
。。。
DECLARE_MESSAGE_MAP()
};
// in implementation file
#define CViewid 122
。。。
BEGIN_MESSAGE_MAP(CView; CWnd)
ON_MAND(CViewid; 0)
END_MESSAGE_MAP()
就被展开成为:
// in header file
class CView : public CWnd
{
public:
。。。
static AFX_MSGMAP_ENTRY _messageEntries'';
static AFX_MSGMAP messageMap;
virtual AFX_MSGMAP* GetMessageMap() const;
};
// in implementation file
AFX_MSGMAP* CView::GetMessageMap() const
{ return &CView::messageMap; }
AFX_MSGMAP CView::messageMap =
{ &(CWnd::messageMap);
(AFX_MSGMAP_ENTRY*) &(CView::_messageEntries) };
AFX_MSGMAP_ENTRY CView::_messageEntries'' =
{
{ WM_MAND; 0; (WORD)122; (WORD)122; 1; (AFX_PMSG)0 };
{ 0; 0; 0; 0; 0; (AFX_PMSG)0 }
};
以图表示则为:
174
…………………………………………………………Page 237……………………………………………………………
第3章 MFC 六大關鍵技術之模擬
CWnd::messageMap
pBaseMessageMap
CView::_messageEntries''
lpEntries
WM_MAND; 0; 122; 122; 1; (AFX_PMSG)0
0; 0; 0; 0; 0; (AFX_PMSG)0 CView::messageMap
我们还可以定义各种类似ON_MAND 这样的宏,把各式各样的消息与特定的处
理例程关联起来。MFC 里头就有名为ON_ WM_PAINT 、ON_ WM_CREATE、ON_ WM_SIZE。。。
等等的宏。
我在Frame7 范例程序中为CCmdTarget 的每一衍生类别都产生类似上图的消息映射表:
// in header files
class CObject
{
。。。 // 注意:CObject 并不属于消息流动网的一份子。
};
class CCmdTarget : public CObject
{
。。。
DECLARE_MESSAGE_MAP()
};
class CWinThread : public CCmdTarget
{
。。。 // 注意:CWinThread 并不属于消息流动网的一份子。
};
class CWinApp : public CWinThread
{
。。。
DECLARE_MESSAGE_MAP()
};
class CDocument : public CCmdTarget
{
。。。
DECLARE_MESSAGE_MAP()
};
class CWnd : public CCmdTarget
{
。。。
DECLARE_MESSAGE_MAP()
175
…………………………………………………………Page 238……………………………………………………………
第篇 勿在浮砂築高台
};
class CFrameWnd : public CWnd
{
。。。
DECLARE_MESSAGE_MAP()
};
class CView : public CWnd
{
。。。
DECLARE_MESSAGE_MAP()
};
class CMyWinApp : public CWinApp
{
。。。
DECLARE_MESSAGE_MAP()
};
class CMyFrameWnd : public CFrameWnd
{
。。。
DECLARE_MESSAGE_MAP()
};
class CMyDoc : public CDocument
{
。。。
DECLARE_MESSAGE_MAP()
};
class CMyView : public CView
{
。。。