VS2008 MFC开发总结

来源:互联网 发布:淘宝联盟 一淘同时使用 编辑:程序博客网 时间:2024/05/21 12:45

  使用Delphi开发工具好多年了,总体上还是从事信息管理系统的开发.总想深入的研究一下其他方向,例如游戏或内核级的编程.但都由于看到C,C++,VC等因素而退却了.Delphi确实优秀,但也能让人懒惰,想实现什么功能了,就去网上搜索现成的控件.当然也偶尔出于好奇,查看这些控件的源码,并对其加以修改,满足开发的要求.自我感觉已经掌握了控件的内部实现原理了,但如果要自己去从新实现控件的功能,却未必是一件轻松的事情.Delphi和VC之间的战争持续好久了,不想过多的说谁优谁劣,各有优势吧.作为有快10年的Delphi使用经历的人,我深刻体会到,要想使用好Delphi,只会Delphi是不够的,必须学习C,C++和VC,只有深入的学习这些看似无关或平行的内容,才能够转变思路,写出更加优秀的Delphi代码.

  前些年还有人在比较Delphi和VC的强弱,大家都会例举出哪些优秀的软件是Delphi开发的,哪些优秀的软件是VC开发的.总体是Delphi开发出来的比较好的软件少些,但也能让人体会到Delphi的强大.我觉得,其实Delphi强不强大不重要,关键是谁在使用,Delphi已经提供了扩展机制,没有提供的功能你可以自己扩展啊,可以将使用C,C++或VC开发的三方类库导入到Delphi中来.看VC的书籍时,有句话说的挺好的,VC不是提供给你的食物,而是一把猎枪,但前提是你要做一个好的猎人.这句话适用于任何开发语言,开发工具.VC之所以生命力如此顽强,是因为他与Windows的紧密结合----开发思路上时刻关注着Windows内部原理,没有过多的依赖于类的封装.对于一个开发经验丰富的老鸟,当然会选择VC.而Delphi的优势是其RAD,高效优雅的封装,这些都是新手急切需要的,用的久了会产生依赖,让其说出Windows下程序的运行原理可能还是泛泛而谈,细节的东西接触不到,自然影响解决疑难问题的水平.那么如何能更好的使用Delphi呢,我觉得在封装底层类库的时候转换开发思路吧,向使用VC一样,时刻关注着Windows消息,掌握好常用的Windows API函数,引入更好的三方类库(不必刻意强求这些类库的开发语言,满足要求就好).在界面开发上是Delphi的强项,继续用鼠标拖拽吧,不过拖拽的核心控件是我们自己写出来的,这样依然可以发挥Delphi的优势,但程序实现更加直接自然,我们也能更好的掌握Windows开发的核心技术,不必受制于人.

  上面一片废话,不喜勿喷.总结记录一下学习MFC中的东西吧,这篇文章用来记录学习中的心得,随时想写了就在后面扩充了.

  1.VS2008下MFC如何为窗体类添加消息处理函数和事件处理函数

  •     在类视图中,右键需要添加处理函数的类,选择属性。
  •     在”属性“窗口中,单击“消息”按钮。
  •     在消息列表框中,选择需要添加的消息,点击下列列表,选择添加....
  •   可见VS2008下MFC开发中事件和消息处理也效仿C#类似的操作风格了.和Delphi也有些像,挺简单的.但更加强大,列出了所有可响应的系统消息和事件.
  •   2.LOWORD,HIWORD宏去32位整数的低16位和高16位.
  •   3.框架CMainFrame中获取当前视图:调用其成员函数CView GetActiveView() const;
  •   4.从视图中获取主框架对象:GetParent();
  •   5.获取CWinApp对象:调用全局AfxGetApp函数:CWinAPP *AFXAPI AfxGetApp()
  •   6.vs2008中如何为控件关联一个成员变量:
  •      在对话框上右键点击按钮,选择"添加变量",在弹出的"添加成员变量向导"对话框中,"变量类型"的地方直接写上自定义的类型(CNewButton)就可以了.这样就可以让CNewButton类的对象实例响应按钮控件的消息,执行虚函数了.
  •   7.要初始化对话框类的成员,可以在构造函数中进行,或在WM_INITDIALOG消息处理函数中进行,这个消息在窗口即将显示的时候触发,相当于Delphi的OnShow.
  •   8.在一个源文件中要想访问另一个源文件中定义的全局变量,必须在调用这个全局变量之前声明这个变量是在外部定义的.例如extern CStyleApp theApp;
  •   9.如何在CDocument中获取对应的视图:
  •       因为MVC架构中,每个文档可以对应多个视图,因此获取文档对应的视图对象需要迭代.可以调用文档对象的成员函数GetFirstViewPosition()返回一个POSITION类型的对象,以此对象作为参数调用GetNextView成员函数,返回CView对象指针,进行类型转换后得到视图对象.如果已经找到了所有对应的视图对象,则GetNextView函数返回NULL.单文档框架中,只有一个视图对象与文档对象相对应.
  •   10.如何在视图对象中获取对应的文档对象:
  •       调用GetDocument()成员函数.
  •   11.如何获取应用程序对象:
  •       调用全局函数AfxGetApp()或成员变量theApp.
  •   12.框架各部分指针获取:
  •  

    获得CWinApp

    获得CMainFrame

    获得CChildFrame

    获得CDocument

    获得CView

    在CWinApp中

     

    AfxGetMainWnd()

    m_pMainWnd

    AfxGetMainWnd()->MDIGetActive()

    AfxGetMainWnd()->GetActiveFrame()

    SDI:AfxGetMainWnd()->GetActiveView()->GetDocument()

    MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()->GetDocument()

    SDI:AfxGetMainWnd()->GetActiveView()  
    MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView() 

    在CMainFrame中

    AfxGetApp()

    theApp

     

    MDIGetActive()

    GetActiveFrame()

    SDI:GetActiveView()->GetDocument()  
    MDI:MDIGetActive()->GetActiveView()->GetDocument()  

    SDI:GetActiveView()  
    MDI:MDIGetActive()->GetActiveView() 

    在CChildFrame中

    AfxGetApp()

    theApp

    GetParentFrame() 

     

    GetActiveView()->GetDocument()  

    GetActiveView()

    在CDocument中

    AfxGetApp()

    theApp

    AfxGetMainWnd()  

    AfxGetMainWnd()->MDIGetActive()

    AfxGetMainWnd()->GetActiveFrame()

     

    POSITION   pos   =   GetFirstViewPosition();GetNextView(pos)  

    在CView中

    AfxGetApp()

    theApp

    AfxGetMainWnd()  

    GetParentFrame()  

    GetDocument()

     

    在其他类中

    AfxGetApp()

    AfxGetMainWnd()  

    AfxGetMainWnd()->MDIGetActive()

    AfxGetMainWnd()->GetActiveFrame() 

    SDI:AfxGetMainWnd()->GetActiveView()->GetDocument()

    MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()->GetDocument()

    SDI:AfxGetMainWnd()->GetActiveView()  
    MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView() 

     

    理一理MFC的这几个类的关系,可以很容易明白上面的这些乱七八糟的逻辑。

    App是应用域,所有的域中的东西都可以通过全局函数访问到它。

    MainFrame是主框架,也基本可以用全局函数访问到。

    MainFrame下是若干个ChildFrame,ChildFrame中若干个View和Document(可能不成对),ChildFrame管理着View,View和Document进行互操作。

    因此整体框架就出来了,一般除了直接应用的关系都可以通过MainFrame-->Active ChildFrame-->Active View-->Document这条线进行访问。

  •   13.在MainFrame中创建分割的多个子窗口
  •         要实现这个效果需要CSplitterWnd类.MSDN中对这个函数的描述:
  • CSplitterWnd object is usually embedded in a parent CFrameWnd or CMDIChildWnd object. Create aCSplitterWnd object using the following steps:

    1. Embed a CSplitterWnd member variable in the parent frame.

    2. Override the parent frame's CFrameWnd::OnCreateClient member function.

    3. From within the overridden OnCreateClient, call the Create or CreateStatic member function ofCSplitterWnd.

    范例:

     CRect rect;
     GetClientRect( &rect);
     CSize sizeTem,size = rect.Size();
     sizeTem=size;
     //调用CreateStatic后将会引发WM_SIZE消息,
     if(!m_wndSplitter.CreateStatic(this, 1, 2 ))
     {
      TRACE0( _T("Failed to create static splitter\n" ));
      return FALSE;
     }
     
     //创建第二个静态分割窗口2*1
     if( !m_wndSplitter2.CreateStatic(&m_wndSplitter,2,1,WS_CHILD|WS_VISIBLE,
      m_wndSplitter.IdFromRowCol(0,1)))
     {
      TRACE0( _T("Failed to create left view\n" ));
      return FALSE;
     }

     sizeTem.cy=size.cy/2;
     //创建第二个静态分割窗口的00窗格
     if( !m_wndSplitter2.CreateView( 0,0,
      RUNTIME_CLASS(CCustListView),
      sizeTem, pContext ))
     {
      TRACE0( _T("Failed to create right view\n" ));
      return FALSE;
     }
     
     sizeTem=size;
     sizeTem.cx=size.cx/3;
     
     //创建第一个静态分割窗口的00窗格
     if( !m_wndSplitter.CreateView( 0,0,
      RUNTIME_CLASS(CCustTreeView),
      sizeTem, pContext))
     {
      TRACE0( _T("Failed to create right view\n" ));
      return FALSE;
     } 
     //创建第二个静态分割窗口的10窗格
     if( !m_wndSplitter2.CreateView(1,0,
      RUNTIME_CLASS(CFileAttrView),
      sizeTem, pContext ) )
     {
      TRACE0( _T("Failed to create right view\n" ));
      return FALSE;
     }

     CCustTreeView* PTree=(CCustTreeView*)m_wndSplitter.GetPane(0,0);//获取子窗口
     CCustListView* PList=(CCustListView*)m_wndSplitter2.GetPane(0,0);
     if (::IsWindow(PList->m_list.m_hWnd)&&::IsWindow(PTree->m_tree.m_hWnd))
     {
      CShellList& shelllist=PList->m_list;
      CShellTree& shelltree=PTree->m_tree;
      shelltree.SetRelatedList (&shelllist);
     }
     return TRUE;

      14 在长时间运算时让界面相应鼠标键盘等消息

  • MSG msg;
    while(::PeekMessage(&msg,NULL,0,0,PM_REMOVE)) //使界面保持活动
    {
    ::TranslateMessage(&msg);
    ::DispatchMessage(&msg);
    }
  • 这个代码相当于Delphi或CBC中的Application.ProcessMessage函数.