我MFC没咋用过,虽然现在Java,C#等语言风头狠劲,Java,.Net平台也是逐渐取代Win32平台,但我认为,MFC也是有值得一学的必要,嗯,看在市场的面子上吧,明天我可是要去找工作了,:),
学win32 api + C++已经近2年,Delphi也有2个月了,相对于动则编程经验10年的老鸟来说,我可能连小鸟都算不上,没有任何VC项目的经验(Delphi的项目做过一些)。但初生牛犊不怕虎,但现在社会民风开放,在网络崇尚言论自由,我也想来言论自由一些。没有人敢说VC的不是,但提起MFC,大都说是垃圾,MFC是不是垃圾,最好要有真凭实据:正比如,你骂一个是笨蛋,还要拿出证据来说它是笨蛋!
嗯,从Delphi的TForm开始吧,在MFC中,与TForm类似的类有CView, CDialog, 先看看CView:
class CView : public CWnd
{
DECLARE_DYNAMIC(CView)
// Constructors
protected:
CView();
// Attributes
public:
CDocument* GetDocument() const;
// Operations
public:
// for standard printing setup (override OnPreparePrinting)
BOOL DoPreparePrinting(CPrintInfo* pInfo);
// Overridables
public:
virtual BOOL IsSelected(const CObject* pDocItem) const; // support for OLE
// OLE scrolling support (used for drag/drop as well)
virtual BOOL OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll = TRUE);
virtual BOOL OnScrollBy(CSize sizeScroll, BOOL bDoScroll = TRUE);
// OLE drag/drop support
virtual DROPEFFECT OnDragEnter(COleDataObject* pDataObject,
DWORD dwKeyState, CPoint point);
virtual DROPEFFECT OnDragOver(COleDataObject* pDataObject,
DWORD dwKeyState, CPoint point);
virtual void OnDragLeave();
virtual BOOL OnDrop(COleDataObject* pDataObject,
DROPEFFECT dropEffect, CPoint point);
virtual DROPEFFECT OnDropEx(COleDataObject* pDataObject,
DROPEFFECT dropDefault, DROPEFFECT dropList, CPoint point);
virtual DROPEFFECT OnDragScroll(DWORD dwKeyState, CPoint point);
virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL);
virtual void OnInitialUpdate(); // called first time after construct
protected:
// Activation
virtual void OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView);
virtual void OnActivateFrame(UINT nState, CFrameWnd* pFrameWnd);
// General drawing/updating
virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
virtual void OnDraw(CDC* pDC) = 0;
// Printing support
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
// must override to enable printing and print preview
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnPrint(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
// Advanced: end print preview mode, move to point
virtual void OnEndPrintPreview(CDC* pDC, CPrintInfo* pInfo, POINT point, CPreviewView* pView);
// Implementation
public:
virtual ~CView();
#ifdef _DEBUG
virtual void Dump(CDumpContext&) const;
virtual void AssertValid() const;
#endif //_DEBUG
// Advanced: for implementing custom print preview
BOOL DoPrintPreview(UINT nIDResource, CView* pPrintView,
CRuntimeClass* pPreviewViewClass, CPrintPreviewState* pState);
virtual void CalcWindowRect(LPRECT lpClientRect,
UINT nAdjustType = adjustBorder);
virtual CScrollBar* GetScrollBarCtrl(int nBar) const;
static CSplitterWnd* PASCAL GetParentSplitter(const CWnd* pWnd, BOOL bAnyState);
protected:
CDocument* m_pDocument;
public:
virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo);
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual void PostNcDestroy();
// friend classes that call protected CView overridables
friend class CDocument;
friend class CDocTemplate;
friend class CPreviewView;
friend class CFrameWnd;
friend class CMDIFrameWnd;
friend class CMDIChildWnd;
friend class CSplitterWnd;
friend class COleServerDoc;
friend class CDocObjectServer;
//{{AFX_MSG(CView)
afx_msg int OnCreate(LPCREATESTRUCT lpcs);
afx_msg void OnDestroy();
afx_msg void OnPaint();
afx_msg int OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message);
// commands
afx_msg void OnUpdateSplitCmd(CCmdUI* pCmdUI);
afx_msg BOOL OnSplitCmd(UINT nID);
afx_msg void OnUpdateNextPaneMenu(CCmdUI* pCmdUI);
afx_msg BOOL OnNextPaneCmd(UINT nID);
// not mapped commands - must be mapped in derived class
afx_msg void OnFilePrint();
afx_msg void OnFilePrintPreview();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
0:代码评释
protected:
CView(); // 表明CView只能用来继承,而不能实例化
BOOL DoPreparePrinting(CPrintInfo* pInfo); //要取得打印效果,必须Override该函数,设置打印机
virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL);
// 从该函数看来,设置打印机效果必须Override该函数 该函数和DoPreparePrinting()函数如何配合呢?
BOOL DoPreparePrinting(CPrintInfo* pInfo); //要取得打印效果,必须Override该函数,设置打印机
1:既然有virtual void OnDraw(CDC* pDC) = 0,虚函数,表示该类为抽象类,类的Constructor没有必要为Protected, Public也一样可以达到要求,不过使用Protected更严格遵守C++语言的语意。
2:CView的友元类:
friend class CDocument;
friend class CDocTemplate;
friend class CPreviewView;
friend class CFrameWnd;
friend class CMDIFrameWnd;
friend class CMDIChildWnd;
friend class CSplitterWnd;
friend class COleServerDoc;
friend class CDocObjectServer;
CView的友元类都是MVC架构中的,文档类,CDocument, COleServerDoc, CDocObjectServer, 框架类:CDocTemplate, CFrameWnd, CMDIFrameWnd, 控制器类:CMIDFrameWnd, CMDIChildWnd, 视图类有:CPreviewView
3: CView类接受的消息
//{{AFX_MSG(CView)
afx_msg int OnCreate(LPCREATESTRUCT lpcs);
afx_msg void OnDestroy();
afx_msg void OnPaint();
afx_msg int OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message);
// commands
afx_msg void OnUpdateSplitCmd(CCmdUI* pCmdUI);
afx_msg BOOL OnSplitCmd(UINT nID);
afx_msg void OnUpdateNextPaneMenu(CCmdUI* pCmdUI);
afx_msg BOOL OnNextPaneCmd(UINT nID);
// not mapped commands - must be mapped in derived class
afx_msg void OnFilePrint();
afx_msg void OnFilePrintPreview();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
该部分函数可以相当于Delphi的事件函数,OnCreate(),从名称看来,是刚创建是,用于设定View的外形,特性等,相当与TForm的procedure TForm1.FormCreate(Sender: TObject); FormCreate()事件, 而OnDestroy()则对等于:procedure TForm1.FormDestroy(Sender: TObject);
由于MFC的消息处理函数直接与WIN32消息是一一对应的,可以看出,CView类有关处理消息的函数极其缺乏的。而Delphi的TForm是极其丰富的,其实,TForm类对应的MFC类应该是CDialog,只是MFC并不打算把CDialog作为其它控件类的容器,所以在设计上,并没有处理其他的更多的消息。以下会接着讨论这个问题!
{ TForm }
TForm = class(TCustomForm)
public
...
property OnActivate;
property OnCanResize;
property OnClick;
property OnClose;
property OnCloseQuery;
property OnConstrainedResize;
property OnContextPopup;
property OnCreate;
property OnDblClick;
property OnDestroy;
property OnDeactivate;
property OnDockDrop;
property OnDockOver;
property OnDragDrop;
property OnDragOver;
property OnEndDock;
property OnGetSiteInfo;
property OnHide;
property OnHelp;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnMouseWheel;
property OnMouseWheelDown;
property OnMouseWheelUp;
property OnPaint;
property OnResize;
property OnShortCut;
property OnShow;
property OnStartDock;
property OnUnDock;
end;
当然了,除了几个是对应Windows api消息外,其他的消息都是VCL自身的消息!
4: 滑稽的OnDraw和OnPaint
virtual void OnDraw(CDC* pDC) = 0;
afx_msg void OnPaint();
从函数声明来看,好像OnDraw是一般的函数,而OnPaint正是WM_PAINT消息函数,可其实如果OnPaint不被Override时,OnPaint调用OnDraw来处理消息。这种手法有点接近Delphi的做法了。而不能一对一,否则,我还用MFC干吗,我直接用WIN32 API好了。
/////////////////////////////////////////////////////////////////////////////
void CEx03aView::OnDraw(CDC* pDC)
{
pDC->TextOut(300, 500, "hello CEx03aView::OnDraw(CDC* pDC) function");
}
void CEx03aView::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.TextOut(300, 400, "hello CEx03aView::OnPaint function");
}
OnPaint被Override之后,OnDraw就失去效果了。以上代码显示为“hello CEx03aView::OnPaint function”
5:Delphi的PME结构(属性方法事件)和VC的(M)FC结构(基础类),先进了整整一代,现在的Java和C#也都提供了PME结构,这是巧合吗?当然不是,Java的Javabean,正是Sun委托Borland做的,C#和.Net的设计师Anders更是Delphi的创始人。所以Java SDK和C#语言,.Net frameword和Delphi语言,VCL库神似,也就不奇怪了。至今,也没有什么消息说微软要出MFC.Net,我认为这是不可能,这不仅仅是市场原因,而是MFC的设计思想太落后了。而Delphi8的推出,VCL.Net的腾空出世,再一起证明VCL的良好设计一直都是领导Frameword的世界潮流。
6:MFC对api的封装极其落后,也极其丑陋,从技术从说就是一个失败的产品。可是它为什么成功了呢?这就说出了MFC的最大的优点:灵活,高效,简单。
灵活:这是得益于C/C++语言的缘故。我也不用多说
高效:还是得益于C/C++语言的缘故。C/C++语言的特点,灵活高效,相信大家不会忘记。
简单:大家对比MFC和VCL,都会相信VCL确实比MFC难学,VCL里面的高级技巧鬼斧神工,VCL程序码里面甚至还有许多汇编。这都是令人望而却步的。而MFC呢,简单封装,简单使用,虽然丧失了RAD,不过,这也是大家喜欢的原因吧。
MFC的成功很大程度是得益于C/C++这个语言中的日不落帝国,VCL成功在于Delphi这个优雅的,威力的,专利的OO语言
噢,MFC,当日不落帝国陨落时,还是把它放到历史的博物馆吧!
当然了,不能凭这点不像样的东西,来议论一个“伟大”的frameword---MFC,否则会让人晕倒,所以会有一系列的学习心得......
to be continued
--- 2004-7-2 by littleroy