MFC 之 对话框编程入门

原文地址: http://my.oschina.net/zhongxhua/blog/15273



下面我们来设计这个程序的UI,首先在“视图”菜单中选择“工具箱”,这个工具箱窗口中,列出了很多常用的Windows控件(如按钮、复选框、编辑框、标签等),点击一个控件,此时鼠标变为十字型,像使用画图工具一样在设计器上绘出该控件,也可以同过拖拽的方法将控件直接拖到UI设计器中的对话框上,还可以直接双击工具栏中的控件。

在UI设计器上的静态标签“TODO: 在此放置对话框控件。”可以将其删掉。按照上述方法在对话框上绘制一个按钮控件,右击此控件,选择“属性”会出现属性窗口,在这个窗口中,左侧是控件的一种属性,右侧是该属性的当前值,在属性窗口的低端是属性的具体含义。对于按钮控件,我们现在关注Caption属性,即按钮上显示的文字,我们将其设为“Hello World”,输入完毕后按回车键确定。在UI设计器上的那个按钮已经变为“Hello World”了。在看一下按钮的ID属性,这个ID表示对话框每个控件唯一的标识(注意ID为IDC_STATIC的控件代表该控件为静态的,在程序运行时不可以动态的改变改控件的属性,如标签控件。但我们亦可以通过,修改标签的ID改为非IDC_STATIC值,这样这个控件就转为动态控件了,此种控件可以用IDC_STATIC来标识,IDC_STATIC没有唯一的限制,),我们一般需要将该属性值改为更有意义的,如IDC_HELLOWORLD。

下面我们为按钮控件编写事件响应代码,右击Hello World按钮,选择“添加事件处理程序”,依然弹出了一个向导对话框,在消息类型中选择选择按钮要响应的消息,在这个程序中我们是要响应按钮的单击事件(其实在一般情况下,按钮就是用来单击的),所以保持默认“BN_CLICKED”,在类列表中说明了响应代码是作为哪个类的成员函数,默认选择那个以“Dlg”结尾的类,这个类是继承于CDialog类的一个派生类。程序员可以设置自己的“函数处理程序名称”。完成后点击“添加编辑”按钮,进入代码编辑器编辑代码(对于按钮这种简单控件,我们要添加其响应代码,一般在UI设计器中直接双击这个控件即可直接进入到代码编辑器中编辑响应默认消息的函数)。

系统为我们自动在CHelloWorldDlg类中添加了OnBnClickedHelloworld()函数,该函数的声明部分在HelloWorldDlg.h文件中,在VS9开发环境的右侧“解决方案资源管理器”中双击该文件,或在HelloWorldDlg.cpp文件中右击,在弹出菜单中选择“转到头文件”。让我们来看一下这个MFC框架是如何构成的。

在这个头文件的头部有一行“#pragma once”,这是条编译命令,功能是让次头文件(Header)在编译时只被编译一次,因为同一个头文件可能被包含(include)过多次。在这个头文件中定义了CHelloWorld类,在这个类中声明了一个HICON类型的m_hIcon成员变量,这是个描述该应用程序图标的变量。如果你不了解HICON这个非标准类型,可以在代码的HICON处右击鼠标,然后选择“转到声明”或“转到定义”,这是VS9会自动定位光标到HICON的声明或定义代码处,笔者认为这是一个非常体贴的功能,为团队开发提供了很大的便利。

这里,我们顺便来简单谈谈MFC采用的“匈牙利标识符命名法”,这是一个约定,可以增加代码的可读性。如果你声明或定义了一个类,那么这个类可以一“C”(class)为前缀,如CHelloWorldDlg类,如果要定义一个无符号型的局部变量,那么可以用“u”(unsigned)为前缀,如UINT uPort; ULONG uFlags;如果是int或long类型的变量则以“n”为前缀,DWORD类型的变量前缀为“dw”,字符数组以“sz”作为前缀,CString类的对象以“str”作为前缀,指针以“lp”或“p”(long pointer或pointer,在WIN32环境下这两种指针并没有什么差别)作为前缀,引用以“r”为前缀,布尔型变量以“b”为前缀,句柄型的变量以“h”(handle)作为前缀。如果变量是全局的,那么以“g_”(global)开头,如BOOL g_bFlags;如果是类的成员变量则以“m_”(member)开头,如HICON m_hIcon;。

讨论完MFC的命名规则,让我们继续看这个头文件,在此类中声明了一个标准构造函数CHelloWorldDlg(CWnd* pParent = NULL);可选形参CWnd* pParent指定此对话框的父窗口。

代码enum { IDD = IDD_HELLOWORLD_DIALOG };的意思是MFC巧妙的将ID为IDD_HELLOWORLD_DIALOG的对话框资源与CHelloWorldDlg类绑定在一起。

这些除外的成员函数都是对父类CDialog中成员函数的重载。

成员函数virtual void DoDataExchange(CDataExchange* pDX);是用来支持DDX(对话框数据交换,将一个变量和一个控件进行绑定的时候用DDX)和DDV(对话框数据效验,检验该控件是否为你所需要的时候用DDV)机制的成员函数。

成员函数virtual BOOL OnInitDialog();是在对话被创建(Create)后立即被执行的函数,因此在这里可以添加对话框的初始化所需要的自定义代码。

成员函数afx_msg void OnSysCommand(UINT nID, LPARAM lParam);是对话框的处理WM_SYSCOMMAND消息的函数。WM_SYSCOMMAND消息是关于系统控制的消息,如鼠标在标题栏上的操作等。

成员函数afx_msg void OnPaint();是对话框处理WM_PAINT的函数,当对话框窗体发生重绘时有WM_PAINT消息到达程序。

成员函数afx_msg HCURSOR OnQueryDragIcon();当用户拖动最小化窗口时系统调用此函数取得光标显示。

接下来是一个DECLARE_MESSAGE_MAP()宏,这是MFC处理消息用的,具体资料可以查阅MSDN。

最下一行afx_msg void OnBnClickedHelloworld();就是刚自动生成的处理按钮单击消息的处理函数。

读者可能注意到了afx_msg,在MFC中,只要是处理消息的响应函数,在声明时,都要加上afx_msg。通过查找其定义,笔者认为这个并没有什么功能性意义,只是一个占位用的或是一个说明标识。

我们分析完HelloWorldDlg.h文件后,再来看看HelloWorldDlg.cpp文件。在文件的include部分,包含了stdafx.h文件,读者可以在“”stdafx.h””上右击鼠标,打开该头文件,在这个头文件中包含了该MFC程序必要的文件,如果程序员要添加自定义类,如果类中还需要MFC支持,那么必须包含这个头文件。HelloWorld.h文件中定义了ChelloWorldApp类(继承于CWinApp),是MFC的应用程序类。一个MFC WIN32应用程序必须是在CWinApp对象之上的,在CHelloWorldApp类中的InitInstance()成员函数的定义中,有相应加载该对话框的代码(CHelloWorldDlg dlg;之后的代码)。

然后是一组宏定义#ifdef _DEBUG #define new DEBUG_NEW #endif,_DEBUG宏对应前面提到的Debug模式。

接下来定义了另一个对话框类CAboutDlg,这是个“关于”对话框的类,用来显示程序版权信息的。

来看看BEGIN_MESSAGE_MAP() …… END_MESSAGE_MAP()这组宏定义,在这中间的代码就是MFC用来指定哪个消息用哪个成员函数来响应。对于那些无需指定的,MFC则没有明确指定,如ON_WM_PAINT()是指定处理WM_PAINT消息的成员函数是OnPaint(),但,这个用户一般不会去更改,所以在这里就没有去明确指定。但ON_BN_CLICKED()中,却指定了具体的成员函数:ID值为IDC_HELLOWORLD的控件的BN_CLICKED消息由CHelloWorldDlg类的OnBnClickedHelloworld()成员函数来处理。

在看看OnInitDialog()函数的定义部分,首先调用了父类了初始化函数,接下来到SetIcon前,是将“关于”加载到了系统菜单中,这样用户在单击程序窗体左上角的图标时,或右击标题栏时,或右击任务栏长条图标时,弹出的菜单就会包含“关于”的菜单项。

SetIcon()的后面有相应注释:“设置大图标”和“设置小图标”。

在OnSysCommand()函数中,处理了有关标题栏上发生的事件,代码(nID & 0xFFF0) == IDM_ABOUTBOX表示,如果用户点击了标题栏系统菜单中的“关于”菜单项,显示“关于”对话框。

在OnPaint()函数中的代码,是用来实现重绘操作的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值