科技行者

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

知识库

知识库 安全导航

至顶网软件频道ATL的GUI程序设计(四)

ATL的GUI程序设计(四)

  • 扫一扫
    分享文章到微信

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

介绍如何利用ATL来操作对话框,以及如何操作对话框上的各种控件。

作者:李马 来源:CSDN 2007年9月24日

关键字: ghost ATL GUI 程序设计

  • 评论
  • 分享微博
  • 分享邮件

在本页阅读全文(共2页)

四章 对话框和控件

对于Win32 GUI的程序设计来说,其实大部分的情况下我们都不需要自己进行窗口类的设计,而是可以使用Win32中与用户交互的标准方式——对话框(Dialog Box)。我们可以在VC IDE的资源设计器中设计对话框资源,并在其上放置各种控件资源——的确是非常方便。在本章里,李马将要向诸位介绍如何利用ATL来操作对话框,以及如何操作对话框上的各种控件。

题外话先

ATL,是的,正是由于我所讲的是“ATL的GUI程序设计”,所以我才可能将内容直接经由CWindowImpl过渡到CDialogImpl——而不是过渡到你先前所熟悉的CFrameWnd和Doc/View体系。况且,即使这之后我深入到了CDialogImpl之中,我也不会讲到你所熟悉的DDX/DDV机制。再三考虑之下,我还是决定把这些东西在CDialogImpl前一并当作题外话说出来,先。

再来回顾一下ATL的性质。它是一个被设计用来开发COM组件的Framework,所以对GUI部分的支持——套用一句2006年的流行语来说:那是相~~当~~(加重且延长声音地)少。于是,它没有“框架窗口”这个概念,更不会有Doc/View体系。其实我对MFC的这一设计特点感觉不错,毕竟它可以通过一个简单的CFrameWnd类来实现一个标准的SDI/MDI框架,而且其中带有工具栏、状态栏和一个用来容纳视图的标准的工作区域。我们可以通过控制框架窗口中的View及其相关的Doc类型来完成特定文档类型的读写与显示。——但是,很不幸,这一切都只属于伟大的MFC;在ATL中,我们什么都没有。

另外,在对话框的技术领域中,使用ATL的我们也不会享有数据交换与验证(DDX/DDV)的支持。这一所谓的缺憾我并不想多加评价,一是因为我并不了解MFC中DDX/DDV的内部机制,二是因为我直觉上认为这是影响MFC效率的罪魁之一。在MFC中,我们可以通过向导的支持轻易地为表单的输入域加入输入校验与限制,而且表现在源代码上的仅仅是几个宏而已——我自认天下没有免费的午餐,这几个简单的宏既然能为我们包办一切,那我们势必会相应地失去些东西,要不然忒便宜了也就。

题外话的最后不免落入俗套,我将会向诸位介绍解决以上缺憾的方法。——也许你猜到了,就是从WTL中寻找解决方案。WTL是对ATL的扩展,所以它的很多代码可以直接拿过来用(当然可能需要一些小小的修改)。而且,不知道WTL的设计者是不是为了拉拢MFC的开发人员,总之它里面添加了很多与MFC相似的元素,例如以上所说的框架窗口和DDX/DDV。

CDialogImpl

与ATL窗口类CWindowImpl相对应,ATL的对话框类名为CDialogImpl。它的定义如下:

template <class T, class TBase = CWindow>
class ATL_NO_VTABLE CDialogImpl : public CDialogImplBaseT< TBase >
{
// ...
};

你可以从上面的代码看到,CDialogImpl与CWindowImpl类似,也经历了一系列的继承链。不过,它较之CWindowImpl的模板参数要简单得多——毕竟是标准对话框,有些东西是不用操心的。

CDialogImpl的使用方法大致如下:

class CYourDlg : public CDialogImpl< CYourDlg >
{
public:
enum { IDD = IDD_YOUR_DLG };
public:
BEGIN_MSG_MAP( CYourDlg )
// 消息映射
END_MSG_MAP()
public:
// 消息响应函数
///////////////////
// 其余的部分...
};

和CWindowImpl不一样,CDialogImpl不需要使用DECLARE_WND_CLASS来定义窗口类。在原来DECLARE_WND_CLASS的位置,一个枚举代替了原来窗口类定义的部分。这里的枚举列表必须有一个被命名为IDD,并且它的值要被设置为相应的对话框资源ID。呃……写到这里,我仿佛已经感觉到了你的不快,但CDialogImpl的实现即是如此(以CDialogImpl::DoModal为例):

// from CDialogImpl::DoModal
return ::DialogBoxParam(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::IDD),
hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);

当然,如果你不喜欢这么做的话,也可以自己从CDialogImplBaseT派生出属于你的对话框类。

再回到CDialogImpl的话题上来。这个类主要有以下几个常用的成员函数:

成员函数 说明
DoModal 显示一个模态对话框
EndDialog 销毁一个模态对话框
Create 创建一个非模态对话框
DestroyWindow 销毁一个非模态对话框

这样看来是不是和MFC十分相似?事实上,如果你已经定义好了一个对话框类,那么它的使用和MFC的对话框类的确没什么两样:

CYourDlg dlg;
dlg.DoModal();

控件的使用

从与用户交互的角度来看,控件是对话框上必不可少的元素。在Win32 GUI程序设计中,对控件的操作大可归为两个方面:一是对控件进行操作,二是响应控件的事件。排除子类化的事件响应(后面我会专门介绍如何在ATL中进行控件的子类化),那么这两方面的具体实现就是:

  • 使用窗口操作的API函数或发送消息来操作控件。
  • 处理WM_COMMAND或WM_NOTIFY来响应控件的事件。

根据顺序,李马来为大家介绍一下如何对控件进行操作先。这通常可以经由CWindow及其派生类实现,以下代码示范了如何禁用一个控件:

CWindow ctrl = GetDlgItem( IDC_CONTROL );
ctrl.EnableWindow( FALSE );

如果你要操作的控件需要用到特定的特性(也就是通过发送消息来实现的特有行为),当然你可以通过使用CWindow::SendMessage来实现,不过我并不推荐你使用这种方法,因为SendMessage是不会对消息参数进行类型检查的。而且,考虑到代码的可复用性,你可以对CWindow进行派生以达到目的。例如,对于列表控件的封装可以是类似下面这个样子:

class CListBox : public CWindow
{
public:
int AddString( LPCTSTR lpszString )
{
return ::SendMessage( m_hWnd, LB_ADDSTRING, 0, (LPARAM)lpszString );
}
};

然后,这样进行调用:

CListBox list;
list.Attach( GetDlgItem( IDC_LIST ) );
list.AddString( _T("This is a test line") );

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

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

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