MFC使用日志2007/6/20

1.  一个MFC程序的基本框架由两个类构成:App类和Window类。通常情况下App类继承自CWinApp,主要负责应用程序相关部分;Window类继承自CFrameWnd,负责窗口显示,窗口逻辑部分。

 

Window类组合于App类,程序存在一个全局的App类对象。通常都在App::InitInstance中创建一个Window类对象,并保存于App::m_pMainWnd

 

App中创建窗口的过程形如:

BOOL AnimPlayerApp::InitInstance()

{

          CWinApp::InitInstance();

m_pMainWnd    =    new  MainWindow();

          m_pMainWnd->ShowWindow( m_nCmdShow );

          m_pMainWnd->UpdateWindow();

return TRUE;

}

 

而对于一个Window类而言,就需要处理该窗口的逻辑,主要包括创建该窗口之上的子控件,以及最重要的消息映射。

 

一个GUI程序最重要的是什么?最重要的是控件的消息处理。Qtsignal and slot机制,Swing AWTlistener机制。MFC也不复杂,MFC处理消息用的是消息映射机制。事情就是这样的,这样一看,当你觉得你掌握了Qt里的signal and slot,掌握了Swing/AWT中的listener,就掌握了这两个GUI库的话,那么,当你掌握了MFC中的消息映射机制(不必去翻映射机制背后的原理,就好比不必去自己实现一个signal and slot一样),那么你就掌握了MFC。但是MFC为什么看上去还要复杂(虽然其设计很差,我们这里暂且只看功能)?因为MFC还实现了其他很多技术。你只需要知道,MFC是尽可能地帮程序员做事,如果你不愿意,你当然可以自己从头干起。

 

       那么我们谈谈Window类中的消息处理。要使用MFC的消息映射,只需要在需要捕获消息的类定义中加上消息处理函数,以及放上一个MFC里的宏即可。消息处理函数和一般的函数是一样的,为了看上去完美(配合MFC),就加上一个afx_msg,但是事实上afx_msg什么也不是。再次强调,消息处理函数和一般的函数没什么两样。

       Window类的基类,例如CFrameWnd,或者更上一层的CWnd类,已经定义了一些消息处理函数,例如OnPaint这个响应窗口绘制的函数。MFC这样做是因为它想对一些事件进行默认处理(起码我这样认为,另:事件亦即消息)。当你想处理一些MFC内部已经默认处理的消息时,你可以重载这些默认的消息处理函数,例如OnPaint。而另一些消息,例如你自己创建的子控件会产生的消息,则需要你新定义。但是无论如何,当你声明了一个消息处理函数后,你都需要在另一个实现地方做另一些宏处理,然后再真正定义函数体。声明消息映射形如:

            /// 消息映射处理

private:

     afx_msg  void OnPaint();

 

     /// 菜单消息处理

     afx_msg  void OnFileOpen();

     afx_msg  void OnFileExit();

     DECLARE_MESSAGE_MAP()

    

     注意最后一句话  DECLARE_MESSAGE_MAP()你不必去翻这句宏的具体定义,你只需要知道,不加上这一句,你什么也做不了。

    然后在我所谓的实现部分,加上形如这样的语句:

    BEGIN_MESSAGE_MAP( MainWindow, CFrameWnd )

     ON_WM_PAINT()

     ON_COMMAND( ID__OPENIMG, OnFileOpen )

     ON_COMMAND( ID__EXIT, OnFileExit )

     END_MESSAGE_MAP()

    

     对于很多MFC自己定义了的消息处理函数,你只需要做类似于ON_WM_PAINT()的声明即可,不需要指定具体的消息处理函数(例如第二句ON_COMMAND(ID_OPENIMG, OnFileOpen)),

MFC始终会调用它自己规定的函数,例如OnPaint。而另一些消息,则需要你写上消息处理的函数名。每一种消息都有自己的消息处理函数形式,因为每一个消息处理时需要得到的信息不一样,信息通常都是由参数传递,这就导致了每一个消息处理函数的参数,返回值不一样。每一个消息具体该定义如何的消息处理函数,这个就是翻阅文档的事情了。

 

    最后,你只需要定义消息处理函数即可。还记的吗?消息处理函数和一般的类成员函数一样。消息处理函数大部分时候都是被MFC内部调用(派发消息时),当然你也可以自己调用。

 

    如果你会Qt,当看了以上我做的分析后,是不是会同我一样,有一种心旷神怡的感觉?MFC中的消息处理函数,就如同Qt中定义的slot函数一样。MFC中的宏,就如同Qt中的slots, signals一样,我让你不要去管MFC中的宏,就如同不要去管Qtslots之类是如何实现一样。

 

    话说到此,真感觉MFC不过如此。MFC不见得实现了多么厉害的技术,它只是一堆糟糕的OO设计,糟糕的设计才导致了复杂。但是无论如何,当你掌握了核心技术,其他的,也还是一种查文档的事罢了。但是,MFC除了消息处理它还实现了其他东西,而这些东西,当你需要的时候,你同样会觉得他们简单无比。

 

    接下来记录一些控件之类的使用经验。

 

2.  对于Window类,创建窗口上子控件之类的活动最好放在OnCreate里,要修改窗口样式,在PreCreateWindow里,要创建自身(调用Create),就在构造函数里。如果创建自身放在PreCreateWindow或者OnCreate里,会引发断点。

 

3.使用菜单:要使用菜单,可以先使用菜单资源编辑器编辑好菜单(包括菜单ID值),在创建窗口时(即调用CFrameWnd::Create之类的函数),传菜单资源句柄即可。当菜单项没有加消息处理时,菜单项默认情况下是灰色的。当加了消息处理后,会自动有效。要使即使没加消息处理的菜单项成为有效,可以置CFrameWnd:: m_bAutoMenuEnable FALSE

    菜单消息处理函数通常都是 void Window::OnFunc()的形式。

    消息映射里:ON_COMMAND( 菜单项ID, 菜单消息处理函数 ) 即可。

   

 

4.  使用滚动条:创建滚动条同大部分子控件一样,先构造一个CScrollBar对象,然后调用Create函数,注意在指定滚动条风格时要加上WS_CHILD以及WS_VISIBLE风格。

 

处理滚动条消息,只需要重载OnHScroll或者OnVScroll。对应的消息映射宏是:

ON_WM_HSCROLL() ON_WM_VSCROLL()

 

关于滚动条消息处理函数的实现,大部分时候需要手动设置滚动条thumb的位置。

 

 

5.使用按钮:同滚动条一样,先构造一个CButton对象,然后调用Create函数,指定风格时依然要指定WS_CHILD以及WS_VISIBLE。处理消息时需要手动指定  ON_BN_CLICKED( ID_BTN_START, OnBtnStart ) ON_BN_CLICKED( 按钮ID,按钮消息处理函数)

    

6.使用定时器Timer,随时调用SetTimer来启动,KillTimer来停止。重载OnTimer来处理消息,对应ON_WM_TIMER映射宏。

 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值