昨天学习了MFC的对话框的添加和简单的使用,了解到对话框有模态和非模态两种区别。今天继续学习对话框的使用,主要是来讨论对话框控件的访问。我们今天使用VS2008新建一个MyDlg1项目,然后按照昨天的思路添加资源对话框,创建CDlg类绑定对话框资源,然后添加菜单“对话框”用于点击时显示模态的对话框。具体的步骤是:
1. 添加新资源:对话框
2. 为对话框创建类CDlg::publicCDialog
3. 新建菜单“对话框”
4. 为“对话框”添加事件响应,添加到View类下
5. 在响应函数中添加创建显示模态对话框的代码
     在这个基础之上,我们从右侧隐藏的工具栏中拖动静态文本框和编辑框空间,添加一个Add按钮,布局如下:
C/C++拾遗(二十三):MFC-对话框-2-LMLPHP

一、静态文本控件的事件响应
     一般来说静态文本控件主要用来作为标签起到注释的作用,如上面的对话框用来说明其右侧编辑框的意义。但是有时候我们也想编辑静态文本框,使得其可以响应一些操作,比如我们点击"Number1"时显示的名称会发生改变。为了实现这一个目的,我们需要以下工作:
1. 修改静态文本控件的ID
     静态文本控件一般用于注释不需要编辑,因此其默认具有统一的ID:IDC_STATIC,我们需要将其修改为IDC_NUMBER1。
2. 在其属性栏中修改Notify为True使得其可以接受消息
3. 双击控件添加、编辑响应函数
     由于MFC中为每个控件都提供了ID用于标识,因此我们使用ID作为空间识别引用的手段。CWnd类为我们提供了三个函数用于实现静态文本控件的事件响应,具体用法可查询MSDN:
--GetDlgItem():接收一个控件ID,返回指向该窗口或控件的指针;
--GetWindowText():接收一个控件ID,获取其文本值;
--SetWindowText():接收一个文本值,设置对应控件的文本值;
     具体实现代码如下:

点击(此处)折叠或打开

  1. void CDlg1::OnStnClickedNumber1()
  2. {
  3.     CString str;
  4.     if (GetDlgItem(IDC_Number1)->GetWindowText((str)), str == L"Number1")
  5.     {
  6.         GetDlgItem(IDC_Number1)->SetWindowText(L"数值1:");
  7.     }
  8.     else
  9.     {
  10.         GetDlgItem(IDC_Number1)->SetWindowText(L"Number1");
  11.     }

  12.     // TODO: 在此添加控件通知处理程序代码
  13. }
      运行的结果是,当点击标签"Number1"时会发生改变为”数值1“:
C/C++拾遗(二十三):MFC-对话框-2-LMLPHP


二、编辑框控件
     这里我们的目的是实现一个MFC入门的时候经常使用的例子,记得当时接触过一段C#,首先编写的也是一个这样的加法计算器程序。这里实现num1和num2的求和,结果放入到num3中。为了实现这个效果,必须对编辑框的文本值进行读取、处理和最后的写入,我们可以继续使用上面类似的SDK,需要注意的是编辑框控件的文本值是wchar_t的,需要转换成int才可以进行运算,得到结果之后还需要再转换成wchar_t:
--使用GetDlgItem()获取目标控件的指针
--使用GetWindowTextW获取目标控件的文本值,写入变量
--使用SetWindowTextW将特定的wchar_t字符串设置为控件的文本显示
--使用_wtoi和_itow实现wchar_t与int的转换

点击(此处)折叠或打开

  1. void CDlg1::OnBnClickedAdd()
  2. {
  3.     int num1, num2, num3;
  4.     wchar_t ch1[10], ch2[10], ch3[10];

  5.     GetDlgItem(IDC_EDIT1)->GetWindowTextW(ch1, 10);
  6.     GetDlgItem(IDC_EDIT2)->GetWindowTextW(ch2, 10);



  7.     num1 = _wtoi(ch1); //atoi的宽字符版
  8.     num2 = _wtoi(ch2);
  9.     num3 = num1 + num2;

  10.     _itow(num3, ch3, 10); //itoa的宽字符版,可以查阅MSDN
  11.     GetDlgItem(IDC_EDIT3)->SetWindowTextW(ch3);


  12.     // TODO: 在此添加控件通知处理程序代码


  13. }
      运行结果如下:
C/C++拾遗(二十三):MFC-对话框-2-LMLPHP
     这里使用最基本的SDK来写,有助于我们弄清整个过程的实现思路。明白这一点之后,可以使用MFC为我们提供的其他函数来简化一些操作,比如:
--使用GetDlgItemText取代GetDlgItem与GetWindowTextW两个函数
--使用GetDlgItemInt取代GetDlgItemText和_wtoi两个函数
     使用上面两种函数替代之后效果是一样的,都可以实现我们的目的。以上是使用SDK来实现的,下面我们使用更像MFC风格的方法来实现,通过为控件绑定变量来实现,这样我们就可以直接操作类的成员变量了。
1. 右键单击控件IDC_EDIT1,选择添加变量
2. 在弹出的对话框中”类别--value“, 变量类型-int,具体设置如下,其中的控件ID应为IDC_EDIT1:
C/C++拾遗(二十三):MFC-对话框-2-LMLPHP
3. 依次为IDC_EDIT2和IDC_EDIT3绑定变量
4. 编译运行,可以看到MFC为三个编辑控件设定了默认值0,这时查看Dlg1.h/cpp会发现添加变量的声明和构造函数的默认初始化
C/C++拾遗(二十三):MFC-对话框-2-LMLPHP
CDlg.h中的声明代码:

点击(此处)折叠或打开

  1. protected:
  2.     virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持

  3.     DECLARE_MESSAGE_MAP()
  4. public:
  5.     afx_msg void OnStnClickedNumber1();
  6.     afx_msg void OnBnClickedAdd();
  7.     afx_msg void OnEnChangeEdit1();

  8.     int m_num1;
  9.     int m_num2;
  10.     int m_num3;
  11.     afx_msg void OnBnClickedOk();
CDlg.cpp中的构造函数:

点击(此处)折叠或打开

  1. CDlg1::CDlg1(CWnd* pParent /*=NULL*/)
  2.     : CDialog(CDlg1::IDD, pParent)
  3.     , m_num1(0)
  4.     , m_num2(0)
  5.     , m_num3(0)
  6. {

  7. }
5.由于变量添加在对话框绑定的类内部,因此直接双击Add按钮,编写其响应函数:

点击(此处)折叠或打开

  1. void CDlg1::OnBnClickedAdd()
  2. {
  3.     /*
  4.     int num1, num2, num3;
  5.     wchar_t ch1[10], ch2[10], ch3[10];

  6.     //GetDlgItem(IDC_EDIT1)->GetWindowTextW(ch1, 10);
  7.     //GetDlgItem(IDC_EDIT2)->GetWindowTextW(ch2, 10);

  8.     //另一种实现
  9.     //GetDlgItemText(IDC_EDIT1, ch1, 10);
  10.     //GetDlgItemText(IDC_EDIT2, ch2, 10);

  11.     //更加简便的实现
  12.     num1 = GetDlgItemInt(IDC_EDIT1);
  13.     num2 = GetDlgItemInt(IDC_EDIT2);


  14.     //num1 = _wtoi(ch1); //atoi的宽字符版
  15.     //num2 = _wtoi(ch2);
  16.     num3 = num1 + num2;

  17.     //_itow(num3, ch3, 10); //itoa的宽字符版,可以查阅MSDN
  18.     //GetDlgItem(IDC_EDIT3)->SetWindowTextW(ch3);
  19.     //SetDlgItemText(IDC_EDIT3, ch3);

  20.     SetDlgItemInt(IDC_EDIT3, num3);

  21.     // TODO: 在此添加控件通知处理程序代码
  22.     */


  23.     UpdateData();
  24.     m_num3 = m_num1 + m_num2;
  25.     UpdateData(FALSE);
  26. }
      上面把之前的实现代码一并列上便于分析比较,最后的这种直接绑定类变量的方法需要注意以下几点:
1. 由于将对话框的控件与类变量绑定,在绑定时设置好了类型,因此MFC会为我们定义声明并自动为我们进行类型检查;
2. 关键代码就是一句:num3 = num1 + num2
3. 对话框数据交换由函数DoDataExchange完成,但是该函数不会自动调用,需要我们人工调用
4. CWnd提供了UpdateData函数进行调用DoDataExchange函数,默认参数true表示获取对话框数据,false表示初始化对话框的控件
5. 我们先调用UpdateData()获取对话框当前数据,再使用FALSE标识初始化对话框IDC_EDIT3
C/C++拾遗(二十三):MFC-对话框-2-LMLPHP
      实现的效果是一样的,但是代码要简便了许多。在弄清原理之后推荐使用这种方式来实现编辑框控件的操作。通过今天的学习,我们发现MFC通过控件的ID进行标识,相关的SDK也以此作为参数返回其可引用的指针;不同的控件之间可以进行数据交换,我们可以通过SDK实现,也可以通过绑定MFC变量实现,后者的实现更加简便,但是删除控件时比较麻烦。


09-14 11:36