• 第六课——创建和使用控件


    一、何为控件

    • 控件:在系统内部定义的用于和用户交互的基本单元。
    • 分类:Windows普通控件(如编辑框、列表框、组合框等)、MFC扩展控件、ActiveX控件
    • 常用控件:静态控件、按钮、编辑框、列表框、组合框、滚动条、旋转按钮控件、日期时间控件
    • 控件的优势:简化编程、完成常用的功能

    二、创建控件

    情形一:在对话框模板中用编辑器指定控件(常用)

    情形二:调用MFC相应控件类的成员函数Create来创建

    • 补充:常用控件类有CStatic、CButton、CEdit、CListBox、CComboBox等。

      下面以情形二来创建一个按钮:基于对话框的应用程序Ex_Create→ClassView选项卡(右击CEx_CreateDlg类名)→Add Member Variable(变量类型为CButton,变量名为m_btnWnd)→双击OnInitDialog函数名转至其实现代码处→添加如下代码。

    BOOL CEx_CreateDlg::OnInitDialog()
    {
    	CDialog::OnInitDialog();
        ...
        // TODO: Add extra initialization here
        m_btnWnd.Create("你好", WS_CHILD | WS_VISIBLE
    					| BS_PUSHBUTTON | WS_TABSTOP,
    					CRect(20, 20, 120, 40), this, 201);		 //创建
        CFont *font = this->GetFont();           //获取对话框的字体
        m_btnWnd.SetFont(font);                  //设置控件字体
        return TRUE;  // return TRUE  unless you set the focus to a control
    }

    分析一:

    ①由于OnInitDialog函数在对话框初始化时被调用,因此将对话框中的一些初始化代码都添加在此函数中。

    ②CButton类成员函数Create用来创建按钮控件。其第一个参数用来指定按钮的标题;第二个参数用来指定按钮控件的样式,其中BS_PUSHBUTTON(以BS_开头的)是按钮类封装的预定义样式,表示创建的是按键按钮;而WS_CHILD(子窗口)、WS_VISIBLE(可见)、WS_TABSTOP(可用Tab键选择)等都是CWnd类封装的预定义窗口样式,它们都可以直接引用;第三个参数用来指定它在父窗口中的位置和大小;第四个参数用来指定父窗口指针;最后一个参数指定该控件的标识值。

    ③由于按钮是作为对话框的一个子窗口来创建的,因此WS_CHILD样式是必不可少的,且还要使用WS_VISIBLE使控件在创建后显示出来。

    ④由于Windows操作系统使用的是图形界面,因此在MFC中,对于每种界面元素的几何大小和位置常使用CPoint类(点)、CSize类(大小)和CRect类(矩形)来描述。

    分析二:

    ①控件编程创建方法是使用各自封装的类(即各控件类)的Create成员来创建。其优点是能动态创建(即运行时才创建控件),但它涉及的编程内容比较复杂,且不能发挥对话框编辑器可视化的优点。

    ②在MFC中,每一种类型的控件都用相应的类来封装。

    三、控件的消息

    • 通知消息:当控件的状态发生改变时,控件就会向其父窗口发送消息,这个消息称为“通知消息”。

    对于每个消息,系统都会用一个MSG结构来记录,MSG具有下列原型:

    typedef struct tagMSG {         //msg
        HWND        hwnd;           //消息发向的(接收到消息的)窗口的句柄
        UINT        message;        //主消息的标识值
        WPARAM      wParam;         //附消息值,其具体含义依赖于主消息值
        LPARAM      lParam;         //附消息值,其具体含义依赖于主消息值
        DWORD       time;           //消息放入消息队列中时的时间
        POINT       pt;             //消息放入消息队列中时的鼠标坐标
    }MSG;
    • 对于一般控件,其通知消息通常是一条WM_COMMAND消息,该消息的wParam参数的低位字中含有控件标识符,wParam参数的高位字则为通知代码,lParam参数则是指向控件的句柄
    • 而对于有些控件,其通知消息通常是一条WM_NOTIFY消息,该消息的wParam参数是发送通知消息的控件的标识符,而lParam参数则是指向一个结构指针

    四、映射控件消息

      不管是什么控件消息,一般都可以用MFC ClassWizard对它们加以映射。

    以一个标识符为IDC_BUTTON1的按键按钮为例:MFC ClassWizard对话框(Message Maps选项卡)→类名选定为CEx_CreateDlgObjects IDs选定为IDC_BUTTON1)→双击Messages列表框中的(要映射的)BN_CLICKED消息→在CEx_CreateDlg类中添加该消息的映射函数OnButton1→双击消息函数OnButton1定位到CEx_CreateDlg:: OnButton1代码实现处→添加如下代码→编译并运行。

    void CEx_CreateDlg::OnButton1()
    {
    	// TODO: Add your control notification handler code here
        MessageBox(_T("你按下了"Button1"按钮!"));
    }

    说明:

    ①不同资源对象(控件、菜单命令等)所产生的消息是不同的。例如,按键按钮IDC_BUTTON1的消息有两个:BN_CLICKED和BN_DOUBLECLICKED,分别表示当用户单击或双击该按钮时产生的消息。

    ②不需要对对话框中的“确定”和“取消”按钮进行消息映射,因为系统已自动设置了这两个按钮的动作,当用户单击这两个按钮时都将自动关闭对话框,且确定按钮动作还使得对话框数据有效。

    五、映射控件通用消息

    上述过程是映射一个控件的某一个消息,事实上也可以通过WM_COMMAND消息的映射来处理一个或多个控件的通用消息

    且以一个标识符为IDC_BUTTON1的按键按钮为例:MFC ClassWizard对话框(Message Maps选项卡)→类名选定为CEx_CreateDlgObjects IDs选定为CEx_CreateDlg)→双击Messages列表框中的(要映射的)OnCommand消息→在CEx_CreateDlg类中添加该消息的映射函数OnCommand→双击消息函数OnCommand定位到CEx_CreateDlg:: OnCommand代码实现处→添加如下代码→编译并运行。

    BOOL CEx_CreateDlg::OnCommand(WPARAM wParam, LPARAM lParam)
    {
    	// TODO: Add your specialized code here and/or call the base class
        WORD nCode = HIWORD(wParam);		//控件的通知消息
        WORD nID = LOWORD(wParam);			//控件的ID号
    	if ((nID == 201) && (nCode == BN_CLICKED))
    		MessageBox(_T("你按下了"你好"按钮!"));
    	if ((nID == IDC_BUTTON1) && (nCode == BN_CLICKED))
    		MessageBox(_T("这是在OnCommand处理的结果!"));
    	return CDialog::OnCommand(wParam, lParam);
    }

    说明:

    ①OnCommand函数是一个用来处理WM_COMMAND消息的虚函数,故而这里添加的OnCommand函数事实上是一个在类中实际调用的函数,可称为“实例函数”。这样的映射操作,可以称为“对虚函数OnCommand的重载”。

    ②在上述编写的代码中,Button1按钮的BN_CLICKED消息用不同的方式处理了两次,即同时存在两种函数OnButton1和OnCommand,故若单击Button1按钮,系统首先执行OnCommand函数,然后执行OnButton1代码。之所以还能执行OnButton1函数代码,是因为OnCommand函数的最后一句代码“return CDialog::OnCommand(wParam, lParam);”,它将控件的消息交由对话框其他函数处理。

    ③由于用Create创建的控件无法用MFC ClassWizard直接映射其消息,因此上述方法弥补了ClassWizard的不足,使用时要特别注意。

    六、使用控件

    • 使用控件之前需获得该控件的类对象指针或映射一个对象,然后通过该指针或对象来引用其成员函数进行操作。

    下表是MFC封装的常用控件类:表3.1

    获取一个控件的类对象指针:通过CWnd类的成员函数GetDlgItem来实现

    //GetDlgItem函数声明
    CWnd* GetDlgItem(int nID) const;
    void GetDlgItem(int nID, HWND *phWnd) const;

    说明:

    ①nID:指定控件或子窗口的ID值

    ②第一个版本:通过函数来返回CWnd类指针

    ③第二个版本:通过函数形参phWnd来返回其句柄指针

    • 注:CWnd类(第三课有提及)是通用的窗口基类,故想要调用实际的控件类及其基类成员,要对返回值进行类型转换,如CButton *pBtn = (CButton*)GetDlgItem(IDC_BUTTON1);

    七、控件对象

    • 控件变量:控件相关联的成员变量(在Member Variables选项卡添加)
    • 控件变量分为两种类型:用于操作的控件对象、用于存取的数据变量
    • 注:它们都是与控件或子窗口进行绑定,但MFC只允许每种类型仅绑定一次。

    为了理解上述两种类型,下面看示例:基于对话框的应用程序Ex_Member→添加ID为IDC_BUTTON1的按钮控件和ID为IDC_EDIT1编辑框控件→MFC ClassWizard对话框(Member Variable选项卡)→类名选定为CEx_MemberDlg(Control IDs选定为IDC_BUTTON1)→单击Add Variable按钮(弹出Add Member Variable对话框)→成员变量名为m_btnWnd(类别项为Control)→MFC ClassWizard对话框(Member Maps选项卡)→为CexMemberDlg添加IDC_BUTTON1的BN_CLICKED消息映射函数OnButton1→添加如下代码。

    void CEx_MemberDlg::OnButton1() 
    {
    	// TODO: Add your control notification handler code here
    	CString strEdit;								//定义一个字符串
    	CEdit *pEdit = (CEdit*)GetDlgItem(IDC_EDIT1);	//获取编辑框中的内容
    	pEdit->GetWindowText(strEdit);
    	strEdit.TrimLeft();
    	strEdit.TrimRight();
    	if (strEdit.IsEmpty())
    		m_btnWnd.SetWindowText(_T("Button1"));		//将m_btnWnd的内容设定为按钮控件的标题
    	else
    		m_btnWnd.SetWindowText(strEdit);
    }

    说明:

    成员变量m_btnWnd与控件IDC_BUTTON1相关联

    ②控件按钮IDC_BUTTON1的编程操作可用与之绑定的对象m_btnWnd来操作

         

    八、DDXDDV技术

    • 概述:对于控件的数据变量MFC提供了DDXDDV技术。
    • DDX:将数据成员变量同对话类模板内的控件相联接(方便数据在控件间传输)
    • DDV:用于数据的校验

    某控件与一个数据变量相绑定后,就可以用CWnd::UpdateData函数实现控件数据的输入和读取

    UpdateData函数:只有一个参数,它为TRUEFALSE。当在程序中调用UpdateData(TRUE)或不带参数的UpdateData()时,数据从控件向相绑定的成员变量复制;反之,数据则由控件绑定的成员变量向控件传输。

    说明:数据变量的类型由被绑定的控件类型而定。

    使用示例(建立在项目Ex_Member的基础上):MFC ClassWizard对话框(Member Variable选项卡)→类名选定为CEx_MemberDlgControl IDs选定为IDC_EDIT1单击Add Variable按钮(弹出Add Member Variable对话框)成员变量名为m_strEdit(类别项为Value)→出现Maximum Characters编辑框(这就是控件变量的DDV设置)→ClassView选项卡(展开CEx_MemberDlg类结点)→双击OnButton1成员函数结点(定位到CEx_MemberDlg::OnButton1函数实现代码处)→改写如下代码。

    void CEx_MemberDlg::OnButton1()
    {
    	// TODO: Add your control notification handler code here
        UpdateData();       //没有参数,表示使用的是默认参数值TRUE
        m_strEdit.TrimLeft();
        m_strEdit.TrimRight();
        if (m_strEdit.IsEmpty())
    		m_btnWnd.SetWindowText(_T("Button1"));
    	else
    		m_btnWnd.SetWindowText(m_strEdit);
    }
    
  • 相关阅读:
    UVA11584 划分成回文串
    UVA1220Party at Hali-Bula(树的最大独立集 + 唯一性判断)
    BUAA1389愤怒的DZY(最大值最小化)
    九度1502 最大值最小化问题
    App(4.25)
    App(4.24)
    App(4.23)
    App(4.22)
    学习进度条(八)
    App(4.21)
  • 原文地址:https://www.cnblogs.com/xzxl/p/7941751.html
Copyright © 2020-2023  润新知