科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件MFC程序员的WTL指南之对话框与控件

MFC程序员的WTL指南之对话框与控件

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

MFC 的对话框和控件的封装真得可以节省你很多时间和功夫

作者:lithe 来源:BLOG 2007年10月19日

关键字: MFC WTL 控件

  • 评论
  • 分享微博
  • 分享邮件
MFC 的对话框和控件的封装真得可以节省你很多时间和功夫。没有MFC对控件的封装,你要操作控件就得耐着性子填写各种结构并写很多的SendMessage调用。MFC还提供了对话框数据交换(DDX),它可以在控件和变量之间传输数据。WTL 当然也提供了这些功能,并对控件的封装做了很多改进。本文将着眼于一个基于对话框的程序演示你以前用MFC实现的功能,除此之外还有WTL消息处理的增强功能。第五章将介绍高级界面特性和WTL对新控件的封装。

  回顾一下ATL的对话框

  现在回顾一下第一章 提到的两个对话框类,CDialogImpl 和 CAxDialogImpl。CAxDialogImpl用于包含ActiveX控件的对话框。本文不准备介绍ActiveX控件,所以只使用CDialogImpl。

  创建一个对话框需要做三件事:

  ·创建一个对话框资源

  ·从CDialogImpl类派生一个新类

  ·添加一个公有成员变量IDD,将它设置为对话框资源的ID。

  然后就像主框架窗口那样添加消息处理函数,WTL没有改变这些,不过确实添加了一些其他能够在对话框中使用得特性。

  通用控件的封装类

  WTL有许多控件的封装类对你应该比较熟悉,因为它们使用与MFC相同(或几乎相同)的名字。控件的方法的命名也和MFC一样,所以你可以参照MFC的文档使用这些WTL的封装类。不足之处是F12键不能方便地跳到类的定义代码处。

  下面是Windows内建控件的封装类:

  ·用户控件: CStatic, CButton, CListBox, CComboBox, CEdit, CScrollBar, CDragListBox

  ·通用控件: CImageList, CListViewCtrl (CListCtrl in MFC), CTreeViewCtrl (CTreeCtrl in MFC), CHeaderCtrl, CToolBarCtrl, CStatusBarCtrl, CTabCtrl, CToolTipCtrl, CTrackBarCtrl (CSliderCtrl in MFC), CUpDownCtrl (CSpinButtonCtrl in MFC), CProgressBarCtrl, CHotKeyCtrl, CAnimateCtrl, CRichEditCtrl, CReBarCtrl, CComboBoxEx, CDateTimePickerCtrl, CMonthCalendarCtrl, CIPAddressCtrl

  ·MFC中没有的封装类: CPagerCtrl, CFlatScrollBar, CLinkCtrl (clickable hyperlink, available on XP only)

  还有一些是WTL特有的类:CBitmapButton, CCheckListViewCtrl (带检查选择框的list控件), CTreeViewCtrlEx 和 CTreeItem (通常一起使用, CTreeItem 封装了HTREEITEM), CHyperLink (类似于网页上的超链接对象,支持所有操作系统)

  需要注意得一点是大多数封装类都是基于CWindow接口的,和CWindow一样,它们封装了HWND并对控件的消息进行了封装(例如,CListBox::GetCurSel()封装了LB_GETCURSEL消息)。所以和CWindow一样,创建一个控件的封装对象并将它与已经存在的控件关联起来只占用很少的资源,当然也和CWindow一样,控件封装对象销毁时不销毁控件本身。也有一些例外,如CBitmapButton, CCheckListViewCtrl和CHyperLink。

  由于这些文章定位于有经验的MFC程序员,我就不浪费时间介绍这些封装类,它们和MFC相应的控件封装相似。当然我会介绍WTL的新类:CBitmapButtonCBitmapButton类与MFC的同名类有很大的不同,CHyperLink则完全是新事物。

  用应用程序向导生成基于对话框的程序

  运行VC并启动WTL应用向导,相信你在做时钟程序时已经用过它了,为我们的新程序命名为ControlMania1。在向导的第一页选择基于对话框的应用,还要选择是使用模式对话框还是使用非模式对话框。它们有很大的区别,我将在第五章介绍它们的不同,现在我们选择简单的一种:模式对话框。如下所示选择模式对话框和生成CPP文件选项:


  第二页上所有的选项只对主窗口是框架窗口时有意义,现在它们是不可用状态,单击"Finish",再单击"OK"完成向导。

  正如你想的那样,向导生成的基于对话框程序的代码非常简单。_tWinMain()函数在ControlMania1.cpp中,下面是重要的部分:

int WINAPI _tWinMain (
 HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow )
 {
  HRESULT hRes = ::CoInitialize(NULL);

  AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES);

  hRes = _Module.Init(NULL, hInstance);

  int nRet = 0;
  // BLOCK: Run application
  {
   CMainDlg dlgMain;
   nRet = dlgMain.DoModal();
  }

  _Module.Term();
  ::CoUninitialize();
  return nRet;
}

  代码首先初始化COM并创建一个单线程公寓,这对于使用ActiveX控件的对话框是有必要得,接着调用WTL的功能函数AtlInitCommonControls(),这个函数是对InitCommonControlsEx()的封装。全局对象_Module被初始化,主对话框显示出来。(注意所有使用DoModal()创建的ATL对话框实际上是模式的,这不像MFC,MFC的所有对话框是非模式的,MFC通过代码禁用对话框的父窗口来模拟模式对话框的行为)最后,_Module和COM被释放,DoModal()的返回值被用来作为程序的结束码。

  将CMainDlg变量放在一个区块中是很重要的,因为CMainDlg可能有成员使用了ATL和WTL的特性,这些成员在析构时也会用到ATL/WTL的特性,如果不使用区块,CMainDlg将在_Module.Term()(这个函数完成ATL/WTL的清理工作)调用之后调用析构函数销毁自己(和成员),并试图使用ATL/WTL的特性,这将导致程序出现诊断错误崩溃。(WTL 3的向导生成的代码没有使用区块,使得我的一些程序在结束时崩溃)

  你现在可以编译并运行这个程序,尽管它只是一个简陋的对话框:


  CMainDlg 的代码处理了WM_INITDIALOG, WM_CLOSE和三个按钮的消息,如果你喜欢可以浏览一下这些代码,你应该能够看懂CMainDlg的声明,它的消息映射和它的消息处理函数。

  这个简单的工程还演示了如何将控件和变量联系起来,这个程序使用了几个控件。在接下来的讨论中你可以随时回来查看这些图表。


  由于程序使用了list view控件,所以对AtlInitCommonControls()的调用需要作些修改,将其改为:

AtlInitCommonControls ( ICC_WIN95_CLASSES );

  虽然这样注册的控件类比我们用到的多,但是当我们向对话框添加不同类型的控件时就不用随时记得添加名为ICC_*的常量(译者加:以ICC_开头的一系列常量)。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章