精华内容
下载资源
问答
  • Windows基础控件

    2014-04-27 21:51:36
    一、Windows控件概述 Windows窗体中只能容纳Windows窗体控件,控件是带有可视化表示形式的组件,所有Windows窗体控件都是从System.Windows.Form.Control类派生的。Control类是定义控件的基类。Control类实现向用户...

    一、Windows控件概述

        Windows窗体中只能容纳Windows窗体控件,控件是带有可视化表示形式的组件,所有Windows窗体控件都是从System.Windows.Form.Control类派生的。Control类是定义控件的基类。Control类实现向用户显示信息的类所需的基本功能,它处理用户通过键盘和鼠标设备所进行的输入。Windows窗体控件都是以类的形式提供的。

        在Visual Studio2010开发环境中,常用的控件可分为文本类控件、选择类控件、分组控件、菜单控件、工具栏控件以及状态栏控件。Windows应用程序控件的基类是位于System.Windows.Form命名空间的Control基类。Control类定义了控件类的共同属性、方法和事件,其他的控件类都直接或者间接派生自这个基类。

    几种常用控件的作用如表所示

    控件分类

    作用

    文本类控件

    文本类控件可以在控件上显示文本

    选择类控件

    主要为用户提供选择的项目

    分组控件

    使用分组控件可以将窗体中的其他控件进行分组处理

    菜单控件

    为系统制作功能菜单,将应用程序命令分组,使他们更容易访问

    工具栏控件

    提供了主菜单中常用的相关工具

    状态栏控件

    用于显示窗体上的对象的相关信息,或者可以显示应用程序的信息

     

    二、控件的相关操作

        对控件的相关操作包括添加控件、对齐控件、锁定控件和删除控件等。

    1、添加控件

        可以通过“在窗体上绘制控件”、“将控件拖拽到窗体上”和“以编程方式向窗体添加控件”这三种方法添加控件。

    ◆在窗体上绘制控件

        在工具箱中单击要添加到窗体的控件,然后在该窗体上单击控件左上角位于的位置,然后拖动到该控件右下角位于的位置,控件按指定的位置和大小添加到窗体中。

    ◆将控件拖拽到窗体上

        在工具箱中单击所需要的控件并将其拖拽到窗体上,控件以其默认大小添加到窗体的指定位置上。

    ◆以编程方式向窗体添加控件

        通过new关键字实例化要添加控件所在的类,然后将实例化的类添加到窗体中。

    例:通过Button按钮的Click事件添加一个TextBox控件,代码如下:

    privatevoid button1_Click( object sender, System.EventArgs e ){

        TextBox myTest = new TextBox();    //实例化TextBox类

        myTest.Location = new Point( 25, 25 );  //设置对象的Location属性

        this.Controls.Add( myTest );  //将控件添加到当前窗体中

    }

     

    2、对齐控件

        选定一组控件,这些控件需要对齐。在执行对齐之前,首先选定主导控件(首先被选定的控件就是主导控件)。控件组的最终位置取决于主导控件的位置,再选择菜单栏中的“格式”/“对齐”命令,然后选择对齐方式。

    ◆左对齐:将选定控件沿他们的左边对齐

    ◆右对齐:将选定控件沿他们的右边对齐

    ◆居中对齐:将选定控件沿他们的中心点水平对齐

    ◆顶端对齐:将选定控件沿他们的顶边对齐

    ◆中间对齐:将选定控件沿他们的中心点垂直对齐

    ◆底部对齐:将选定控件沿他们的底边对齐

     

    3、锁定控件

    在控件的“属性”窗口中,单击Locked属性并选择True。此外,还可以右击控件并选择“锁定控件命令”。如果要锁定窗体上的所有控件,可以选择菜单栏中的“格式”/“锁定控件”命令。

     

    4、删除控件

    删除控件简单,可以在控件上单击鼠标右键,在弹出的快捷菜单中选择“删除”命令进行删除,或者选中控件,然后按下Delete键。

     

    三、关于Control类

        System.Windows.Froms命名空间中有一个特殊的类,它是每个控件和窗体的基类,这个类就是System.Windows.Form.Control。Control类执行核心功能,创建用户所见的界面。Control类派生于System.ComponentModel.Component类。Component类为Control类提供了所必要的基础结构,在把控件拖放到设计界面上以及包含在另一个对象中时需要它。Control类为派生于它的类提供了一个很长的功能列表。


    1、大小和位置

        控件的大小和位置由属性Height、Width、Top、Bottom、Left、Right以及辅助属性Size、Location确定。区别是Height、Width、Top、Bottom、Left、Right属性值都是一个整数,而Size的值使用一个Size结构来表示,Location的值使用一个Point结构来表示。

        Size结构和Point结构都包含XY坐标。Point结构一般相对于一个位置,而Size结构是对象的高和宽。Size和Point都位于System.Drawing命名空间。它们非常相似,因为它们都提供了XY坐标对,还拥有用于简单的比较和转换的重写运算符。例如,可以对两个Size结构执行相加操作。对于Point结构,加法运算符已进行了重写,可以把Size结构加到Point结构上,得到一个新的Point结构。其结果是给某个位置加上某个距离位置值,得到一个新位置。

        Bounds属性返回一个Rectangle对象,它表示一个控件区域。这个区域包含滚动条和标题栏。Rectangle也位于System.Drawing命名空间。ClientSize属性是一个Size结构,表示控件的客户区域,不包含滚动条和标题栏。

        PointToClient和PointToScreen方法是方便的转换方法,它们的参数是Point结构,返回一个Point结构PointToClient的Point参数表示屏幕坐标,该方法把屏幕坐标转换为基于当前客户对象的坐标,这非常便于进行拖放操作。PointToScreen正好与之相反,它提取客户对象的坐标,把它转换为屏幕坐标。

        Dock属性确定子控件停放在父控件的哪条边上。DockStyle枚举值用作其属性值,属性值包括Top、Bottom、Left、Right、Fill和None。Fill会使控件的大小正好匹配父控件的客户区域。

        Anchor属性把子控件的一条边与父控件的一条边对齐,这与停靠不同,因为它不设置父控件的一条边,而是把到该边界的当前距离设置为常量。Anchor属性采用AnchorStyles枚举的值,其值包括Top、       Bottom、Left、Right和None。通过设置该属性值,可以在重新设置父控件的大小时,动态地设置子控件的大小。这样,当用户重新设置窗体的大小时,按钮和文本框就不会被剪切或隐藏。

        Dock和Anchor属性与Flow和Table布局控件一起使用,可以创建非常复杂的用户窗口。对于包含许多控件的复杂窗体来说,窗口大小的重新设置比较困难。

     

    2、外观

        与控件外观相关的属性有BackColor和ForeColor,它们把System.Drawing.Color对象作为其值。BackGroundImage属性把基于Image的对象作为其值。System.Drawing.Image是一个抽象类,用作Bitmap和Metafile类的基类。BackColorImageLayout属性使用ImageLayout枚举设置图像在控件上的显示方式,其有效值是Center、Tile、Stretch、Zoom和None。

        Font和Text属性处理文字的显示。要修改Font属性,需要创建一个Font属性,在创建Font对象时,需要指定字体名称,字号和样式。

     

    3、用户交互操作

        用户交互操作最好描述为控件创建和响应的各种事件。一般比较常见的事件有:Click、DoubleClick、KeyDown、KeyPress、Validating和Paint。

        鼠标事件有Click、DoubleClick、MouseDown、MouseUp、MouseEnter、MouseLeave和MouseHover处理鼠标和控件的交互操作。Cl i ck和DoubleClick事件都把EventArgs作为其参数。而MouseDown和MouseUp事件把MouseEventArgs作为其参数。MouseEventArgs包含几个有用的信息,例如单击的按钮、按钮被单击的次数、鼠标轮制动器(鼠标轮上的凹槽)的数目和鼠标的当前XY坐标。如果可以访问这些信息,就必须处理MouseDown和MouseUp事件,而不是Click和DoubleClick事件。

    注:如果处理Click和DoubleClick事件,每次捕获一个DoubleClick事件,也会引发Click事件。如果处理不正确,就会出现我们不希望的结果。

     

        键盘事件的工作方式与鼠标类似:需要一些信息来确定处理什么事件。KeyPress事件接收一个KeyPressEventArgs,它包含表示被按键的字符值KeyChar。Handled属性用于确定事件是否已处理,把Handled属性设置为True,事件就不会由操作系统进行默认处理。

        如果需要被按的键的更多信息,则处理KeyDown或KeyUp事件会比较合适,它们都接收KeyEventArgs。KeyEventArgs中的属性包括Ctrl、Alt或Shift键是否被按下。

        KeyCode属性返回一个Keys枚举值,表示被按下的键。与KeyPressEventArgs.KeyChar不同,KeyCode属性指定键盘上的每个键,而不仅仅是数字、字母键。

        KeyData属性返回一个Key值,还设置修饰符。修饰符与值进行OR运算,指定是否同时按下了Shift或Ctrl键。

        KeyValue属性是Keys枚举的整数值。

        Modifiers属性包含一个Keys值,它表示被按下的修饰符键。如果选择了多个修饰符,这些值就进行OR运算。

        键盘事件以下述顺序来引发:①KeyDown②KeyPress③KeyUp。

     

        Validating、Validated、Enter、Leave、GotFocus和LostFocus事件都处理获得焦点(或被激活)和失去焦点的控件。在用户用Tab键选择一个控件或用鼠标选择该控件时,该控件就获得了焦点。

        Validating和Validated事件在验证控件时发生。这些事件接收一个CancelEventArgs,利用该参数,把Cancel属性设置为True,就可以取消以后的事件。如果定制了验证代码,而且验证失败,就可以把Cancel属性设置为True,且控件也不会失去焦点。Validating事件在验证过程中发生,Validated事件在验证过程后发生。

        这些事件的引发顺序如下:①Enter②GotFocus③Leave④Validating⑤Validated⑥LostFocus。

    注:理解这些事件的引发顺序是很重要的,可以避免不小心创建事件。如,在控件的LostFocus事件中设置控件的焦点,就会创建一个消息死锁,且应用程序会停止响应。

     

    展开全文
  • Windows标准控件

    千次阅读 2012-01-06 23:00:56
    使用Windows标准控件 我们在前面曾提到过,控件是一些行为标准化了的窗口,一般用于对话框或其它窗口中充当与用户交互的元素。在Visual C++中,可以使用的控件分成三类: (1) Windows标准控件 Windows标准控件...
     
    

    使用Windows标准控件

    我们在前面曾提到过,控件是一些行为标准化了的窗口,一般用于对话框或其它窗口中充当与用户交互的元素。在Visual C++中,可以使用的控件分成三类:

    (1) Windows标准控件

    Windows标准控件由Windows操作系统提供,在Windows 95中还提供了一些新增的控件。所有这些控件对象都是可编程的,我们可以使用Visual C++提供的对话框编辑器把它们添加到对话框中。Microsoft基础类库(MFC)提供了封装这些控件的类,它们列于表6.1。

    表6.1 Windows标准控件

    控件

    MFC类

    描述

    动画

    CAnimateCtrl

    显示连续的AVI视频剪辑

    按钮

    CButton

    用来产生某种行为的按钮,以及复选框、单选钮和组框

    组合框

    CComboBox

    编辑框和列表框的组合

    编辑框

    CEdit

    用于键入文本

    标题头

    CHeaderCtrl

    位于某一行文本之上的按钮,可用来控制显示文件的宽度

    热键

    CHotKeyCtrl

    用于通过按下某一组合键来很快的执行某些常用的操作

    图象列表

    CImageList

    一系列图象(典型情况下是一系列图标或位图)的集合。图象列表本身不是一种控件,它常常是和其它控件一起工作,为其它控件提供所用的图象列表

    列表

    CListCtrl

    显示文本及其图标列表的窗口

    列表框

    CListBox

    包括一系列字符串的列表

    进度

    CProgressCtrl

    用于在一较长操作中提示用户所完成的进度

    多格式文本编辑

    CRichEditCtrl

    提供可设置字符和段落格式的文本编辑的窗口

    滚动条

    CScrollBar

    为对话框提供控件形式的滚动条

    滑块

    CSliderCtrl

    包括一个有可选标记的滑块的窗口

    旋转按钮

    CSpinButtonCtrl

    提供一对可用于增减某个值的箭头

    静态文本

    CStatic

    常用于为其它控件提供标签

    状态条

    CStatusBarCtrl

    用于显示状态信息的窗口,同MFC类CStatusBar类似

    续表6.1

    控件

    MFC类

    描述

    选项卡

    CTabCtrl

    在选项卡对话框或属性页中提供具有类似笔记本中使用的分隔标签的外观的选项卡

    工具条

    CToolBarCtrl

    具有一系列命令生成按钮的窗口,同MFC类CToolBar类似

    工具提示

    CToolTipCtrl

    一个小的弹出式窗口,用于提供对工具条按钮或其它控件功能的简单描述

    CTreeCtrl

    用于显示一系列的项的继承结构

    前面提到过,在MFC中,类CWnd是所有窗口类的基类,很自然的,它也是所有控件类的基类。Windows标准控件在以下环境下提供:

    · Windows 95 

    · Windows NT 3.51及以后版本 

    · Win32s 1.3 

    · 注意: 

    · Visual C++ 4.2及以后版本不再支持Win32s。 

     

    (2) ActiveX控件

    ActiveX控件可用于对话框中,也可用于HTML文档中。这种控件过去被称为OLE控件。本书将在专门的章节中来讲述关于ActiveX控件的知识。这里仅指出ActiveX控件使用了与标准控件完全不同的接口和实现方法。

    (3) 其它MFC控件类

    除了Windows标准控件和自己编写的或者来自于第三方软件开发商的ActiveX控件以外,MFC还提供了另外三种控件,它们由下面的三个类进行封装:

    · 类CBitmapButton用于创建以位图作为标签的按钮,位图按钮最多可以包括四个位图图片,分别代表按钮的四种不同状态。 

    · 类CCheckListBox用于创建选择列表框,这种列表框中的每一项前面有一个复选框,以决定该项是否被选中。 

    · 类CDragListBox用于创建一种特殊的列表框,这种列表框允许用户移动列表项。 

    在本章我们仅讲述第一类控件,即Windows标准控件。所涉及的内容包括各个控件的使用及相应的技巧。

    第一节 使用对话框编辑器和ClassWizard

    对于大多数Windows标准控件,我们一般都使用对话框编辑器来将它们添加到对话框中。

    图6. 1 在ResourceView中选择对话框
    IDD_DIALOGDEMO_DIALOG

    图6. 2 控件的Properties对话框

    图6. 3 对话框编辑器的Controls工具窗口

    在下面的过程中,我们将一个编辑框控件添加到在第四章创建的基于对话框的MFC框架应用程序的主对话框窗口中。

    1. 首先,在Workspace窗口的ResourceView选项内双击DialogDemo resources\Dialog节点下的IDD_DIALOGDEMO_DIALOG图标。上面的操作如图所示。

    2. 用鼠标选中标有“要做……”的静态文本控件。右击鼠标,从上下文菜单中选择Properties,打开如图6.2所示的对话框,在Caption文本框中输入新的控件文本:“在下面的文本框中输入一些字符”,然后将静态文本控件拖动到对话框的左上角。

    3. 从Controls工具窗口(如图6.3所示,如果在你的资源编辑器中看不到该工具窗口,可以在工具条上右击鼠标,从上下文菜单中选择Controls)中选择编辑控件图标,在对话框中绘制一个编辑框控件,如图6.4所示。

    在该编辑框控件的Properties窗口的General选项卡中输入其ID为IDC_EDIT。然后在Styles选项卡下将Multiline复选框划上勾,并消除Auto HScroll复选框前的勾。

    4. 右击该编辑框控件,从上下文菜单中选择ClassWizard命令,打开ClassWizard对话框,该对话框看起来如图6.5所示。

    图6. 4 向对话框中添加一个编辑框控件

    图6. 5 ClassWizard对话框

    单击Member Variables选项卡,确信在Project处选择了DialogDemo,在Class name处选择了CDialogDemoDlg。现在我们为刚才添加的编辑框控件IDC_EDIT添加一个数据映射入口。在Control IDs处选择IDC_EDIT,单击右边的Add Viable按钮。打开如图6.6所示的对话框。

    在Member variable name处链接变量名m_strEdit (这里m表示该变量为类CDialogDemoDlg的一个成员变量,str表明其类型为字符串,即类CString),在Category下拉列表中选择Value (另一种选择是Control,两种选择的不同将在后面的内容中讲述),在Variable type下拉列表中选择CString (还有其它很多数据类型可供选择,但由于这里编辑框中的内容为一字符串,因此CString是最恰当的选择)。单击OK关闭对话框。

    图6. 6 为控件映射添加成员变量

    5. 检查一下现在的ClassWizard对话框(图6.7)与图6.5相比有何不同。在图6.7所示的对话框中下方的Maximum characters文本框中输入50。由字面意思可以很容易猜出其含义,即将编辑框IDC_EDIT中可能的最长字符串的大小限制为50。单击OK关闭对话框。

    图6. 7 使用ClassWizard设置数据验证方案

    6. 从Workspace窗口的ClassView中双击类CDialogDemoDlg的OnInitDialog成员函数,使用下面的代码来代替位于语句

    return TRUE;

    前的// TODO注释:

    m_strEdit="您好! 请在这里输入一些字符串。";

    UpdateData(FALSE);

    7. 在ClassView中双击类CDialogDemoApp的InitInstance成员函数,使用下面的代码来找替位于选择支

    if (nResponse == IDOK)

    下的//TODO注释:

    AfxMessageBox(dlg.m_strEdit);

    然后将同一成员函数中的下面的代码行删掉(或注释掉):

    m_pMainWnd = &dlg;

    8. 编译并运行该应用程序。显示如图6.8所示的对话框。

    图6. 8 示例程序DialogDemo的运行结果

    在图6.8所示的文本框中输入一些字符,单击“确定”。随即弹出如图6.9所示的消息框。该消息框复述了用户在图6.8所示的对话框中的输入。我们还发现,在图6.8所示的对话框中,当输入字符串达到一定的长度之后,我们不可以再输入更多的字符,这是我们在前面设置了Maximum characters为50的结果。

    图6. 9 以消息框的形式反馈输入的字符串

    下面我们来看在上面的步骤中都完成了什么。首先我们使用资源编辑器向对话框模板中添加这些标准控件,这一步的概念很清晰,因此并不难理解。

    然后,我们打开了所绘制的编辑框的Properties (属性)对话框。先将其控件ID设置为IDC_EDIT。这时如果打开头文件Resource.h,就会发现宏IDC_EDIT被定义为常量1001。不过,事实上在很多情况下我们并不需要关心每一控件的ID的具体值,而只需要记住相应的助记符。对于这里的编辑框控件,我们只需要记住IDC_EDIT即可,而不需要关心它等于1001。接着,我们在Styles选项卡中设置了Multiline属性,同时清除了Auto HScroll属性,两者共同作用使用得编辑框IDC_EDIT支持多行文本,并且如文本行的长度超过编辑框宽度时自动回行。

    下面的步骤是最重要的一步,我们动用了功能强大的工具ClassWizard。首先,我们将编辑框与一个CString对象相关联,这使用了一种被称为Dialog Data Exchange (DDX)的机制。在这种机制中,我们先在处理函数OnInitDialog或对话框类的构造函数中对对话框对象的成员变量进行初始化,在对话框显示之前,框架的DDX机制将成员变量的值传递给对话框中的控件。这个过程在成员函数DoModal或Create被调用的过程中发生。类CDialog中对OnInitDialog成员函数的默认实现调用了类CWnd成员函数UpdateData来初始化对话框中的控件。这时我们就可以看到前面的第6步还可在具有下面的几种变通方案:

    1. 将代码行

    m_strEdit="您好! 请在这里输入一些字符串。";

    移到对基类的OnInitDialog成员函数的调用之前,即位于下面的代码之前:

    CDialog::OnInitDialog();

    2. 将代码

    m_strEdit="您好! 请在这里输入一些字符串。";

    移到类CDialogDemoDlg的构造函数中。

    对于上面的两种方法,与前面第6步中使用的方法相比,我们没有必要调用类CWnd的成员函数UpdateData。因为该函数在类CDialog的成员函数OnInitDialog中将被调用。

    这三种方法之间并没有明确的优劣之分,在很多情况下,它们分别适用于不同的场合。

    这里我们说一下成员函数UpdateData。该函数带有一个布尔类型的参数,如果该参数为FALSE,函数UpdateData将成员变量的值传递给对话框的变量;而如果该参数为TRUE,函数UpdateData将进行相反的过程。

    如果用户单击了对话框中ID为IDOK的按钮,或者以TRUE为参数调用函数UpdateData,DDX机制从控件中将值传递到成员变量,同时对话框数据验证(dialog data validation,DDV)机制根据设定的验证规则验证所有数据项。

    在数据交换的过程中,成员函数UpdateData先创建一个CDataExchange对象,然后调用对话框对类CDialog成员函数DoDataExchange的重载版本。该CDataExchange对象将作为成员函数DoDataExchange的一个参数,该参数定义了数据交换的上下文。

    在DoDataExchange中,我们为每一个数据成员指定了一个对DDX函数的调用。每一个函数定义了基于由成员函数UpdateData所提供的CDataExchange参数所确定的上下文而进行的双向数据交换。

    下面的代码摘自实现文件DialogDemo.cpp中对函数DoDataExchange的定义:

    void CDialogDemoDlg::DoDataExchange(CDataExchange* pDX)

    {

    CDialog::DoDataExchange(pDX);

    //{{AFX_DATA_MAP(CDialogDemoDlg)

    DDX_Text(pDX, IDC_EDIT, m_strEdit);

    DDV_MaxChars(pDX, m_strEdit, 50);

    //}}AFX_DATA_MAP

    }

    在两行注释//{{AFX_DATA_MAP和//}}AFX_DATA_MAP之间的代码部分称作数据映射。函数DDX_Text使用CString对象m_strEdit与ID为IDC_EDIT的编辑框控件相关联。函数DDV_MaxChars设置与编辑框控件IDC_EDIT相关联CString对象m_strEdit的最大长度为50。

    需要注意的是,如果用户在模式对话框中单击了“取消”(Cancel)按钮,DoModal函数将返回值IDCANCEL,在这种情况下,在对话框和对话框对象之前的数据交换不会发生。

    由于这个原因,如果DoModal函数返回了值IDOK,我们可以使用下面的代码来复述用户在对话框中所输入的值:

    AfxMessageBox(dlg.m_strEdit);

    · 注意: 

    · 在前面的第7步中有一个乍看起来有一些费解的过程,这就是我们为什么要将下面的代码从函数OnInitDialog中删除: 

    · m_pMainWnd = &dlg; 

    这基于下面的一个事实:

    类CWinThread的数据成员m_pMainWnd有一个有用的特征,如果由该成员所引用的窗口被关闭的话,MFC库将自动的终止CWinThread对象所代表的线程。这样,如果我们将指向dlg的指针赋予了成员变量m_pMainWnd,那么,无论我们单击了“确认”还是“取消”,应用程序的主线程都将被自动终止,之后的代码当然不会得到执行。而在本示例中,我们希望在对话框被关闭后程序继续运行(即弹出一个消息重述用户所输入的内容),因此不应该将dlg对象的指针赋予成员变量m_pMainWnd,从而需要将前面的代码从函数OnInitDialog中删除。

     

    第二节 所有窗口类的基类:CWnd

    在MFC中类CWnd是一个很重要的类,它封装了Windows窗口句柄HWND。在Windows编程中,窗口句柄唯一的标识了一个窗口。然而,尽管类CWnd的对象和窗口句柄之间有着如此紧密的联系,但两者并不是等同的概念。CWnd对象通过类CWnd的构造函数和析构函数创建和消毁,而Windows窗口是Windows内部的一种数据结构,在类CWnd中,它通过Create成员函数创建,通过其析构函数消毁。除此之外,成员函数DestroyWindow可以消毁Windows窗口,而不需要消毁CWnd对象。

    传统的Windows应用程序中,消息是通过一个称作窗口过程(window procedure,通常具有WndProc之类的函数名)的回调函数来处理的。这种方式在MFC中仍然使用,但为CWnd类及其消息映射所隐藏。在类CWnd中,Windows通知消息会被自动的通过消息映射传递到类CWnd中合适的OnMessage成员函数(这里OnMessage是指这些函数具有的以On为前缀的函数名,如OnPaint和前面接触到的OnInitDialog等)进行处理。通常我们都在类CWnd的派生类中重载需要处理的特定消息所对应的OnMessage成员函数。除了直接从CWnd派生新的窗口类以外,我们更倾向于从MFC中定义的其它类,如CFrameWnd、CMIDFrameWnd、CMDIChileWnd、CView和CDialog以及CButton之类的控件类派生新的窗口类。在MFC中定义的这些类本身也是从CWnd派生的。

    通常我们使用两个步骤来创建一个窗口:首先,调用类CWnd的构造函数来构造一个CWnd对象,然后调用其成员函数Create来创建窗口并将该窗口与所创建的CWnd对象相关联。

    当用户终止该窗口时,消毁与之相关联的CWnd对象,或者调用CWnd对象的成员函数DestroyWindow删除窗口并消毁其数据结构。

    大多数以HWND为参数的Win32 API函数都已作为类CWnd的成员函数进行了封装,事实上,很多时候我们通过类Wnd的派生类调用的成员函数并不是由派生类本身所提供的,而是在类CWnd中进行定义的。下面我们分类给出在CWnd类中定义的各类成员函数。完整而详尽的说明每一个成员函数在本书中是不现实的,这里我们仅给出对每一个成员函数的简短说明,以便读者在编程时能够很快的查找到所需的函数,这时再去查找有关于该函数的详细的说明就不是一件困难的事了。

    1. 类CWnd的数据成员(表6.2):

    表6. 2 类CWnd的数据成员

    数据成员

    描述

    m_hWnd

    与该CWnd对象相关联的Windows窗口句柄(HWND)

    2. 构造函数/析构函数(表6.3):

    表6. 3 类CWnd的构造函数和析构函数

    成员函数

    获得图标句柄

    SetIcon

    设置句柄为一指定图标

    GetWindowContextHelpId

    获得帮助上下文标识符

    SetWindowContextHelpId

    设置帮助上下文标识符

    ModifyStyle

    修改当前窗口样式

    ModifyStyleEx

    修改当前窗口的扩展样式

    5. 窗口大小和位置函数(表6.6):

    表6. 6 类CWnd的窗口大小和位置成员函数

    成员函数

    描述

    GetWindowPlacement

    获得显示状态和窗口的正常、最小化和最大化位置

    SetWindowPlacement

    设置显示状态和窗口的正常、最小化和最大化位置

    GetWindowRgn

    获得窗口的窗口区域的拷贝

    SetWindowRgn

    设置窗口区域

    IsIconic

    判断窗口是否被最小化(图标化)

    IsZoomed

    判断窗口是否被最大化

    MoveWindow

    改变窗口的位置和度量

    SetWindowPos

    改变子窗口、弹出式窗口或顶层窗口的大小、位置和顺序

    ArrangeIconicWindows

    排列所有最小化的子窗口

    BringWindowToTop

    将CWnd对象放到覆盖窗口栈的顶部

    GetWindowRect

    获得CWnd对象的屏幕坐标

    GetClientRect

    获得CWnd对象客户区的度量

    6. 窗口访问函数: 

    表6. 7 类CWnd的窗口访问成员函数

    成员函数

    描述

    ChildWindowFromPoint

    判断包含指定点的子窗口

    FindWindow

    返回由其窗口名称和窗口类标识的窗口的句柄

    GetNextWindow

    返回窗口管理器列表中的下一个(或上一个)窗口

    GetOwner

    返回指向CWnd对象的所有者的指针

    续表6.7

    成员函数

    描述

    SetOwner

    改变CWnd对象的所有者

    GetTopWindow

    返回属于CWnd对象的第一个子窗口

    GetWindow

    返回与当前窗口有指定关系的窗口

    GetLastActivePopup

    判断由CWnd对象所有的弹出窗口中最近激活的窗口

    IsChild

    判断CWnd对象是否为一个子窗口

    GetParent

    如果存在的话,获得CWnd对象的父窗口

    GetSafeOwner

    获得给定窗口的安全的所有者

    SetParent

    改变父窗口

    WindowFromPoint

    标识包括给定点的窗口

    GetDlgItem

    从指定的对话框获得标准符为指定ID的控件

    GetDlgCtrlID

    如果CWnd为一子窗口,返回其ID值

    SetDlgCtrlID

    当CWnd对象为一子窗口(不仅指对话框中的控件)时,为其指定控件ID或窗口ID

    GetDescendantWindow

    检查所有下级窗口(descendant window)并返回具有指定ID的窗口

    GetParentFrame

    获得CWnd对象的父框架窗口

    SendMessageToDescendants

    发送一条消息到窗口的所有下级窗口

    GetTopLevelParent

    获得窗口的顶层父窗口

    GetTopLevelOwner

    获得窗口的顶层所有者窗口

    GetParentOwner

    返回指向子窗口的父窗口的指针

    GetTopLevelFrame

    获得窗口的顶层框架窗口

    UpdateDialogControls

    用来更新对话框按钮或其它控件的状态

    UpdateData

    初始化对话框或从对话框中获取数据

    CenterWindow

    相对于父窗口使窗口居中

    7. 更新和绘制函数(表6.8)

    表6. 8 类CWnd的更新和绘制函数

    成员函数

    描述

    BeginPaint

    为重绘操作准备CWnd对象

    EndPaint

    标记重绘操作的结束

    续表6.8

    成员函数

    描述

    Print

    在指定的设备上下文绘制当前窗口

    PrintClient

    在指定的设备上下文(通常是打印机)绘制所有窗口

    LockWindowUpdate

    禁止或重新允许绘制指定的窗口

    UnlockWindowUpdate

    解除CWnd::LockWindowUpdate对窗口的锁定

    GetDC

    获得客户区的显示上下文

    GetDCEx

    获得客户区的显示上下文,并在绘制过程中允许裁剪

    RedrawWindow

    在客户区中更新指定的矩形或区域

    GetWindowDC

    获得整个窗口的显示上下文,包括标题条,菜单和滚动条

    ReleaseDC

    释放客户区或窗口设备上下文,并使其可为其它程序所使用

    UpdateWindow

    更新客户区

    SetRedraw

    决定在CWnd对象中的改变是否被重绘

    GetUpdateRect

    获得完全覆盖CWnd对象的更新区域的最小矩形坐标

    GetUpdateRgn

    获得CWnd对象的更新区域

    Invalidate

    使用整个客户区无效

    InvalidateRect

    通过将给定矩形添加到当前更新区域来使包括在给定矩形内的客户区无效

    InvalidateRgn

    通过将给定区域添加到当前更新区域来使包括在给定区域内的客户区无效

    ValidateRect

    通过将给定矩形从当前更新区域中移出来使包括在给定矩形内的客户区有效

    ValidateRgn

    通过将给定区域从当前更新区域中移出来使包括在给定区域内的窗户区有效

    ShowWindow

    显示或隐藏窗口

    IsWindowVisible

    判断窗口是否可见

    ShowOwnedPopups

    显示或隐藏窗口拥有的所有弹出式窗口

    EnableScrollBar

    允许或禁止滚动条上的一个或两个箭头

    8. 坐标映射函数(表6.9)

    表6. 9 类CWnd的坐标映射函数

    成员函数

    描述

    MapWindowPoints

    从CWnd对象的坐标空间映射一系列点到另一窗口的坐标空间

    续表6.9

    成员函数

    描述

    ClientToScreen

    转换给定点的客户坐标或显示矩形到屏幕坐标

    ScreenToClient

    转换给定点的屏幕坐标或显示矩形到客户坐标

    9. 窗口文本函数(表6.10)

    表6. 10 类CWnd的窗口文本函数

    成员函数

    描述

    SetWindowText

    设置窗口文本或标题条(如果有的话)为指定文本

    GetWindowText

    获得窗口文本或标题条

    GetWindowTextLength

    返回窗口文本或标题条的长度

    SetFont

    设置当前字体

    GetFont

    获得当前字体

    10. 滚动函数(表6.11)

    表6. 11 类CWnd的滚动成员函数

    成员函数

    描述

    GetScrollPos

    获得滚动框的当前位置

    GetScrollRange

    拷贝给定滚动框中滚动块的当前最大和最小位置

    ScrollWindow

    滚动客户区的内容

    ScrollWindowEx

    滚动客户区内容。与ScrollWindowEx类似,但具有一些附加特性

    GetScrollInfo

    获得关于某一滚动条的由SCROLLINFO结构维护的信息

    GetScrollLimit

    获得滚动条的限制

    SetScrollInfo

    设置关于滚动条的信息

    SetScrollPos

    设置滚动条的当前位置,并在指定的情况下重绘滚动条以反映新的位置

    SetScrollRange

    设置给定滚动条的最小和最大位置值

    ShowScrollBar

    显示或隐藏滚动条

    EnableScrollBarCtrl

    允许或禁止兄弟滚动条控件

    GetScrollBarCtrl

    返回兄弟滚动条控件

    RepositionBars

    在客户区中对控件条重定位

    11. 拖放函数(表6.12)

    表6. 12 类CWnd的拖放成员函数

    成员函数

    描述

    DragAcceptFiles

    使窗口可以接受文件拖放

    12. 插入符函数(表6.13)

    表6. 13 类CWnd的插入符成员函数

    成员函数

    描述

    CreateCaret

    新的插入符形状,并获得该插入符的所有权

    CreateSolidCaret

    创建方块形状的插入符,并获得该插入符的所有权

    CreateGrayCaret

    创建变灰方块形状的插入符,并获得该插入符的所有权

    GetCaretPos

    获得插入符当前位置的客户坐标

    SetCaretPos

    移动插入符到指定的位置

    HideCaret

    隐藏插入符

    ShowCaret

    在插入符的当前位置显示插入符

    13. 对话框项函数(表6.14)“

    表6. 14 类CWnd的对话框项函数

    成员函数

    描述

    CheckDlgButton

    在按钮控件前放置选中标记或清除按钮控件的选中标记

    CheckRadioButton

    选中指定的单选钮并清除指定给中其它所有单选钮的选中标记

    GetCheckedRadioButton

    返回一组按钮中当前选中单选钮的ID

    DlgDirList

    使用文件或目录列表填充一列表框

    DlgDirListComboBox

    使用文件或目录列表填充一组合框的列表框

    DlgDirSelect

    从一列表框中获得当前选择

    DlgDirSelectComboBox

    从一组合框的列表框中获得当前选择

    GetDlgItemInt

    将给定对话框中某一控件的文本转换为一个整数值

    GetDlgItemText

    获得与某一控件相关联的标题或文本

    GetNextDlgGroupItem

    查找同一组中的下一个(或前一个)控件

    续表6.14

    成员函数

    描述

    GetNextDlgTabItem

    查找在指定控件之前(或之后)的第一个具有WS_TABSTOP样式的控件

    IsDlgButtonChecked

    判断一个按钮控件是否选中

    IsDialogMessage

    判断一个给定消息是否影响非模态对话框,如果是,处理该消息

    SendDlgItemMessage

    向指定的控件发送一条消息

    SetDlgItemInt

    使某一控件的文本为某一给定整数值

    SetDlgItemText

    设置指定对话框中某一控件的标题或文本

    SubclassDlgItem

    将一个Windows控件与CWnd对象相关联,并使其通过CWnd对象的消息映射传递消息

    ExecuteDlgInit

    初始化对话框资源

    RunModalLoop

    为一模态窗口获取、翻译或发送消息

    ContinueModal

    使一窗口继续保持模态

    EndModalLoop

    结束某一窗口的模态状态

    14. 数据绑定函数(表6.15):

    表6. 15 类CWnd的数据绑定成员函数

    成员函数

    描述

    BindDefaultProperty

    将调用对象的默认简单绑定属性(该属性在类型库中标记)绑定至相关联的数据源控件的游标

    BindProperty

    将数据绑定控件的游标绑定属性绑定至数据源控件,并使用MFC绑定管理器注册绑定关系

    GetDSCCursor

    获得指向由数据源控件的数据源、用户名、密码和SQL属性定义的底层游标的指针

    15. 菜单函数(表6.16)

    表6. 16 类CWnd的菜单成员函数

    成员函数

    描述

    GetMenu

    获得指向指定菜单的指针

    SetMenu

    设置菜单为指定的菜单

    DrawMenuBar

    重绘菜单条

    GetSystemMenu

    允许应用程序访问控制菜单以进行复制和修改

    续表6.16

    成员函数

    描述

    HiliteMenuItem

    加亮顶层菜单项或移去顶层菜单项的加亮显示

    16. 工具提示函数(表6.17)

    表6. 17 类CWnd的工具提示函数

    成员函数

    描述

    EnableToolTip

    允许工具提示控件

    CancelToolTip

    禁止工具提示控件

    FilterToolTipMessage

    获得对话框中与某一控件相关联的标题或文本

    OnToolHitTest

    判断一个点是否在指定工具的绑定矩形内,并获得该工具的信息

    17. 计时器函数(表6.18)

    表6. 18 类CWnd的计时器成员函数

    成员函数

    描述

    SetTimer

    安装系统计时器,计时器触发时发送WM_TIMER消息

    KillTimer

    消除系统计时器

    18. 提示函数(表6.19)

    表6. 19 类CWnd的提示成员函数

    成员函数

    描述

    FlashWindow

    闪烁窗口一次

    MessageBox

    创建并显示一个包括应用程序提供的消息和标题的窗口

    19. 窗口消息函数(表6.20)

    表6. 20 类CWnd的窗口消息成员函数

    成员函数

    描述

    GetCurrentMessage

    返回窗口正在处理的消息的指针。仅当在一个OnMessage消息处理函数中调用该成员函数。

    Default

    调用默认窗口过程,该过程提供对所有应用程序未处理的消息的默认处理

    PreTranslateMessage

    由CWinApp使用,在窗口消息被发送到TranslateMessage和DispatchMessage之前对其进行过滤

    续表6.20

    成员函数

    描述

    SendMessage

    将一条消息发送到CWnd对象,直至该对象处理该消息之后才返回

    PostMessage

    将一条消息放入程序的消息队列,不等待窗口处理该消息就立即返回

    SendNotifyMessage

    将指定消息发送到窗口,并尽可能快的返回,这依赖于调用线程如何创建窗口

    20. 剪贴板函数(表6.21)

    表6. 21 类CWnd的剪贴板函数

    成员函数

    描述

    ChangeClipboardChain

    从剪贴板查看器链中移去CWnd对象

    SetClipboardViewer

    添到CWnd对象到窗口链,这些窗口当剪贴板内容改变时会收到通知

    OpenClipboard

    打开剪贴板。其它程序仅当Windows CloseClipboard函数被调用时才可以更改剪贴板

    GetClipboardOwner

    获得剪贴板的当前拥有者的指针

    GetOpenClipboardWindow

    获得指向当前打开剪贴板的窗口的指针

    GetClipboardViewer

    获得指向剪贴板查看器链中第一个窗口的指针

    21. OLE控件函数(表6.22)

    表6. 22 类CWnd的OLE控件函数

    成员函数

    描述

    SetProperty

    设置OLE控件属性

    OnAmbientProperty

    实现环境属性值

    GetControlUnknown

    获得指向一未知OLE控件的指针

    GetProperty

    获得一OLE控件的属性

    InvokeHelper

    调用OLE控件方法或属性

    22. 可重载函数(表6.23)

     

    表6. 23 类CWnd的可重载成员函数

    成员函数

    描述

    WindowProc

    为CWnd对象提供一个窗口过程。默认的窗口过程通过消息映射发送消息

    DefWindowProc

    调用默认窗口过程,该过程提供应用程序未处理的所有窗口消息的默认处理

    PostNcDestroy

    在窗口被消毁后由OnNcDestroy函数调用

    OnNotify

    由框架调用以通知父窗口某一事件在某一控件中发生或者该控件需要信息

    OnChildNotify

    由父窗口调用以给通知控件一个响应控件通知的机会

    DoDataExchange

    用于对话框数据交换和验证。由UpdateData调用

    其余函数包括对各种窗口消息的消息处理函数,这些函数为数众多,这里我们限于篇幅不再一一介绍。类CWnd中定义的消息处理函数几乎都具有一致的命名方式,其格式为前缀On再加上相应的消息名,如WM_PAINT消息的处理函数在类CWnd中被命名为OnPaint。因此,只需知道所需处理的消息,就可以很快的推知该消息的处理函数名。

    第三节 按钮

    在本节中要讲述的实际包括四种控件:下压按钮、单选钮、复选框和组框,它们之间无论在外观还是在使用上都有较大的差异。在MFC中之所以使用一个类CButton来封装这四种不同控件纯粹出于历史的原因。这使得一些使用过Visual Basic之类的编程工具的程序员可能会有一点混淆,但相信只需要很短的时间就可以习惯这一点转变。

    下面我们分别讲述这四种按钮控件:

    6.3.1 下压按钮

    在基于对话框的应用程序中,下压按钮是最常见的控件之一,如图6.10所示。

    图6. 10 下压按钮

    下面的步骤讲述如何向对话框中添加下压按钮控件。

    1. 在ResourceView中双击需要添加下压按按钮控件的对话框模板,Developer Studio将在资源编辑器中打开该对话框模板。如图6.11所示。

    2. 在图6.3所示的控件工具窗口中选择图标,直接使用鼠标在对话框中绘制出一个下压按钮。

    3. 右击所绘制的下压按钮,选择Properties命令打开其属性对话框,设置下压按钮的各项属性。下面详细描述这些属性的含义:

    图6. 11 在资源编辑器中打开一对话框模板

    图6. 12 在对话框中绘制下压按钮控件

    一般属性:

    ID:

    在头文件中定义的符号。类型:符号、整数或用引号括起来的字符串

    Caption:

    控件标签文本。如果在标题中的某个字母前加上了“&”符号,该字母在显示时将被加上下划线,相应的“&”符不会被显示。在运行直接按下加有下划线的字母同单击按钮具有同样的效果。默认情况下,资源编辑器对按钮标题的命名依赖于控件的类型,如Button1、Button2等。

    Visible:

    决定当应用程序第一次运行时控件是否可见。类型:布尔值 默认值为真

    Disabled:

    决定当对话框创建时该控件是否显示为禁止状态。类型:布尔值 默认值为假

    Group:

    指定一组控件中的第一个控件。在同组控件中用户可以使用箭头键在控件之间移动。以tab order为序,在该控件之后的所有该属性值为False的控件将被视为同一组控件,直到遇上Group属性标记为True的控件为止。类型:布尔值 默认值为假

    Tabstop:

    决定用户是否可以使用TAB键来定位到该控件。类型:布尔值 默认值为假

    HelpID:

    为控件指定一个帮助标识符。该标识符基于相应的资源标识符。类型:布尔值 默认值为假

    样式:

    Default button:

    该属性为真时,控件将作为对话框中的默认按钮,默认按钮在对话框第一次显示时具有粗的黑边,用户在对话框中按下ENTER键相当于单击该按钮。一个对话框中只允许有一个默认按钮。类型:布尔值 默认值为假

    Owner draw:

    创建一个自绘按钮。使用自绘按钮可以定制按钮的外观。使用自绘按钮需要重载下面的两个函数或其中之一:CWnd::OnDrawItem和CButton::OnDraw。

    Icon:

    在按钮显示时使用一个图标来代替文本。类型:布尔值 默认值为假 

    该按钮样式为Windows 95中新引入的按钮样式

    Bitmap:

    在按钮显示时使用位图来代替文本。类型:布尔值 默认值为假

    该样式为Windows 95中新引入的样式

    Multi-line:

    当按钮文本太长时使用多行回绕的方式进行显示。类型:布尔值 默认值为假

    Notify:

    按钮控件被单击或双击时通知父窗口。类型:布尔值 默认值为真

    Flat:

    使用平面外观代替按钮默认的三维外观。类型:布尔值 默认值为假

    Horizontal alignment:

    设置按钮标题文本的对齐方式(左对齐、右对齐、居中对齐或使用默认位置)

    Vertical alignment:

    设置按钮标题文本的对齐方式(向上对齐、向下对齐、居中对齐或使用默认位置)

    扩展样式

    Client edge:

    使按钮看起来有下凹的感觉。类型:布尔值 默认值为假

    Static edge:

    在按钮边缘创建边框。类型:布尔值 默认值为假

    Modal frame:

    提供一个三维框架

    Transparent:

    使控件透明。位于透明窗口下面的窗口不会被该窗口所覆盖。具有透明样式的窗口仅当所有底层兄弟窗口完成更新之后才会收到WM_PAINT消息。类型:布尔值 默认什为假

    Accept files:

    是否接受文件拖放。如果在控件上放下文件时,控件将接收到WM_DROPFILES消息。类型:布尔值 默认值为假

    No parent notify:

    指定子窗口不向父窗口发送WM_PARENTNOTIFY消息。类型:布尔值 默认值为假

    Right aligned text:

    指定文本为右对齐。类型:布尔值 默认值为假

    Right-to-left reading order:

    使用从右向左的阅读方式来显示文本。主要用于希伯来语系和阿拉伯语等。类型:布尔值 默认值为假

    · 技巧: 

    · 如果需要在控件的标题文本中使用“&”符,可以使用双写的“&”符,如按钮文本“&File && Directory”在显示时将成为。 

    · 如果需要在控件标题中使用多行文本,可以将按钮控件的Multiline属性设置为真,然后在需要换行的地方使用转义字符 "\n" 或 "\r"。在Multiline属性值为真的情况下,如果文本行的宽度超过了控件的宽度,即使没有使用换行转义字符,文本也将会在合适的地方进行折行处理。但要注意,其它一些转义字符序列,如 "\t" 等不被控件所支持。 

    我们一般只处理按钮控件一种通知消息:BN_CLICKED,该消息表示用户单击了该按钮控件。按钮控件的另外一种通知消息是BN_DOUBLECLICKED,它表示用户双击了按钮控件,但是一般情况下我们不需要处理下压按钮的双击事件。

    图6. 13 ClassWizard对话框:Message Maps选项卡

    下面我们介绍如何为下压按钮的单击事件添加消息处理函数和消息映射,这里我们假设所添加的下压按钮ID为IDC_CLICKHERE,标题文本为“单击这里(&C)”,其余属性使用默认设置。

    第一种方法如下:

    1. 在资源编辑器右击按钮IDC_CLICKHERE,选择“ClassWizard”,打开如图6.13所示的窗口,单击Message Maps选项卡。

    确信在Project处选择的工程为当前工程,Class name处为当前对话框模板所对应的类。Object IDs列表框中给出了当前对话框类中的所有对象标识符,从中选择IDC_CLICKHERE,即我们刚才添加的下压按钮,这里,在右边的Message列表框中给出了当前对象的消息,这里即BN_CLICKED和BN_DOUBLECLICKED,从中选择BN_CLICKED (它代表了按钮的单击事件),然后单击右边的Add Function按钮(注意:Add Function按钮仅当已选择了某一消息时才会出现)。

    图6. 14 决定是否需要更改命令处理函数名

    图6. 15 为控件通知消息添加处理函数

    2. 在随后出现的对话框(如图6.14所示)中选择是否需要更改命令处理函数的函数名。ClassWizard的默认函数名遵从于下面的命令协议:

    前缀On + 控件ID中除去IDC_前缀的剩余部分

    这里我们接受默认的命令处理函数名OnClickhere。

    3. 新添加的命令处理函数OnClickhere已经出现在图6.13所示的对话框中的下面的Member functions部分。同时,Edit Code按钮获得输入焦点。单击该按钮,ClassWizard将在Developer Studio的代码编辑器窗口中打开函数OnClickhere,并高亮度显示下面的// TODO注释:

    // TODO: Add your control notification handler code here

    我们使用下面的代码来替换上面的// TODO注释:

    MessageBox

    ("您刚才单击了按钮 IDC_CLICKHERE, 因此相应的命令处理函数 OnClickhere 被调用!");

    第二种方法:

    1. 在资源编辑器中右击按钮IDC_CLICKHERE,选择Events命令,打开如图6.15所示的对话框:

    2. 在Class or object to handle列表框中选择IDC_CLICKHERE,然后在New Windows messages/events列表框中选择BN_CLICKED,单击右边的Add and Edit,余下的步骤同第一种方法的第2步开始相同。

    这时编译并运行上面的程序,单击标签为“单击这里”的下压按钮,弹出如图所示的消息框。

    图6. 16 程序PushButton的运行结果

    下面我们来看相应的消息映射。

    首先,在类CPushButtonDlg的定义中添加了消息处理函数OnClickhere的原型:

    afx_msg void OnClickhere();

    函数OnClickhere的声明被放进了两行注释分隔符//{{AFX_MSG(CPushButtonDlg)和//}}AFX_MSG之间。前面我们提到过,ClassWizard将由它定义的消息处理函数的声明放入这两行注释分隔符之间。

    下面我们来看相应的消息映射入口。它位于实现文件PushButtonDlg.cpp中的两个宏BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间:

    ON_BN_CLICKED(IDC_CLICKHERE, OnClickhere)

    其中第一个参数IDC_CLICKHERE为控件的标识符,第二个参数OnClickhere为相应的消息处理函数。

    一旦弄清楚了由ClassWizard添加这些代码,我们就可以手动的添加命令消息处理函数的消息映射。但是,从上面的过程中我们可以很明显的看出一点,使用ClassWizard来完成这一点要简单得多。

    下面我们介绍与下压按钮控件有关的几个技巧:

    (1) 在运行过程中改变下压按钮的标题文本

    有时候我们需要在程序运行的过程中改变按钮的标题文本。典型的,我们可能需要根据用户所输入的数据来决定按钮上应该写些什么。我们到前面去看一下表6.14,看一看有什么成员函数可以完成这种功能。

    很好,类CWnd的成员函数SetDlgItemText可以由窗口或对话框所有的控件的标题文本。其原型如下:

    void SetDlgItemText( int nID, LPCTSTR lpszString );

    其中nID为控件标识符(ID),lpszString为控件的新标题文本。

    成员函数SetDlgItemText事实上是向控件发送一条WM_SETTEXT消息,该消息的wParam参数必须为0,而lParam为指向窗口标题文本字符串的指针。

    因此,SetDlgItemText等价于下面的函数调用:

    CWnd::SendDlgItemMessage(nID, WM_SETTEXT, 0, LPARAM(lpszString));

    ::SendDlgItemMessage(GetSafeHwnd(), nID, WM_SETTEXT, 0, LPARAM(lpszString));

    比如说,我们用以将下面的代码添加到OnClickhere中对MessageBox的调用之后:

    SetDlgItemText(IDC_CLICKHERE,"此按钮已被单击过.");

    (2) 使用按钮无效(或有效)

    假设我们在上面的例子中希望用户只能单击按钮IDC_CLICKHERE一次。那么,按钮IDC_CLICKHERE被单击一次之后应该变灰,以禁止用户再次单它。这可以通过下面的步骤来实现:

    首先调用对话框对象的成员函数GetDlgItem (该成员函数在类CWnd中定义),该成员函数获得一个指向对话框中的控件的CWnd指针,然后再通过该指针调用控件对象的成员函数EnableWindow (该成员函数在类CWnd中定义)。该成员函数允许或禁止调用它的CWnd对象对应窗口。整个过程可以使用一行语句来实现,如下所示:

    GetDlgItem(IDC_CLICKHERE)->EnableWindow(FALSE);

    其中GetDlgItem函数以控件的ID为参数,返回值的类型为CWnd *,如果需要通过该指针调用在类CButton所定义的成员函数,可以使用强制类型转换。EnableWindow以一个布尔值为参数,该参数为真时表示允许该窗口接受鼠标和键盘输入,为假时禁止该窗口接受鼠标和键签署输入。这里再一次强调,控件本身也是一种窗口。

    将上面的代码放到命令处理函数OnClickhere的最后,这样,在单击一次按钮“单击这里”之后,对话框如图6.17所示。

    图6. 17 处于禁止状态的控钮控件

    此外,如果使用了ClassWizard为按钮建立了对话框的成员变量的数据映射,则可以通过对话框中的成员变量直接操纵控件。在本例中,如果我们已将下压按钮映射为类型为CButton的成员变量m_bnClickhere,则可以通过下面成员函数调用设置按钮的允许状态:

    m_bnClickhere->EnableWindow(FALSE);

    (3) 使按钮获得输入焦点

    具有输入焦点的窗口将会得到所有的键盘输入消息。我们可以通过类CWnd的成员函数GetFocus来使对话框中的控件获得输入焦点。

    试将下面的代码加到消息处理函数OnInitDialog的return语句前:

    m_bnClickhere.SetFocus();

    GetDlgItem(IDC_CLICKHERE)->SetFocus();

    编译并运行程序。非常奇怪,输入焦点并没有被设置到下压按钮“单击这里”上。依然是按钮“确定”拥有当前输入焦点。

    请注意这样的事实:

    · 注意: 

    · 如果在消息处理成员函数OnInitDialog中将输入焦点设置到指定的控件,则函数应该返回FALSE,这是因为如果WM_INITDIALOG消息的处理函数返回真值,Windows会将输入焦点设置为对话框中的第一个控件。因此,如果在该处理函数中设置了控件的输入焦点,WM_INITDIALOG消息的处理函数应该返回假值。 

    将下面的代码

    return TRUE;

    修改为

    return FALSE;

    这时再编译并运行程序,则输入焦点将被正常地设置到下压按钮“单击这里”上。这时按下空格键相当于在按钮“单击这里”上单击鼠标左键。

    (4) 使用图形代替文本

    在一些应用程序,尤其是一些多媒体应用程序中,我们希望按钮的外观看起来更加的美观,比如说我们希望使用多变的图形代替单调乏味的纯文本。对于一般的按钮控件,我们可以使用两种方法来在按钮中使用图形来代替文本。

    第一种方法是使用图标来代替文本。下面的示例说明了这种用法:

    1. 使用资源编辑器或其它工作编辑一个图标资源,其ID为IDI_CLICKHERE,图案如图6.18所示。

    2. 在希望使用图标图案的按钮控件的Properties属性框在Styles选项卡中设置Icon属性为真。并按图6.19修改对话框及其中控件的大小。

    3. 在类CPushButtonDlg的消息处理成员函数OnInitDialog中添加下面的代码。这些代码应该在对基类的OnInitDialog成员函数的调用之后。

    图6. 18 图标IDI_CLICKHERE

    图6. 19 为使用图标按钮修改
    对话框中控件的大小

    HICON hIcon=AfxGetApp()->LoadIcon(IDI_CLICKHERE);

    m_bnClickhere.SetIcon(hIcon);

    编译该应用程序,运行结果如图6.20所示。

    图6. 20 在按钮中使用图标的示例

    这时单击按钮Click Here,图标图案会有向右和向下下压的效果。

    第二种方法是使用位图来代替文本。步骤如下:

    图6. 21 位图资源IDB_CLICKHERE

    1. 向工程资源中添加如图6.21的位图资源,其ID为IDB_CLICKHERE。

    2. 在希望使用位图图案的按钮控件的Properties属性框在Styles选项卡中设置Bitmap属性为真。我们注意到Icon属性和Bitmap属性是互斥的,即选择一属性的同时也清除了另一属性。并按图6.19修改对话框及其中控件的大小。同时参考最终运行结果(如图6.22)修改对话框及其按钮的大小。

    3. 在OnInitDialog成员函数中添加如下的代码:

    HBITMAP hBitmap=LoadBitmap(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDB_CLICKHERE));

    m_bnClickhere.SetBitmap(hBitmap);

    在上面的代码中,我们使用Win32 API函数LoadBitmap (注意它不是类CWinApp的成员函数)来加载位图资源IDB_CLICKHERE,从而获得位图句柄hBitmap,最后以该句柄为参数调用类CButton的成员函数SetBitmap。

    编译并运行上面的程序,得到如图6.22所示的运行结果。

    图6. 22 在按钮中使用位图的示例

    · 注意: 

    · 在上面的示例程序中我们使用了真彩色(24位)的位图。这样的位图不可以使用资源编辑器来进行编辑。上面的位图是使用其它专门的图形工具来进行编辑并保存到文件Clickhere.bmp中的。请按下面的步骤将该文件添加为工程的资源: 

    1. 选择Insert菜单下的Resource命令,打开如图所示的对话框。

    图6. 23 插入新的资源

    2. 从中单击Import按钮,从位图文件Clickhere.bmp中输入资源。注意在文件类型中选择“All files (*.*)”。

    Developer Studio将弹出如图6.24所示的警告对话框。该对话框表明位图资源已被正确添加。但由于使用了多于256色的颜色数,因此该资源不可以在资源编辑器中打开。

    图6. 24 试图添加使用了多于256色的位图资源时的警告消息框

    3. 按正常的方法将所添加的位图资源的ID修改为IDB_CLICKHERE。必要时重新编辑资源文件或工程。

    6.3.2 位图按钮

    位图按钮是由MFC提供的几种附加控件之一。在前一节的过程中,我们可以使用一个位图来代替文本作为下压按钮的标签。而在位图按钮中,我们可以使用多达四个位图来分别代表按钮处于四种不同的状态(凸起、按下、获得焦点或被禁止)下的显示。而且,使用位图按钮还可以去除掉令人讨厌的按钮黑边。而使用位图按钮并不复杂,但是相比起标准的按钮控件(它由Windows自身所提供)而言有一些特殊。下面的过程描述了位图按钮的使用,它们在MFC中使用类CBitmapButton封装。

    1. 使用AppWizard创建新的基于对话框的MFC工程BitmapButton。

    2. 使用资源编辑器绘制一个标准按钮,将其ID设为IDC_CLICKHERE,标题文本设为CLICKHERE,然后在Styles选项卡中将Owner draw属性设置为真。

    3. 向工程中添加四个位图资源。

    "CLICKHEREU"

    "CLICKHERED"

    "CLICKHEREF"

    "CLICKHEREX"

    图6. 25 位图按钮IDC_CLICKHERE所使用的四个位图资源

    所添加的四个位图资源的ID的设置取决于在第一步中的标题文本的设置:按钮未按下去时使用的位图添加了后缀"U";按钮按下去时使用的位图添加了后缀"D";按钮拥有焦点时使用的位图添加了后缀"F";按钮被禁止时使用的位图添加了后缀"X"。需要注意的是,由于这些位图资源的ID为字符串,因此在使用属性对话框设置其ID时一定要加了双引号,否则资源编辑器会将该ID值看作代表一个整型量的符号。

    4. 在对话框类CBitmapButtonDlg(这里我们沿用上一节中的示例程序)中添加类型为CBitmapButton的新的成员变量m_bnClickhere。

    5. 在OnInitDialog成员函数中的return语句前添加下面的代码:

    m_bnClickhere.AutoLoad(IDC_CLICKHERE, this);

    CRect rect1,rect2;

    CButton *pClickhere=(CButton*)GetDlgItem(IDC_CLICKHERE);

    GetClientRect(&rect1);

    pClickhere->GetWindowRect(&rect2);

    ScreenToClient(&rect2);

    pClickhere->MoveWindow(rect2.left,(rect1.Height()-rect2.Height())/2,

    rect2.Width(),rect2.Height());

    其中第一个参数IDC_CLICKHERE是位图按钮的资源ID,第二个参数为指向该位图按钮的父窗口的CWnd对象的指针,这里即类CBitmapButtonDlg的this指针。类CBitmapButton的成员函数AutoLoad完成以下几步工作:

    (1) 将按钮与CBitmapButton对象相关联;

    (2) 自动加载按钮所使用的位图,条件是这些位图资源满足步骤2中的命名约定;

    (3) 自动改变控件的大小以适合所加载的位图资源。

    接下来的几行代码将位图按钮在对话框中进行垂直居中。首先类CWnd的成员函数GetClientRect返回了对话框的客户区矩形,接着,类CWnd的成员函数GetWindowRect返回了控件IDC_CLICKHERE的窗口矩形,然后使用类CWnd的成员函数ScreenToClient将rect2由屏幕坐标转换为对话框的客户坐标,这是因为类CWnd的成员函数MoveWindow在移动子窗口时将使用父窗口的客户区坐标,而不是使用屏幕坐标。

    6. 按图6.26添加下面的下压按钮IDC_DISABLE,将其标题设置为“禁止使用(&X)”。

    图6. 26 位图按钮示例程序对话框的设计

    7. 将所有下压按钮的Tab stop属性(位于General选项卡中)设置为真。并按图6.26调整各控件的大小位置。其中按钮CLICKHERE的大小的无关紧要的,我们只需要保证对话框左边是否有足够的空间来显示按钮所使用的位图即可。

    8. 为按钮IDC_DISABLE的BN_CLICKED命令编写下面的命令处理函数:

    void CBitmapButtonDlg::OnDisable() 

    {

    CButton *pClickhere=(CButton*)GetDlgItem(IDC_CLICKHERE);

    static int bIsEnabled=pClickhere->IsWindowEnabled();

    if (bIsEnabled)

    {

    pClickhere->EnableWindow(FALSE);

    SetDlgItemText(IDC_DISABLE,"允许使用(&E)");

    }

    else

    {

    pClickhere->EnableWindow(TRUE);

    SetDlgItemText(IDC_DISABLE,"禁止使用(&X)");

    }

    bIsEnabled=!bIsEnabled;

    }

    上面的代码实现两个功能,即当位图按钮的状态为允许时,单击按钮IDC_DISABLE将其状态设置为不允许;在相反的状态下,单击按钮IDC_DISABLE将其状态设置为允许。由于实现该过程的代码比较简单,因此我们在这里不作详细的讲述。

    编译并运行上面的示例程序,其结果如图6.27所示。

    反复单击位图按钮和禁止使用按钮,以观察位图按钮在不同状态下的外观的改变。还可以使用TAB键改变按钮的输入焦点,以观察位图按钮获得输入焦点和失去输入焦点时的不同外观。

    图6. 27 位图按钮示例程序

    6.3.3 组框

    组框也是一种按钮控件。它常常用来在视觉上将控件(典型情况下是一系列的单选钮和复选框)进行分组,从而使对话框中的各个控件看起来比较有条理。

    图6. 28 组框(Group box)控件

    相对于其它控件来说,组框的使用非常之简单。这里我们需要强调的是,组框仅仅是在视觉上将控件进行分组,事实上控件在编程上的分组依赖于其Group属性的设置。

    组框也可以发送BN_CLICKED和BN_DOUBLECLICKED命令消息。但是在般情况下我们都不对这些命令作响应。此外,组框也可以设置Icon或Bitmap属性(注意它们之间的互斥的),即我们可以使用图标或位图来代替默认情况下的文本。但是在绝大多数情况下,我们仅使用纯文本来作为组框的标题。

    与前面讲述的下压按钮类似,我们同样可以使用SetDlgItemText成员函数来设置组框控件的标题文本。此外,我们还可以使用GetDlgItem来获得与组框控件相关联的CWnd对象的指针,然后通过该指针调用成员函数SetWindowText来实现同样的功能。由于在程序中常常不需要频繁的操纵组框控件,因此大多数情况下我们不需要为组框控件进行成员变量的映射,但这种方法是完全可以的。

    对于如何将控件进行分组的方法在讲述单选钮和复选框时再作介绍。

    6.3.4 单选钮

    图6. 29 单选钮示例程序

    单选钮用来表示一系列的互斥选项,这些互斥选项常常被分成若干个组。下面的示例程序说明了单选钮的使用。

    1. 创建新的基于对话框的MFC应用程序,将工程名设置为RadioButton。

    2. 按图6.29绘制应用程序的主对话框。其中在Control工具箱中单选钮对应的图标是,组框控件对应的图标是。

    3. 单击Layout菜单下的Tab Order命令,按图6.30的顺序单击各控件以设置控件的TAB键顺序(Tab Order)。

    4. 确信所有控件的Group属性都被设置为假。分别单击组框“性别”和组框“年龄”,将其Group属性设置为真。

    图6. 30 设置控件的Tab Order

    以Tab Order为序,从Group属性为真的控件开始(包括该控件),到下一个Group属性的真的控件结束(不包括该控件),所有的这些控件将组成一个组。对于单选钮,同一组内同时只能有(也应该有)一个处于被选中的状态。当其中一个控件被置于选中状态时,同组的其它单选钮应该清除其选中状态。对于由资源编辑器生成的单选钮控件,在默认情况由Windows自动处理同组控件之间的互斥关系。

    下面我们简述一下特定于单选钮的一些属性及其含义,这些属性被列于Styles选项卡内:

    Auto:

    在具有Auto属性的情况下,当用户单击了同一组的某个单选钮时,其余单选钮的选中属性被自动清除。当在一组单选钮中使用Dialog Data Exchange时,该属性必须被设置为True。类型:布尔值 默认值:真

    Left text:

    将单选钮的标题文本显示于圆形标记的左边。类型:布尔值 默认值:假

    Push-like:

    使一个复选框、三态复选框或单选项具有类似于下压按钮的外观和行为。该按钮在选中时显示为凸起,在不被选中时显示为凹下(参见图。类型:布尔值 默认值:假

    Notify:

    决定在默认情况下当单选钮被单击或双击时向父窗口发送通知消息。类型:布尔值 默认值:真

    图6. 31 具有Pusk-like样式的单选钮

    5. 将性别框内的两个控件的ID按从上到下的顺序设置为IDC_SEX1和IDC_SEX2;将年龄框内的两个控件的ID按从上到下的顺序设置为IDC_AGE1、IDC_AGE2、IDC_AGE3、IDC_AGE4和IDC_AGE5。

    在程序运行时可以调用CButton的成员函数SetCheck设置单选钮的选中状态。该成员函数带有一个类型为整型的参数,该参数为0表示清除选中按钮的选中状态,参数为1表示设置选中按钮的选中状态。

    · 注意: 

    · 如果我们在程序中调用SetCheck设置同一组中某一单选钮的为选中状态,并不意味着同时清除同一组中其它单选钮的选中状态。以前面创建的工程来举例,请看下面的两行代码: 

    · ((CButton*)GetDlgItem(IDC_AGE1))->SetCheck(1); 

    · ((CButton*)GetDlgItem(IDC_AGE5))->SetCheck(1); 

    上面的代码将导致年龄组中的第一个按钮和第五个按钮在对话框第一次显示时同时处于选中状态。这是应该避免的。因此,如果我们通过代码改变了单选钮的选中状态,一定要记得同时清除同组的其它单选钮的选中状态。

    对于单个的单选钮,我们可以调用类CButton的成员函数GetCheck,该函数的返回值为0、1或2,分别代表按钮处理未选中状态、选中状态或中间状态(对三态复选框而言)。但是,对于对话框中的单选锯而言,我们更感兴趣于同一组单选钮中哪一个被选中,因此,调用类CWnd的成员函数GetCheckedRadioButton要更为方便。该成员函数原型如下:

    int GetCheckedRadioButton( int nIDFirstButton, int nIDLastButton );

    第一个参数nIDFirstButton是同一组中的第一个单选钮控件的ID,nIDLastButton是同一组中最后一个单选钮控件的ID。成员函数GetCheckedRadioButton返回指定组中第一个所选中的单选钮(在正常情况下仅应当有一个单钮被选中)的ID,如果没有按钮被选中,则返回0。

    这里需要注意的是,成员函数GetCheckedRadioButton被没有要求两个参数nIDFirstButton和nIDLastButton所指定的控件一定位于同一组中。

    · 注意: 

    · 若干个单选钮是否属于同一组是以其Tab顺序来排定的,而GetCheckedRadioButton函数是以ID顺序来检查按钮的选定状态的。因此,如果传递给函数GetCheckedRadioButton的第一个参数的值大于第二个参数的值时,其返回值总是为0,而事实上,由这两个参数指定的单选钮的TAB顺序可能恰恰相反。因此,一般情况下我们应该尽量保证同一组单选钮的资源ID是连续递增的。通常这些资源ID是在头文件Resource.h中定义的。如果你同一组的单选钮不是一次创建的,那么它们的资源ID可能不是连续递增的,甚至可能是相反的。这时我们可以手动的修改资源头文件中的宏定义,以保证如GetCheckedRadioButton之类的成员函数得到正确的结果。 

    同时,这也说明一点,即使用GetCheck一个一个控件的检查各单选钮的选中状态要安全得多。

    下面我们来完成应用程序RadioButton。

    首先,使用ClassWizard重载类CDialog的OnOK成员函数,方法是重载ID为IDOK的按钮的BN_CLICKED命令处理函数。由ClassWizard生成的默认重载形式如下:

    void CRadioBoxDlg::OnOK() 

    {

    // TODO: 在此添加附加的验证

    CDialog::OnOK();

    }

    这里特定的代码来替代前面的// TODO注释后得到如下的程序代码:

    void CRadioBoxDlg::OnOK() 

    {

    // 暂时隐藏主对话框

    ShowWindow(SW_HIDE);

    UINT nSex=GetCheckedRadioButton(IDC_SEX1,IDC_SEX2); // 获得性别选择

    UINT nAge=GetCheckedRadioButton(IDC_AGE1,IDC_AGE5); // 获得年龄选择

    CString msg="性别: "; // 保存输出消息字符串

    // 根据用户的选择生成消息串

    // 添加性别信息

    switch (nSex)

    {

    case IDC_SEX1:

    msg+="男\n";

    break;

    case IDC_SEX2:

    msg+="女\n";

    break;

    default:

    break;

    }

    // 添加年龄信息

    msg+="年龄: ";

    switch (nAge)

    {

    case IDC_AGE1:

    msg+="18 岁以下";

    break;

    case IDC_AGE2:

    msg+="18 - 25 岁";

    break;

    case IDC_AGE3:

    msg+="25 - 35 岁";

    break;

    case IDC_AGE4:

    msg+="35 - 45 岁";

    break;

    case IDC_AGE5:

    msg+="45 岁以上";

    break;

    default:

    break;

    }

    msg+="\n\n以上数据是否正确?";

    // 显示输入消息框询问用户所输入的信息是否正确

    if(MessageBox(msg,NULL,MB_YESNO|MB_ICONQUESTION)==IDNO)

    {

    // 当用户回答“否”时重新显示对话框以供便用户可以更改所作的选择

    ShowWindow(SW_SHOW);

    return;

    }

    // 否则退出应用程序

    CDialog::OnOK();

    }

    以上应用程序的运行结果如图6.32所示:

    按如图6.32所示进行选择,单击确定弹出如图6.33所示的对话框。

    下一节中我们将讲述复选框的使用。

    图6. 32 单选钮示例程序的运行结果

    图6. 33 单击“确定”之后的确认消息框

    6.3.5 复选框

    复选框与单选钮很相象,不同之处在于在同一组控件中,通常使用复选框来代表多重选择,即选项不是互斥的。从外观上来说,复选框所使用的选中标记是一个方框和方框里面的小叉,而不是单选钮所使用的小圆圈和里面的小点。

    对于编程者来说,复选框和单选钮非常相似。我们通过SetCheck成员函数来设置某一复选框的选中状态,通过GetCheck成员函数来获取某一复选框的选中状态。一般来说,对于复选框,由于其选项不是互斥的,我们一般不通过GetCheckedRadioButton之类的函数来获得处于选中状态的按钮。

    以下特定于复选框的样式可以Properties对话框的Styles属性页中进行设置:

    Auto:

    对于Auto属性为真的复选框,在单击时将自动在“选中”和“不选中”之间进行切换。如果在一组复选框中使用了Dialog Data Exchange,则必须将该属性设置为真。类型:布尔值 默认值:真

    Tri-state:

    创建三态复选框。除了处于“选中”和“不选中”状态外,三态复选框还可以处于变灰状态。通常,态复选框的变灰状态表示其选中状态不确定。在很多软件的安装程序中,变灰往往表示仅选中该组件中的一部分。

    图6. 34 工程CheckBox的主对话框的设计

    下面的应用程序举例说明了复选框的使用。

    1. 使用默认选项创建一个基于对话框的MFC工程,设置工程名为CheckBox。

    2. 按图6.34绘制对话框中的各个复选框(在Control工具箱中复选框所对应的图标为),并按表6.24设置各复选框的样式和属性。

    表6. 24 工程CheckBox中各控件的属性设置

    控件

    ID

    标题文本

    其它

    复选框

    IDC_PLACE1

    在家里(&H)

    Auto属性和Tri-state属性均为真

    IDC_PLACE2

    在公司办公室(&O)

    IDC_PLACE3

    在学校公共机房(&S)

    IDC_OFTEN

    经常

    Auto属性为假,Tri-state属性为真

    IDC_SELDOM

    偶尔

    IDC_NEVER

    从不

    组框

    IDC_STATIC

    使用计算机的场所

     

    3. 使用下面的代码替换类CCheckBoxDlg的成员函数OnInitDialog中的// TODO注释:

    ((CButton*)GetDlgItem(IDC_OFTEN))->SetCheck(1);

    ((CButton*)GetDlgItem(IDC_SELDOM))->SetCheck(2);

    ((CButton*)GetDlgItem(IDC_NEVER))->SetCheck(0);

    由于三个复选框IDC_OFTEN、IDC_SELDOM、IDC_NEVER的Auto属性值为假,因此当用户单击这三个复选框时其状态不会发生改变。它们在本示例程序中起了图例的作用。

    4. 在类CCheckBoxDlg中重载类CDialog的成员函数OnOK如下(关于对命令处理成员函数OnOK的重载我们已经在前一小节中作了讲述):

    void CCheckBoxDlg::OnOK() 

    {

    // 定义和初始化所用的变量

    CString strMsg, // 消息字符串

    strMsgA[3]; // 分别对应于三种不同时间频度的消息字符串

    int iCount[3]; // 对应于每种时间频度的情况计数

    // 初始化各变量

    iCount[0]=iCount[1]=iCount[2]=0;

    strMsgA[0]="从不在";

    strMsgA[1]="经常在";

    strMsgA[2]="偶尔在";

    int i; // 用着循环变量或中间变量

    // 检查各复选框的选中状态,并根据用户的选择生成对应于三种不同时间

    // 频度的消息字符串

    // 检查复选框 IDC_PLACE1

    i=( (CButton*)GetDlgItem(IDC_PLACE1) )->GetCheck();

    if ( (iCount[i]++)==0 )

    strMsgA[i]+="家里";

    else

    strMsgA[i]+="、家里";

    // 检查复选框 IDC_PLACE2

    i=( (CButton*)GetDlgItem(IDC_PLACE2) )->GetCheck();

    if ( (iCount[i]++)==0 )

    strMsgA[i]+="公司办公室";

    else

    strMsgA[i]+="、公司办公室";

    // 检查复选框 IDC_PLACE3

    i=( (CButton*)GetDlgItem(IDC_PLACE3) )->GetCheck();

    if ( (iCount[i]++)==0 )

    strMsgA[i]+="学校开放机房";

    else

    strMsgA[i]+="、学校开放机房";

    // 为了符合汉语的语气转折,判断是否需要在“从不……”分句前添加转折

    // 连词“但”。如果用户对三种情况的选择都是“从不”,那么这个“但”

    // 字是不应该要的。

    if ( !(iCount[1]==0 && iCount[2]==0) )

    strMsgA[0]=CString("但")+strMsgA[0];

    // 如果用户对三种情况的选择都不属于某种时间频度,那么该时间频度所对应

    // 的消息字符串应该为空。否则,在该分句的末尾加了字符串“使用计算机,”。

    for (i=0;i<3;i++)

    {

    if ( iCount[i]==0 )

    strMsgA[i]="";

    else

    strMsgA[i]+="使用计算机,";

    }

    // 生成最终显示的消息字符串

    strMsg=CString("您")+strMsgA[1]+strMsgA[2]+strMsgA[0];

    // 处理消息字符串的标点

    strMsg=strMsg.Left( strMsg.GetLength()-2 )+"。";

    // 弹出消息框询问用户所输入的数据是否正确

    if ( MessageBox( strMsg,"确认",MB_YESNO|MB_ICONQUESTION )==IDNO )

    {

    // 如果用户选择“否”,则重新输入数据

    return;

    }

    // 调用基类的 OnOK 成员函数,并关闭对话框

    CDialog::OnOK();

    }

    上面的代码都加上了详细的注释,而且所用的函数也都是我们所熟知的,这里我们就不再重复讲述了。

    到目前为止,我们已经讲述完了Windows标准控件中的按钮类控件:下压按钮、组框、单选钮和复选框。此外,我们还介绍了位图按钮,一般来说我们并不把它归入Windows标准控件中,而认为它是由MFC提供的少数几个控件之一。而位图按钮事实上是具有Owner draw属性的自绘制下压按钮,MFC类CBitmapButton封装了其内部实现的复杂性,而以简单的接口提供给程序员。

    作为本节的结束,我们来讨论一样如何改变按钮标题文本的字体属性。在Developer Studio的资源编辑器中,我们可以统一的修改同一对话框中所有按钮的标题文本的字体属性。方法是打开对话框本身的属性(Properties)对话框,在General选项卡中单击Font按钮,从弹出Select Dialog Font对话框中选择对话框所用的字体。

    图6. 35 设置对话框的字体属性

    通过上面的方法设置的字体对整个对话框中所有的控件都有效。如果需要设置单个控件的字体,我们必须通过编写代码来实现。下面的示例程序ButtonFont演示了如何单独更改某个控件的字体。

    图6. 36 示例程序ButtonFont的主对话框

    按图6.36绘制应用程序主对话框中所有的各按钮控件。其中标签为“我爱你”的按钮ID为IDC_LOVE,标签为“改变字体”的按钮ID为IDC_CHANGEFONT。

    在类CButtonFontDlg中添加类型为CFont的私有成员变量m_Font。

    为按钮IDC_CHANGEFONT的BN_CLICKED事件编写下面的处理函数:

    void CButtonFontDlg::OnChangefont() 

    {

    // 获取按钮 IDC_LOVE 的当前所用字体

    LOGFONT lf;

    GetDlgItem(IDC_LOVE)->GetFont()->GetLogFont(&lf);

    // 使用按钮的当前字体初始化字体对话框

    CFontDialog dlgFontDlg(&lf);

    // 显示字体选择对话框

    if (dlgFontDlg.DoModal()==IDOK)

    {

    // 如果用户在字体选择对话框中单击了“确定”按钮,

    // 则使用

    dlgFontDlg.GetCurrentFont(&lf);

    m_Font.DeleteObject();

    m_Font.CreateFontIndirect(&lf);

    GetDlgItem(IDC_LOVE)->SetFont(&m_Font);

    }

    }

    编译并运行程序ButtonFont,单击“改变字体”按钮,在随后弹出的字体选择对话框中设置字体并单击“确定”按钮。对话框的显示可能如图6.37所示。

    图6. 37 示例程序ButtonFont的运行结果

    · 注意: 

    · 在示例程序中,如果不定义类CButtonFontDlg的成员变量m_Font,命令处理函数OnChangefont可以应该这样编写: 

    · void CButtonFontDlg::OnChangefont() 

    · { 

    · // 获取按钮 IDC_LOVE 的当前所用字体 

    · LOGFONT lf; 

    · GetDlgItem(IDC_LOVE)->GetFont()->GetLogFont(&lf); 

    · 

    · // 使用按钮的当前字体初始化字体对话框 

    · CFontDialog dlgFontDlg(&lf); 

    · 

    · // 显示字体选择对话框 

    · if (dlgFontDlg.DoModal()==IDOK) 

    · { 

    · // 如果用户在字体选择对话框中单击了“确定”按钮, 

    · // 则将按钮 IDC_LOVE 的标题文本字体设置为所选定的字体。 

    · static CFont font; 

    · dlgFontDlg.GetCurrentFont(&lf); 

    · font.DeleteObject(); 

    · font.CreateFontIndirect(&lf); 

    · GetDlgItem(IDC_LOVE)->SetFont(&font); 

    · } 

    · } 

    按下面的方式编写命令处理函数OnChangefont不会得到正确的结果:

    · void CButtonFontDlg::OnChangefont() 

    · { 

    · ... 

    · if (dlgFontDlg.DoModal()==IDOK) 

    · { 

    · CFont font; 

    · dlgFontDlg.GetCurrentFont(&lf); 

    · font.DeleteObject(); 

    · font.CreateFontIndirect(&lf); 

    · GetDlgItem(IDC_LOVE)->SetFont(&font); 

    · } 

    · } 

    之所以会出现这种情况与用来设置字体的CFont变量的存活期有关。

     

    第四节 静态控件

    静态控件一般用来显示静态的文本、图标、位图或图元文件,它不能用来接受用户的输入,也很少用来显示输出,而在更多的情况下用作那些没有固定的标题文本属性的控件(如文本编辑控件、列表框等)的标签,或者用来进行控件的分组,或者用来显示一些提示性文本。

    MFC类CStatic封装了标准的Windows静态控件。下面的示例程序StaticDemo演示了静态控件的使用。

    1. 使用AppWizard创建一个基于对话框的MFC应用程序,设置其工程名为StaticDemo。

    2. 按如图6.38绘制主对话框中的控件。其中标签为“静态控件”的静态控件ID为IDC_STATIC。需要注意是的,由资源管理器添加的静态控件在默认情况下其ID均为IDC_STATIC,因此,如果需要在程序中区分和操纵各个不同的静态控件,一般情况下我们都需要更改新添加的静态控件的ID值。这里我们将静态控件的ID值设置为IDC_STATICDEMO。

    图6. 38 示例程序StaticDemo的主对话框

    以下属性和样式没有在本章前面的内容中涉及,它们可以适用于静态控件。可以通过静态控件的Properties属性对话框的Styles选项卡进行这些属性或样式的设置。

    Align text:

    决定静态文本控件中文本的横向对齐方式。可供选择的值为Left (向左对齐)、Center (居中对齐)和Right (向右对齐)。默认值:Left

    Center Vertically:

    在静态文本控件中将文本进行垂直居中。类型:布尔值 默认值:假

    No prefix:

    不将控件文本中的“&”符解释为助记字符。在默认情况下,“&”符号在显示时会被去掉,取而代之的是紧接“&”符之后的字符被以加下划线的格式进行显示。我们早在前面说过,通过双写“&”符可以在控件文本中显示出实际的“&”符,但是,对于一些特殊的场合,如使用静态文本控件来显示文件名的时候,将No prefix属性设置为“真”要更方便。

    No wrap:

    以左对齐的方式来显示文本,并且不进行文本的自动回行。超出控件右边界的文本将被裁去。需要注意的是,这时即使使用转义字符序列"\n"也不可以强制控件文本进行换行。类型:布尔值 默认值:假

    Simple:

    禁止设置Text Align属性和No Wrap样式。在该属性为真的情况下,静态文本控件中的文本不会被自动回行,也不会被剪裁。类型:布尔值 默认值:假

    Notify:

    决定控件在被单击时是否通知父窗口。类型:布尔值 默认值:假

    Sunken:

    使用静态文本控件看上去有下凹的感觉。类型:布尔值 默认值:假

    Border:

    为文本控件创建边框。类型:布尔值 默认值:假

    4. 静态控件一般不用于输入,但是如果它的Notify属性设置为真,则当用户单击静态控件时,静态控件将向父窗口发送通知消息。但是,我们不可以使用前面所讲述的方法(即使用ClassWizard或从上下文菜单中选择Events命令)来为静态控件添加消息处理函数。而要以手动的方式来实现这一点。下面我们结合示例StaticDemo来说明如何为静态控件添加单击事件的命令处理程序。在进行下面的步骤之前,请确认静态控件IDC_STATICDEMO的Notify属性值为真。

    在类CStaticDemoDlg的定义处添加下面的命令处理函数声明:

    afx_msg void OnStaticDemo();

    最好把成员函数OnStaticDemo的声明与其它命令处理函数的声明放在一起,但不要放到//{{AFX_MSG和//}}AFX_MSG之间。

    然后,打开类CStaticDemoDlg的实现文件StaticDemoDlg.cpp,在宏

    BEGIN_MESSAGE_MAP(CStaticDemoDlg, CDialog)

    和宏

    BEGIN_MESSAGE_MAP

    之间添加如下的消息映射入口:

    ON_BN_CLICKED(IDC_STATICDEMO, OnStaticDemo)

    同样,不要把手动添加的消息映射入口项放到注释//{{AFX_MSG_MAP和//}}AFX_MSG_MAP之间。

    手动添加成员函数OnStaticDemo或OnDoubleclickedStaticDemo的实现代码:

    void CStaticDemoDlg::OnStaticDemo()

    {

    MessageBox("您刚才单击了“静态控件”!");

    }

    编译上面的示例程序,单击“静态控件”,命令处理函数OnStaticDemo将被调用,从而弹出相应的消息框。

    下面我们来看一下如果在静态控件中使用图标和位图。

    图6. 39 使用图标代替静态控件中的文本

    首先介绍使用图标代替文本的例子,方法如下:

    假设对话框类为CStaticDemoDlg,所需使用图标的静态控件ID为IDC_STATICDEMO,相应的图标的ID为IDR_MAINFRAME,则可用下面的代码代替类CStaticDemoDlg的成员函数OnInitDialog中的// TODO注释:

    // 获得指向静态控件的指针

    CStatic *pStaticDemo=(CStatic*)GetDlgItem(IDC_STATICDEMO);

    // 加载图标

    HICON hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);

    // 设置静态控件的样式以使得可以使用图标,并使图标显示时居中

    pStaticDemo->ModifyStyle(0xF,SS_ICON|SS_CENTERIMAGE);

    // 设置静态控件图标

    pStaticDemo->SetIcon(hIcon);

    运行该程序,显示如图6.39。

    接着我们来看如何使用位图代替文本,方法如下:

    假设所用位图的资源ID为IDB_STATICDEMO,其余设置如上。用以下代码来代替成员函数OnInitDialog中的// TODO注释:

    // 获得指向静态控件的指针

    CStatic *pStaticDemo=(CStatic*)GetDlgItem(IDC_STATICDEMO);

    // 获得位图句柄

    HBITMAP hBitmap=::LoadBitmap(AfxGetApp()->m_hInstance, 

    MAKEINTRESOURCE(IDB_STATICDEMO));

    // 设置静态控件的样式以使得可以使用位图,并使位图在显示时居中

    pStaticDemo->ModifyStyle(0xF,SS_BITMAP|SS_CENTERIMAGE);

    // 设置静态控件显示时使用的位图

    pStaticDemo->SetBitmap(hBitmap);

    编译并运行该程序,对话框显示如图6.40所示。

    图6. 40 使用位图代替文本的静态控件

    · 注意: 

    · 在使用位图的例子中,传递给ModifyStyle的第一个参数的值绝对不可以为0,否则将得不到正常的运行结果。 

     

    第五节 文本编辑控件

    静态文本控件只能用来显示文本,而不可以用来输入文本。如果需要提供输入文本的功能应该使用文本编辑控件。文本编辑控件在Control工具箱中对应的图标为。对于文本编辑控件,除了我们在前面所涉及的一些外,还可以设置以下的一些属性样式:

    Align text:

    决定当Multiline属性为真时文本的对齐方式。默认值为:Left

    Multi-line:

    创建一个多行文本编辑控件。当一个多行文本编辑控件具有输入焦点时,如果用户按下了ENTER键,以默认情况下的行为是选择对话框中的默认命令按钮,而不是向文本编辑控件中插入新行。将AutoHScroll属性或Want return属性设置为真可以将用户按下的ENTER键解释为插入新行,而不是选择默认命令按钮。

    在选择了AutoHScroll属性时,如果插入点超过了控件的右边界,多行文本编辑控件自动进行水平滚动。用户可以使用ENTER键来开始新行。

    如果没有选择AutoHScroll属性,多行文本编辑控件将视需要将文本进行自动折行。而仅当Want return属性为真时,用户才可以使用ENTER键来开始新行。

    多行文本编辑控件也可以拥有自己的滚动条。具有滚动条的编辑控件处理自己的滚动条消息,而不具有滚动条的编辑控件也可以由父窗口发送的滚动条消息。

    类型:布尔值 默认值:假

    Number:

    用户不能输入非数字字符。类型:布尔值 默认值:假

    Horizontal scroll:

    为多行控件提供水平滚动条。类型:布尔值 默认值:假

    Auto HScroll:

    当用户输入的字符超过了编辑框的右边界时自动水平向右滚动文本。类型:布尔值 默认值:真

    Vertical scroll:

    为多行控件提供垂直滚动条。类型:布尔值 默认值:假

    Auto VScroll:

    在多行控件中,当用户在最后一行按下ENTER键时自动向上滚动文本

    Password:

    当用户键入时将所有字符显示为星号(*)。该属性对于多行控件不可用。类型:布尔值 默认值:假

    No hide selection:

    改变当编辑框失去和重新获得焦点时文本的显示方式。如果该属性为真,在编辑框中选中的文本在任何时候都显示为选中状态(即反白状态)。类型:布尔值 默认值:假

    OEM convert:

    将键入的文本从Windows字符集转换为OEM字符集,再转换回Windows字符集。该操作确认应用程序在调用AnsiToOem函数将编辑框中的字符串转换为OEM字符串时进行正确的字符转换,因此该样式对于包括文件名的编辑控件特别有用。类型:布尔值 默认值:假

    Want return:

    指定当用户在多行编辑控件中按下ENTER键时插入一个回车符,否则用户按下ENTER将被解释为选择了对话框中的默认命令按钮。该样式对于单行编辑框控件没有任何影响。类型:布尔值 默认值:假

    Border:

    在编辑框边缘创建边框。类型:布尔值 默认值:真

    Uppercase:

    将用户在编辑框中输入的字符转换为大写。类型:布尔值 默认值:假

    Lowercase:

    将用户在编辑框中输入的字符转换为小写。

    类型:布尔值 默认值:假

    Read-only:

    防止用户编辑和更改编辑框中的文本。类型:布尔值 默认值:假

    相比我们在前面所讲述的几个类CButton、CBitmapButton和CStatic而言,封装标准编辑控件的MFC类CEdit要复杂得多。表给出了在类CEdit中定义的成员函数:

    表6. 25 类CEdit中定义的成员函数

    成员函数

    描述

    CEdit

    构造CEdit控件对象

    Create

    创建Windows编辑控件,并将其与CEdit对象相关联

    GetSel

    获得编辑控件中当前选择的开始和结束字符的位置

    ReplaceSel

    使用特定的文本来替换编辑控件中的当前选择

    SetSel

    设置编辑控件中所选定的字符范围

    Clear

    删除编辑控件中当前选定的字符

    Copy

    使用CF_TEXT格式将编辑控件中当前选定的文本复制到剪贴板

    Cut

    删除当前选定的字符,并将所删除的字符复制到剪贴板

    Paste

    将剪贴板中格式为CF_TEXT的数据(如果有的话)插入到编辑框中的当前位置。

    Undo

    撤销最后一次编辑操作

    CanUndo

    决定编辑控件的操作是否可以被撤销

    EmptyUndoBuffer

    重置编辑控件的undo标志

    GetModify

    判断编辑控件中的内容是否被修改过

    SetModify

    设置或清除编辑控件中的修改标志

    SetReadOnly

    设置编辑控件的只读状态

    GetPasswordChar

    当用户输入文本时获得编辑控件中显示的密码字符

    SetPasswordChar

    设置或移去当用户输入文本时编辑控件中显示的密码字符

    GetFirstVisibleLine

    获得编辑控件中最上面的可见行

    LineLength

    获得编辑控件中一行的长度

    LineScroll

    滚动多行编辑控件中的文本

    LineFromChar

    获得包含指定索引字符的行的行号

    GetRect

    获得编辑控件的格式矩形

    LimitText

    限制用户可以在编辑控件中输入的文本的长度

    GetLineCount

    获得多行编辑控件中行的数目

    GetLine

    获得编辑控件中的一行文本

    LineIndex

    获得多行编辑控件中一行的字符索引

    FmtLines

    在多行编辑控件中设置是否包含软换行符的开关

    续表6.25

    成员函数

    描述

    SetTabStops

    在多行编辑控件中设置制表位

    SetRect

    设置多行文本编辑控件的格式矩形,并更新控件

    SetRectNP

    设置多行文本编辑控件的格式矩形,但不重绘控件窗口

    GetHandle

    获得为多行编辑控件分配的内存的句柄

    SetHandle

    设置供多行编辑控件使用的本地内存句柄

    GetMargins

    获得当前CEdit对象的左右页边距

    SetMargins

    设置当前CEdit对象的左右页边距

    GetLimitText

    获得当前CEdit对象可以包括的最大文本量

    SetLimitText

    设置当前CEdit对象可以包括的最大文本量

    CharFromPos

    获得最接近于指定位图的行和字符的索引

    PosFromChar

    获得指定字符索引的左上角的坐标

    上面的成员函数涵盖了编辑控件在使用中的很多方面,可以满足我们在很多情况下的绝大部分需要。这里要注意的是,一些CWnd中定义的成员函数也是很重要的,比如说我们常用CWnd的成员函数GetWindowText和SetWindowText来获取和设置编辑控件的文本,使用成员函数GetFont和SetFont来获取和设置编辑控件显示文本时所使用的字体。

    编辑控件可以向父窗口发送的通知消息也要比前面讲述的几种控件多。这些消息有:

    ON_EN_CHANGE:ON_EN_ERRSPACE:

    编辑控件不能按选定需要分配足够的内存

    ON_EN_HSCROLL:

    用户单击了编辑控件中的水平滚动条。父窗口在屏幕更新前获得此消息

    ON_EN_KILLFOCUS:

    编辑控件失去输入焦点

    ON_EN_MAXTEXT:

    当前插入内容超过了编辑控件中的指定的字符数,该插入内容已被裁剪。如果控件没有设置ES_AUTOHSCROLL样式,那么在插入的字符超出了编辑控件的宽度也发送该通知消息。同样,如果控件没有指定ES_AUTOVSCROLL样式,该通知也以插入操作导致总行数超过编辑控件的高度时发送。

    ON_EN_SETFOCUS:

    编辑按钮获得输入焦点

    ON_EN_UPDATE:

    控件已对文本作了格式化,但尚未显示文本。通常可以处理该消息以决定是否需要对窗口的大小作改变等。

    ON_EN_VSCROLL:

    用户单击了编辑控件的垂直滚动条。父窗口在屏幕更新前收到该消息。

    示例程序EditDemo演示了编辑控件的一般使用方法。按如下步骤创建该工程:

    1. 使用AppWizard创建基于对话框的工程EditDemo。

    2. 向工程中添加菜单资源IDR_MAINMENU,该菜单资源包括两个顶层菜单项“文件(&F)”和“编辑(&E)”,“文件(&F)”下包括如图6.41所示的菜单命令。各菜单命令(不包括具有Separator样式的菜单项)的资源ID依次为ID_FILE_NEW和ID_FILE_EXIT。“编辑(&E)”菜单下包括如图6.42所示菜单命令。各菜单命令的资源ID依次为ID_EDIT_UNDO、ID_EDIT_CUT、ID_EDIT_COPY、ID_EDIT_PASTE、ID_EDIT_DEL、ID_EDIT_SELECTALL和ID_EDIT_SETFONT。

    图6. 41 “文件”菜单下的菜单命令

    图6. 42 “编辑”菜单下的菜单命令

    3. 按图6.43在应用程序的主对话框上绘制编辑框(对应于Control工具箱中的图标为),设置其ID为IDC_EDIT,并将其Multiline属性、Auto VScroll属性和Want return属性设置为真,同时将Auto HScroll属性设置为假。这里,编辑框IDC_EDIT在大小和位置并不重要,我们将在程序中对其进行调整。

    4. 删除原有的“确定”按钮和“取消”按钮。接着打开对话框本身的属性对话框,从Menu下拉列表框中选择IDR_MAINMENU。

    图6. 43 设置主对话框的Menu属性

    5. 在资源管理器中打开菜单资源IDR_MAINMENU,如图6.44所示。在任一菜单项上单击鼠标右键,选择命令ClassWizard。这时ClassWizard将弹出如图6.45所示的对话框,单击Cancel。在Object IDs处选择ID_FILE_EXIT,在Messages处选择COMMAND,单击And function按钮并接受默认的处理函数名OnFileExit,在函数OnFileExit中调用类CDialog的成员函数OnCancel,如下面的代码所示:

    void CEditDemoDlg::OnFileExit() 

    {

    // 调用基类成员函数 OnCancel 终止对话框

    OnCancel(); 

    }

    按同样的方法为ID_FILE_NEW的COMMAND命令添加处理函数OnFileNew如下:

    void CEditDemoDlg::OnFileNew() 

    {

    // 将编辑控件中的文本初始化为零,

    // 并清除其撤消缓冲区。

    CEdit *pEdit=(CEdit*)GetDlgItem(IDC_EDIT);

    pEdit->SetWindowText("");

    pEdit->EmptyUndoBuffer();

    }}

    图6. 44 在Developer Studio的资源编辑器中打开菜单资源IDR_MAINMENU

    为ID_EDIT_UNDO的COMMAND命令添加处理函数OnEditUndo如下:

    void CEditDemoDlg::OnEditUndo() 

    {

    // 直接调用类 CEdit 的成员函数 Undo

    CEdit *pEdit=(CEdit*)GetDlgItem(IDC_EDIT);

    pEdit->Undo();

    }

    图6. 45 询问是否将菜单IDR_MAINMENU与某一视类相关联

    为ID_EDIT_CUT的COMMAND命令添加处理函数OnEditCut如下:

    void CEditDemoDlg::OnEditCut() 

    {

    // 直接调用类 CEdit 的成员函数 Cut

    ((CEdit*)GetDlgItem(IDC_EDIT))->Cut(); 

    }

    为ID_EDIT_COPY的COMMAND命令添加处理函数OnEditCopy如下:

    void CEditDemoDlg::OnEditCopy() 

    {

    // 直接调用类 CEdit 的成员函数 Copy

    ((CEdit*)GetDlgItem(IDC_EDIT))->Copy(); 

    }

    为ID_EDIT_PASTE的COMMAND命令添加处理函数OnEditPaste如下:

    void CEditDemoDlg::OnEditPaste() 

    {

    // 直接调用类 CEdit 的成员函数 Paste

    ((CEdit*)GetDlgItem(IDC_EDIT))->Paste();

    }

    为ID_EDIT_DEL的COMMAND命令添加处理函数OnEditDel如下:

    void CEditDemoDlg::OnEditDel() 

    {

    // 直接调用类 CEdit 的成员函数 Clear

    ((CEdit*)GetDlgItem(IDC_EDIT))->Clear(); 

    }

    为ID_EDIT_SELECT的COMMAND命令添加处理函数OnEditSelectall如下:

    void CEditDemoDlg::OnEditSelectall() 

    {

    int nStart,nEnd;

    // 设置选定字符的开始

    nStart=0;

    // 设置选定字符的结尾。函数 GetWindowTextLength 返回编辑控件中文本的长度

    nEnd=((CEdit*)GetDlgItem(IDC_EDIT))->GetWindowTextLength();

    // 以 nStart 和 nEnd 为参数调用类 CEdit 的成员函数 SetSel

    ((CEdit*)GetDlgItem(IDC_EDIT))->SetSel(nStart,nSel);

    }

    为ID_EDIT_SETFONT的COMMAND命令添加处理函数OnEditSetfont如下:

    void CEditDemoDlg::OnEditSetfont() 

    {

    LOGFONT lf;

    static CFont font;

    // 获得编辑框原来使用的字体信息,并使用该信息初始化字体对话框

    CEdit *pEdit=(CEdit*)GetDlgItem(IDC_EDIT);

    pEdit->GetFont()->GetLogFont(&lf);

    CFontDialog dlg(&lf);

    // 弹出字体对话框以供用户选择新的字体,

    // 并在用户确认的情况下更改编辑控件所使用的字体。

    if (dlg.DoModal()==IDOK)

    {

    dlg.GetCurrentFont(&lf);

    font.DeleteObject();

    font.CreateFontIndirect(&lf);

    pEdit->SetFont(&font);

    }

    }

    在成员函数OnEditSetfont中所使用的方法和技巧已在第三节的末尾讲述如何为按钮控件设置字体时进行了介绍。因此对于函数OnEditSetfont我们不进行详细的注解。

    6. 考虑下面的情况:如果当前没有可供撤消的操作,“编辑”菜单下的“撤消”应该处于不可用(变灰)状态;同样的,如果当前编辑控件中没有选定任何文本,那么“剪贴”、“复制”以及“删除”命令也应该不可用;如果当前剪贴板中没有任何文本数据,“粘贴”命令应该不可用。我们通过为消息WM_INITMENUPOPUP添加消息处理函数来设置各菜单命令的可用状态。该消息在用户单击某菜单之后在菜单项弹出之前发送。

    对于类CEditDemoDlg,我们不能使用ClassWizard来为消息WM_INITMENUPOPUP添加消息处理函数,但事实上,对话框也可以接收到消息WM_INITMENUPOPUP。这里,我们可以手动来添加相应的消息映射项。

    第一步是在类CEditDemoDlg的定义中添加消息处理函数

    afx_msg void OnInitMenuPopup( CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu );

    可以把该处理函数的声明添加到由ClassWizard生成的消息处理函数的后面。由ClassWizard生成的消息处理函数位于两行注释标记//{{AFX_MSG和//}}AFX_MSG之间。同我们在此之前强调过的一样,不要将OnInitMenuPopup的声明添加到两行注释之间。以后如果再遇到与此相似的情况,我们将不再强调。

    接着添加相应的消息映射入口,在类CEditDemoDlg的实现文件EditEemoDlg.cpp中找到宏BEGIN_MESSAGE_MAP(CEditDemoDlg, CDialog),在它之后,宏END_MESSAGE_MAP之前添加下面的宏代码:

    ON_WM_INITMENUPOPUP()

    我们仍应将上面的代码添加到注释标记//{{AFX_MSG_MAP和//}}AFX_MSG_MAP之外。同样的,以后如果再遇到这种情况我们将不再强调。

    最后添加函数OnInitMenuPopup的定义:

    void CEditDemoDlg::OnInitMenuPopup( CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu )

    {

    CEdit *pEdit=(CEdit*)GetDlgItem(IDC_EDIT);

    // 当用户单击的是窗口的控制菜单时 bSysMenu 参数为真,否则为假

    if (!bSysMenu)

    {

    // 检查编辑控件是否有可撤消的操作

    if (pEdit->CanUndo())

    {

    pPopupMenu->EnableMenuItem(ID_EDIT_UNDO,MF_ENABLED);

    }

    else

    {

    pPopupMenu->EnableMenuItem(ID_EDIT_UNDO,MF_GRAYED);

    }

    // 检查编辑控件中是否有选定的文本

    int nStart,nEnd;

    pEdit->GetSel(nStart,nEnd);

    if (nStart==nEnd)

    {

    pPopupMenu->EnableMenuItem(ID_EDIT_CUT,MF_GRAYED);

    pPopupMenu->EnableMenuItem(ID_EDIT_COPY,MF_GRAYED);

    pPopupMenu->EnableMenuItem(ID_EDIT_DEL,MF_GRAYED);

    }

    else

    {

    pPopupMenu->EnableMenuItem(ID_EDIT_CUT,MF_ENABLED);

    pPopupMenu->EnableMenuItem(ID_EDIT_COPY,MF_ENABLED);

    pPopupMenu->EnableMenuItem(ID_EDIT_DEL,MF_ENABLED);

    }

    // 检查剪贴板中是否有文本格式的数据可供粘贴

    // 该过程通过调用 Win32 API 函数 IsClipboardFormatAvailable 来实现

    if (IsClipboardFormatAvailable(CF_TEXT))

    {

    pPopupMenu->EnableMenuItem(ID_EDIT_PASTE,MF_ENABLED);

    }

    else

    {

    pPopupMenu->EnableMenuItem(ID_EDIT_PASTE,MF_GRAYED);

    }

    }

    }

    7. 最后我们希望一点,就是说用户可以改变对话框的大小,而且当用户改变对话框的大小时,编辑框自动的改变其大小以适应父窗口大小的变化。方法是为WM_SIZE添加消息处理函数。在进行这一步操作之前,打开对话框的Dialog Properties对话框,在Styles选项卡中将其Border属性设置为Resizing (即可以改变大小),同时将Maximize box属性值设置为真。然后,使用ClassWizard为消息WM_SIZE添加消息处理函数OnSize,其定义如下:

    void CEditDemoDlg::OnSize(UINT nType, int cx, int cy) 

    {

    // 调用基类的 OnSize 成员函数

    CDialog::OnSize(nType, cx, cy);

    CRect rect;

    // 获得父窗口的客户区矩形

    GetClientRect(&rect);

    CEdit *pEdit=(CEdit*)GetDlgItem(IDC_EDIT);

    if (pEdit)

    {

    // 改变编辑控件的大小以适应父窗口大小的改变

    pEdit->MoveWindow(&rect);

    }

    }

    由于OnSize会在对话框第一次显示时被调用,因此使用if语句检查pEdit是否为NULL是必要的。出于同样的目的,我们还需要使用下面的代码来替换成员函数OnInitDialog中的// TODO注释:

    CRect rect;

    GetClientRect(&rect);

    CEdit *pEdit=(CEdit*)GetDlgItem(IDC_EDIT);

    if (pEdit)

    {

    pEdit->MoveWindow(&rect);

    }

    它在对话框第一次显示时完成与上面的OnSize成员函数同样的操作。以保证在第一次显示对话框时编辑框控件以正确的大小进行显示。

    编译并运行上面的程序(如图6.46),并测试其各项功能是否正常。

    图6. 46 示例程序EditDemo的运行结果

    第六节 列表框控件

    列表框控件通常用来列出一系列可供用户从中进行选择的项,这些项一般来说都在字符串的形式给出,但也可以采用其它的形式,如图形等。列表框可以只允许单一选择,也就是说用户同时只能选择所有列表项中的一项;除此之外,列表框也可以是多项选择的,用户可以在多项选择列表框中选择多于一项的列表项。当用户选择了某项时,该项被反白显示,同时列表框向父窗口发送一条通知消息。MFC类CListBox封装了Windows标准列表框控件,其成员函数(参见表6.26)提供了对标准列表框的绝大多数操作。

    表6. 26 在类CListBox中定义的成员函数

    成员函数

    描述

    AddString

    向列表框中添加字符串

    CharToItem

    为不包含字符串的自绘制列表框提供对WM_CHAR的定制处理

    CListBox

    构造一个CListBox对象

    CompareItem

    由框架调用以决定新添加的项在有序自绘制列表框中的位置

    Create

    创建一个Windows列表框控件,并将它与CListBox对象相关联

    DeleteItem

    当用户从自绘制列表框中删除一项时由框架调用

    DeleteString

    从列表框中删除字符串

    Dir

    从当前目录向列表框中添加文件名

    DrawItem

    当自绘列表框的可视部分改变时由框架调用

    FindString

    在列表框中查询指定的字符串

    FindStringExact

    查找与指定字符串相匹配的第一个列表框字符串

    GetAnchorIndex

    返回列表框中当前“锚点”项的基于零的索引

    续表6.26

    成员函数

    描述

    GetCaretIndex

    在多重选择列表框中获得当前拥有焦点矩形的项的索引

    GetCount

    返回列表框中字符串的数目

    GetCurSel

    返回列表框中当前选择字符串的基于零的索引值

    GetHorizontalExtent

    以象素为单位返回列表框横向可滚动的宽度

    GetItemData

    返回下列表框项相关联的32位值

    GetItemDataPtr

    返回指向列表框项的指针

    GetItemHeight

    决定列表框中项的高度

    GetLocale

    获得列表框使用的区域标识符

    GetSel

    返回列表框项的选定状态

    GetSelItems

    返回当前选定字符串的索引

    GetSelCount

    在多重选择列表框中获得当前选定字符串的数目

    GetText

    拷贝列表框项到缓冲区

    GetTextLen

    以字节为单位返回列表框项的长度

    GetTopIndex

    返回列表框中第一个可视项的索引

    InitStorage

    为列表框项和字符串预先分配内存

    InsertString

    在列表框中的指定位置插入一个字符串

    ItemFromPoint

    返回与指定点最接近的列表框项的索引

    MeasureItem

    当自绘列表框创建时由框架调用以获得列表框的尺寸

    ResetContent

    从列表框中清除所有的项

    SelectString

    从单项选择列表框中查找并选定一个字符串

    SelItemRange

    在多重选择列表框中选中某一范围的字符串或清除某一范围的字符串的选定状态

    SetAnchorIndex

    在多重选择列表框的设置扩展选定的起点(“锚点”项)

    SetCaretIndex

    在多重选择列表框中设置当前拥有焦点矩形的项的索引

    SetColumnWidth

    设置多列列表框的列宽

    SetCurSel

    在列表框中选定一字符串

    SetHorizontalExtent

    以象素为单位设置列表框横向可滚动的宽度

    SetItemHeight

    设置列表框中项的高度

    SetItemRect

    返回列表框项当前显示的边界矩形

    SetLocale

    为列表框指定区域标识符

    续表6.26

    成员函数

    描述

    SetSel

    在多重选择列表框中选定一列表框项或清除某一列表框项的选定状态

    SetTabStops

    设置列表框的制表位

    SetTopIndex

    设置列表框中第一个可视项的基于零的索引

    VKeyToItem

    为具有LBS_WANTKEYBOARDINPUT样式的列表框提供定制的WM_KEYDOWN消息处理

    以下是列表框可能向父窗口发送的通知消息及其说明:

    ON_LBN_DLBCLK:

    用户双击了列表框中的字符串。仅当列表框具有LBS_NOTIFY样式时会发送该通知消息

    ON_LBN_ERRSPACE:

    列表框不能按需要分配足够的内存

    ON_LBN_KILLFOCUS:

    列表框失去输入焦点

    ON_LBN_SELCANCEL:

    列表框中的当前选择被取消。仅当列表框具有LBS_NOTIFY样式时才会发送该通知消息

    ON_LBN_SELCHANGE:

    列表框中的选择将被更新。需要注意的是,当使用成员函数CListBox::SetCurSel时不会发送该通知消息,同时,该消息也仅当列表框具有LBS_NOTIFY样式才会发送。对于多重选择列表框,当用户按下光标键时,即使所选择的内容没有改变,也会发送LBN_SELCHANGE通知消息。

    ON_LBN_SETFOCUS:

    列表框获得输入焦点

    ON_WM_CHARTOITEM:

    不包括字符串的列表框收到WM_CHAR消息

    ON_WM_VKEYTOITEM:

    具有LBS_WANTKEYBOARDINPUT样式的列表框接收到WM_KEYDOWN消息

    在资源编辑器中,对应于列表框的Control工具箱图标为。在绘制列表框的同时可以在Properties属性对话框中指定其属性。除了在前面几节中所讲述的以外,我们还可以为列表框设置以下的属性,这些属性可以在Styles选项卡中设置。

    Selection:

    决定列表框的选择方式。可以设置的值如下:

    Single:用户同时只能选择列表框中的一项

    Multiple:用户可以同时选择多于一个的列表框项,但不可以从开始项扩展选定内容。在鼠标单击时可以使用SHIFT键和CTRL键选定和取消选定,同时选定项不一定需要连续。单击或双击未选定项时将选定该项;单击或双击已选定项时将取消对该项的选定。

    Extended:用户可以通过拖动来扩展选定内容。用户可以鼠标和SHIFT键和CTRL键进行选定或取消选定,选择成组的项或不连续的项。

    默认值为Single。

    Owner draw:

    控制列表框的自绘特性。可以设置的值如下:

    No:关闭自绘制样式,列表框中包含的内容为字符串。

    Fixed:指定列表框的所有者负责绘制其内容,并且列表框中的项具有相同的高度。

    Variable:指定列表框的所有者负责绘制其内容,并且列表框的项具有不同的高度。

    当列表框创建时CWnd::OnMeasureItem将被调用;当列表框的可视部分改变时CWnd::OnDrawItem将被调用。

    默认值为No。

    Has strings:

    指定自绘制列表框包括由字符串组成的项。列表框为字符串维护内存和指针,因此应用程序可以使用LB_GETTEXT消息来获得特定项的文本。在默认情况下,除了自绘制按钮以外,所有的列表框都具有该项属性。由应用程序创建的自绘制列表框可以具有或不具有该样式。

    该样式仅当自绘制属性被设置为Fixed或Variable时可用。如果自绘制属性被设置为No,列表框在默认情况下包括字符串。

    类型:布尔值 默认值为假

    Sort:

    以字母为序对列表框内容进行排序。

    类型:布尔值 默认值为真

    Notify:

    如果列表项被单击或双击时通知父窗口。

    类型:布尔值 默认值为真

    Multi-colume:

    指定多列列表框,多列列表框可以在水平方向上进行滚动。消息LB_SETCOLUMNWIDTH用来设置列宽。

    类型:布尔值 默认值为假

    Horizontal scroll:

    创建具有水平滚动条的列表框。类型:布尔值 默认值为假

    Vertical scroll:

    创建具有垂直滚动条的列表框。类型:布尔值 默认值为真

    No redraw:

    指定当发生改变时列表框外观不进行更新。可以通过发送WM_SETREDRAW消息或调用CWnd::SetRedraw函数改变该属性。

    类型:布尔值 默认值为假

    Use tabstops:

    允许列表框在绘制字符串辨认和扩展制表符。默认的制表位为32个对话框单位(DLU)。类型:布尔值 默认值为假

    Want key input:

    指定当用户有按键动作并且列表框具有输入焦点时列表框的所有者收到WM_VKEYTOITEM和WM_CHARTOITEM消息,以允许应用程序在使用键盘输入时进行特定的处理。如果列表框具有了Has Strings样式,列表框将接收到WM_VKEYTOITEM消息;如果列表框不具有WM_CHARTOITEM消息,则列表框将接收到WM_CHARTOITEM消息。

    类型:布尔值 默认值为假

    Disable no scroll:

    当列表框不具有足够多的项时显示不可用的滚动条。如果不使用该属性,在这种情况下将不使用滚动条。类型:布尔值 默认值为假

    No integral height:

    设置对话框的大小严格等于创建对话框时由应用程序指定的大小。一般情况下,Windows改变列表框的大小以使得它不会只显示某一项的一部分,即列表框客户区的高度为项高的整数倍。

    类型:布尔值 默认值为真

    下面的示例程序演示了列表框控件的使用。

    1. 使用AppWizard创建名为ListBoxDemo的基于对话框的MFC应用程序工程。

    2. 按图6.47设计应用程序的主对话框。各控件的属性值如表6.27所示。

    图6. 47 应用程序ListBoxDemo的主对话框

    3. 单击Insert菜单下的Resource命令,插入ID为IDD_INPUT的对话框,按图6.48添加对话框的各个控件。

    图6. 48 应用程序ListBoxDemo的IDD_INPUT对话框

    各控件的属性如表6.28所示。

    4. 为对话框IDD_INPUT创建新的对话框类CInputDlg。方法是在资源编辑器中打开对话框IDD_INPUT,此时按下Ctrl+W键打开ClassWizard,由于尚没有类与对话框IDD_INPUT相关联,因此ClassWizard将弹出如图6.49所示的对话框,询问是否为对话框创建新的类。选择Create a new class (这也是默认选项),单击OK,弹出如图6.50所示的New class对话框。在Name处输入CInputDlg,其余采用默认设置,单击OK即为对话框IDD_INPUT创建了新类CInputDlg。这时就可以使用ClassWizard的Member Variables选项卡为对话框进行如表6.28所示的成员变量映射了。

    表6. 27 应用程序ListBoxDemo主对话框各控件的属性设置

    控件类型

    资源ID

    控件标题

    其他

    列表框

    IDC_LISTSELECTABLE

     

    位于图6.47左边的列表框,其Selection属性为Extended。对应的DDX变量映射(使用ClassWizard的Member Vari-ables选项卡进行设置)为CListBox类型变量m_lsSelectable。

    IDC_LISTSELECTED

     

    位于图6.47右边的列表框,其Selection属性为Extended。对应的DDX变量映射为CListBox类型变量m_lsSelected。

    静态控件

    (无需更改)

    待选择的文件

     

    已选择的文件

     

    下压按钮

    IDC_BTNCHANGEDIR

    <- 改变目录(&H)

     

    IDC_BTNADD

    添加到(&A) ->

     

    IDC_BTNDEL

    删除(&D) <-

     

    IDC_BTNCLEAR

    全部清除(&L) <-

     

     

    表6. 28 对话框IDD_INPUT各控件的属性设置

    控件类型

    资源ID

    控件标题

    其他

    静态控件

    IDC_PROMPT

    提示字符串

    对应的DDX变量映射为CString类型成员变量m_strPrompt

    编辑框

    IDC_INPUT

     

    对应的DDX变量映射为CString类型成员变量m_strInput

    接着为类添加类型为CString的保护成员变量m_strTitle。然而在类CInputDlg中添加成员函数GetInput的声明:

    CString GetInput(LPCTSTR lpszTitle="输入", 

    LPCTSTR lpszPrompt="请在下面的文本框中输入字符串: ");

    该函数显示对话框IDD_INPUT (如图6.51所示),并返回用户在对话框中输入的字符串,如果用户单击了输入对话框的“取消”按钮,则函数返回空字符串,参数lpszTitle为输入对话框的标题,lpszPrompt为输入对话框的提示字符串。其实现如下:

    图6. 49 询问是否为对话框IDD_INPUT创建新类

    图6. 50 为对话框IDD_INPUT创建新类

    图6. 51 输入对话框

    CString CInputDlg::GetInput(LPCTSTR lpszTitle, LPCTSTR lpszPrompt)

    {

    // 设置标题字符串和提示字符串

    m_strTitle=lpszTitle;

    m_strPrompt=lpszPrompt;

    // 显示输入对话框并返回用户输入的字符串

    if (DoModal()==IDOK)

    {

    return m_strInput;

    }

    else

    {

    return CString("");

    }

    }

    为类CInputDlg重载OnInitDialog成员函数

    BOOL CInputDlg::OnInitDialog() 

    {

    CDialog::OnInitDialog();

    // TODO: 在这里添加额外的初始化代码

    SetWindowText(m_strTitle);

    GetDlgItem(IDC_INPUT)->SetFocus();

    // 由于为控件 IDC_INPUT 设置了输入焦点,因此函数 OnInitDialog 应该返回 FALSE

    return FALSE;

    }

    成员函数OnInitDialog的重载版本设置输入对话框的标题文本和提示字符串。

    5. 用下面的代码替代类CListBoxDemoDlg的OnInitDialog成员函数中的// TODO注释:

    m_lsSelectable.ResetContent();

    m_lsSelectable.Dir(0x17,"*.*");

    上面的代码先调用成员函数ResetContent清除列表框IDC_LISTSELECTABLE中的所有项,再调用成员函数Dir使用当前目录下的文件名来填充该列表框。第一个参数0x17是文件类型屏蔽位,它等于0x01|0x02|0x04|0x10,它包括了所有常规属性文件、只读文件、系统文件和目录名,第二个参数为所显示的文件名,在参数中可以使用通配符。

    为按钮IDC_BTNCHANGEDIR的BN_CLICKED命令添加下面的处理函数OnBtnChangeDir:

    void CListBoxDemoDlg::OnBtnChangeDir() 

    {

    CInputDlg dlg;

    CString str=dlg.GetInput("输入目录","输入新的目录名:");

    if (str!="" && str.Left(1)!="\\")

    {

    str+="\\";

    }

    if (str!="")

    {

    m_lsSelectable.ResetContent();

    int iResult=m_lsSelectable.Dir(0x17,str+"*.*");

    if (iResult==LB_ERR)

    {

    MessageBox("添加文件名出错!");

    }

    else if (iResult==LB_ERRSPACE)

    {

    MessageBox("无法为列表框分配足够的内存!");

    }

    }

    }

    上面的代码首先定义一个类型为CInputDlg的成员变量,然后调用其成员函数GetInput (我们已在前面讨论过该成员函数)获得用户输入的列表目录名,如果用户输入的目录名不为空字符串,则调用类CListBox的成员函数将指定目录下的文件名添加到列表框IDC_LISTSELECTABLE中,如果添加失败,则弹出相应的出错信息。

    为按钮IDC_BTNADD的BN_CLICKED命令添加下面的处理函数OnBtnAdd:

    void CListBoxDemoDlg::OnBtnAdd() 

    {

    CString str;

    for (int i=0; i<m_lsSelectable.GetCount(); i++)

    {

    if (m_lsSelectable.GetSel(i))

    {

    m_lsSelectable.GetText(i, str);

    m_lsSelected.AddString(str);

    }

    }

    }

    其中,类CListBox的成员函数GetCount返回了列表框中项的数目,然后使用GetSel成员函数获得每一项的选定状态,这里要注意列表框中项的索引是基于零的。如果该项的已被选定(即GetSel成员函数返回真值),则使用GetText成员函数获得该项的文本,并将它放到CString类型的变量str中,接着,调用类CListBox中定义的成员函数AddString将字符串str添加到列表框IDC_LISTSELECTED中。

    为按钮IDC_BTNDEL的BN_CLICKED命令添加如下的处理函数OnBtnDel:

    void CListBoxDemoDlg::OnBtnDel() 

    {

    for (int i=m_lsSelected.GetCount()-1; i>-1; i--)

    {

    if (m_lsSelected.GetSel(i))

    {

    m_lsSelected.DeleteString(i);

    }

    }

    }

    上面的代码从最末一项开始,检查列表框IDC_LISTSELECTED中每一项的选定状态,如果发现该项被选定,则将它从列表框中删除。从列表框中删除一项使用类CListBox的成员函数DeleteString,其参数为所删除项的索引值。

    · 注意: 

    · 我们在上面的代码中使用的for循环为 

    · for (int i=m_lsSelected.GetCount()-1; i>-1; i--) 

    · { 

    · ... 

    · } 

    而不是

    · for (int i=0; i<m_lsSelected.GetCount(); i++) 

    · { 

    · ... 

    · } 

    这是因为成员函数DeleteString的使用将导致所删除项之后的所有项的索引值发生改变,这里,如果所删除的项的下一项仍被选定的话,该项将不会被删除。与此相反,删除一项并不会导致此项之前的项的索引值发生改变,因此,从最末一项开始进行检查是可行的。

    按钮IDC_BTNCLEAR的BN_CLICKED命令的处理成员函数OnBtnClear具有最简单的结构,它直接调用类CListBox的成员函数ResetContent删除列表框IDC_LISTSELECTED中的所有项。

    void CListBoxDemoDlg::OnBtnClear() 

    {

    m_lsSelected.ResetContent(); 

    }

    图6. 52 示例程序ListBoxDemo的运行结果

    编译并运行上面的示例程序,其运行结果如图6.52所示。单击“改变目录”按钮,输入一个新的目录名,查看左边列表框中项的改变情况。从左边列表框中选定若干项,单击“添加到”,将所选定的项添加到右边列表框(注意列表框中可以包括相同字符串的项)。再从右边列表框中选定若干项,验证按钮“删除”和“全部清除”是否正常工作。

    第七节 组合框

    组合框(combo box)可以看作是一个编辑框或静态文本框与一个列表框的组合,组合框的名称也正是由此而来。当前选定的项将显示在组合框的编辑框或静态文本框中。如果组合框具有下拉列表(drop-down list)样式,则用户可以在编辑框中键入列表框中某一项的首字母,在列表框可见时,与该首字母相匹配的最近的项将被加亮显示。

    组合框对应于Controls工具箱内的按钮为。在绘制组合框的同时可以使用控件的Properties对话框设置控件的各种属性样式。一些样式已在前面的几节中作了介绍,因此这里不再重复,下面给出一些在前面的内容中没有进行说明的样式及其含义:

    Type:

    指定组合框的类型。可以使用的类型如下:

    Simple:创建包括编辑框控件和列表框的简单组合框,其中编辑框控件用来接受用户的输入。

    Dropdown:创建下拉组合框。该类型与简单组合框类似。但仅当用户单击了编辑框控件部分右边的下拉箭头时组合框的列表框部分才被显示。

    Drop List:该类型类似于下拉样式(drop-down),只是使用静态文本项代替编辑框控件来显示列表框中的当前选择。

    默认值为Dropdown。

    Uppercase:

    将选择域或列表中的所有文本转换为大写。

    类型:布尔值 默认值为假

    Lowercase:

    将选择域或列表中的所有文本转换为小写。

    类型:布尔值 默认值为假

    与列表框不同的是,在绘制组合框的同时可以预先为组合框添加一些可选项,方法是单击Properties对话框中的Data选项卡(如图所示),直接在Enter listbox items处键入组合框中的可选项,每一行为一个选项,使用Ctrl+Enter键开始新的一行。在运行时这些选项将出现在组合框的列表框中。

    图6. 53 为组合框预置选项

    MFC类CComboBox封装了Windows标准组合框,其成员函数提供了对组合框控件的常见操作的实现。表给出了对在类CListBox中定义的成员函数的描述。

    表6. 29 在类CListBox中定义的成员函数

    成员函数

    描述

    CComboBox

    构造一个CComboBox对象

    Create

    创建一个组合框并将它与CComboBox对象相关联

    InitStorage

    为组合框的列表框部分的项和字符串预先分配内存块

    GetCount

    获得组合框中列表框项的数目

    GetCurSel

    如果存在的话,返回组合框中列表框的当前选定项的索引

    SetCurSel

    选择组合框中列表框内的一条字符串

    GetEditSel

    获得组合框中编辑控件的当前选定的起始和终止字符位置

    SetEditSel

    在组合框的编辑控件中选定字符

    SetItemData

    设置与组合框中指定项相关联的32位值

    SetItemDataPtr

    将与组合框中指定项相关联的32位值设置为指定的void指针

    GetItemData

    获得由应用程序提供的与指定组合框项相关联的32位值

    GetItemDataPtr

    以void指针的形式返回由应用程序提供的与指定组合框项相关联的32位值

    GetTopIndex

    返回组合框中列表框部分的第一个可视项的索引

    SetTopIndex

    在组合框中的列表框部分的顶部显示指定索引对应的项

    SetHorizontalExtent

    以象素为单位指定组合框的列表框部分可以横向滚动的宽度

    GetHorizontalExtent

    以象素为单位获得组合框中列表框部分可以横向滚动的宽度

    SetDroppedWidth

    为组合框的下拉列表框部分设置最小允许宽度

    GetDroppedWidth

    获得组合框的下拉列表框部分的最小允许宽度

    Clear

    如果存在的话,删除编辑控件中当前选定的内容

    Copy

    如果存在的话,将当前选定以CF_TEXT格式复制到剪贴板

    Cut

    如果存在的话,删除编辑控件中当前选定的内容,并将其以CF_TEXT格式复制到剪贴板

    Paste

    当剪贴板包括CF_TEXT格式的数据时,从剪贴板复制数据到编辑控件的当前插入位置

    LimitText

    设置用户可以在组合框的编辑控件中输入的文本的长度限制

    SetItemHeight

    设置组合框中列表项的高度或编辑控件(或静态文本控件)部分的高度

    GetItemHeight

    获得组合框中列表项的高度

    GetLBText

    从组合框中的列表框获取字符串

    续表6.29

    成员函数

    描述

    GetLBTextLen

    获得组合框的列表框中某一字符串的长度

    ShowDropDown

    对于具有CBS_DROPDOWN或CBS_DROPDOWNLIST属性的组合框,显示或隐藏其列表框

    GetDroppedControlRect

    获得下拉组合框的可视(下拉)列表框的屏幕坐标

    GetDroppedState

    判断下拉组合框的列表框是否可见(处理下拉状态)

    SetExtendedUI

    对于具有CBS_DROPDOWN或CBS_DROPDOWNLIST样式的组合框,选择默认用户界面或扩展用户界面

    GetExtendedUI

    判断组合框具有默认用户界面还是扩展用户界面

    GetLocale

    获得组合框的区域标识符

    SetLocale

    设置组合框的区域标识符

    AddString

    向组合框的列表框添加一字符串,对于具有CBS_SORT样式的组合框,新增加的字符串将被排序并插入到合适的位置,否则将被添加到列表框框的末尾

    DeleteString

    从组合框的列表框中删除字符串

    InsertString

    向组合框的列表框中插入一字符串

    ResetContent

    清除组合框的列表框和编辑控件中的所有内容

    Dir

    添加文件名列表到组合框的列表框中

    FindString

    在组合框的列表框中查找包括指定前缀的第一个字符串

    FindStringExact

    在组合框的列表框中查找与指定字符串匹配的字符串

    SelectString

    在组合框的列表框中查找字符串,如果找到的话,在列表框中选择该字符串,并将字符串复制到编辑控件中

    DrawItem

    当一个自绘制组合框的可视部分改变时由框架调用

    MeasureItem

    在创建自绘制组合框时,由框架调用以判断组合框的尺寸

    CompareItem

    当将一新项插入到排序的自绘制框中时由框架调用以判断项的相对位置

    DeleteItem

    当一列表项被从自绘制组合框中删除时由框架调用

    下面的示例程序演示了自绘制组合框的使用。

    1. 使用AppWizard创建名为ComboDemo的基于对话框的工程,按图6.54添加工程的主对话框(IDD_COMBODEMO_DIALOG)中的各个控件。每个控件的属性如表6.30所示。

    2. 在ClassView中用鼠标右击ComboDemo classes,选择New Class命令。上面的操作将弹出如图6.55所示的对话框,确认在Class type下拉列表框[注] 中选择了MFC Class。然后在Name处输入新的类名CClrComboBox,在Base class下拉列表框中选择CComboBox。如果需要修改新类的头文件或实现文件的文件名,可以单击Change按钮,这里,我们接受默认的文件名ClrComboBox.cpp和ClrComboBox.h。

    图6. 54 工程ComboDemo的主对话框

    表6. 30 对话框IDD_COMBODEMO_DIALOG的控件属性设置

    控件类型

    ID

    属性值

    组合框

    IDC_CLRCOMBO

    Type:Dropdown

    Owner draw:Fixed

    Sort:真

    Vertical scroll:真

    Has string:假

    下压按钮

    IDC_ADDCLR

    Caption:添加颜色(&A)

    IDC_CHGCLR

    Caption:改变颜色(&C)

    静态控件

    IDC_STATICCLR

    Caption属性值为空

    3. 使用ClassWizard的Message Map选项卡在类CClrComboBox中重载基类的MeasureItem成员函数,其重载版本的代码如下:

    void CClrComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) 

    {

    // 由于组合框具有 CBS_OWNERDRAWFIXED 样式,因此以 0 为参数调用成员函数

    // GetItemHeight 获得每一项的固定高度

    lpMeasureItemStruct->itemHeight=GetItemHeight(0);

    }

    图6. 55 从CComboBox派生新类CClrComboBox

    函数MeasureItem在自绘制样式的组合框创建时由框架调用。该函数将每一项的高度放入MEASUREITEMSTRUCT结构的成员中。如果对话框以CBS_OWNERDRAWVARIABLE样式创建,框架将为列表框中的每一项调用一次该成员函数,否则,该成员函数只被调用一次。

    接着,在CClrComboBox的重载基类的DrawItem成员函数,其代码如下:

    void CClrComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 

    {

    CDC* pDC=CDC::FromHandle(lpDrawItemStruct->hDC);

    COLORREF cr=(COLORREF)lpDrawItemStruct->itemData;

    // 注意到在出错的情况下,GetCurSel 和 GetItemData 返回 CB_ERR,而常量

    // CB_ERR 被定义为 -1,这时不应把它视为一种系统颜色。

    if (cr==CB_ERR)

    cr=GetSysColor(COLOR_WINDOW);

    if (lpDrawItemStruct->itemAction & ODA_DRAWENTIRE)

    {

    // 需要重绘整个项

    // 以该项所对应的颜色填充整个项

    CBrush br(cr);

    pDC->FillRect(&lpDrawItemStruct->rcItem, &br);

    // 反色居中显示该颜色的 RGB 组成

    CString str;

    str.Format("R: %d G: %d B: %d", GetRValue(cr), GetGValue(cr), GetBValue(cr));

    CSize size;

    size=pDC->GetTextExtent(str);

    CRect rect=lpDrawItemStruct->rcItem;

    COLORREF tcr;

    tcr=~cr & 0x00FFFFFF; // 获得背景色的反色,不能简单的使用 ~cr

    pDC->SetTextColor(tcr);

    pDC->SetBkColor(cr);

    pDC->TextOut(rect.left+(rect.Width()-size.cx)/2, 

    rect.top+(rect.Height()-size.cy)/2, str);

    }

    if ((lpDrawItemStruct->itemState & ODS_SELECTED) &&

    (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)))

    {

    // 选中状态由未选中变为选中,其边框被加亮显示

    COLORREF crHilite=~cr & 0x00FFFFFF;

    CBrush br(crHilite);

    pDC->FrameRect(&lpDrawItemStruct->rcItem, &br);

    }

    if (!(lpDrawItemStruct->itemState & ODS_SELECTED) &&

    (lpDrawItemStruct->itemAction & ODA_SELECT))

    {

    // 选中状态由选中变为非选中,清除其边框的加亮显示

    CBrush br(cr);

    pDC->FrameRect(&lpDrawItemStruct->rcItem, &br);

    }

    }

    对于自绘制组合框来说,成员函数DrawItem是需要重载的一个很重要的成员函数。该函数在自绘制组合框的可视部分发生改变时由框架调用。在默认情况下,该成员函数不做任何操作。其参数lpDrawItemStruct所指向的DRAWITEMSTRUCT结构包括了重绘制所需要的各种信息,如所需重绘的项、其设备上下文以及所执行的重绘行为等。在该成员函数终止前,应用程序应该恢复由该DRAWITEMSTRUCT结构所提供的为该显示上下文所选定图形设备接口。

    由表6.30可知在本示例程序中所使用的自绘组合框中的可选项是有序的,而它们都是一些颜色值,框架如何知道当一个新的颜色值被添加到组合框的列表框中时,它应该处于哪个颜色值之前,哪个颜色值之后呢?这时通过调用成员函数CompareItem成员函数来实现的。如果在创建组合框时指定了LBS_SORT样式,则必须重载该成员函数以提供足够的理由来帮助框架对新添加入组合框的列表框中的颜色项进行排序。这里,我们首先根据颜色亮度的大小来对颜色进行排序,对于亮度相同的颜色,我们依次以从蓝色到红色的优先级来判定其相对位置。这个操作是以下面的代码来实现的:

    int CClrComboBox::CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct) 

    {

    // TODO: 添加判断指定项的排序顺序的代码

    // 当项 1 在项 2 之前时返回 -1

    // 当项 1 和项 2 顺序相同时返回 0

    // 当项 1 在项 2 之后时返回 1

    // 获得项 1 和项 2 的颜色值

    COLORREF cr1 = (COLORREF)lpCompareItemStruct->itemData1;

    COLORREF cr2 = (COLORREF)lpCompareItemStruct->itemData2;

    if (cr1 == cr2)

    {

    // 项 1 和项 2 具有相同的颜色

    return 0;

    }

    // 进行亮度比较, 亮度低的排列顺序在前

    int intensity1 = GetRValue(cr1) + GetGValue(cr1) + GetBValue(cr1);

    int intensity2 = GetRValue(cr2) + GetGValue(cr2) + GetBValue(cr2);

    if (intensity1 < intensity2)

    return -1;

    else if (intensity1 > intensity2)

    return 1;

    // 如果亮度相同, 按颜色进行排序, (蓝色最前, 红色最后)

    if (GetBValue(cr1) > GetBValue(cr2))

    return -1;

    else if (GetGValue(cr1) > GetGValue(cr2))

    return -1;

    else if (GetRValue(cr1) > GetRValue(cr2))

    return -1;

    else

    return 1;

    }

    上面的代码同时也说明了CompareItem成员函数的不同返回值所代表的不同含义。这里要注意的是,由于同亮度的不同颜色给人的眼睛的亮度感觉是不一样的(这好比人耳对声音的高频段和低频段的听觉灵敏度要比对中频段的听觉灵敏度要小一样),上面的排序结果给人感觉并不象我们所想象的那样,是通过颜色的亮度来进行的。但我们没有必要在这个问题上过分的纠缠而浪费时间。另外我们解释一下,为什么要使用~cr & 0x00FFFFFF来代替~cr。很多人会认为直接将颜色值按位取反就可以得到其对比色,但事实不是这样的。这是因为如果32位颜色值的高位字节不为零的话,该颜色值将不被当作一个RGB颜色值,而使用某个32位值与0x00FFFFFF按位与恰可以使其高位字节为零,而其它位则不变。

    到目前为止我们完成了自绘制组合框对应的类CClrComboBox的设计,下面我们来看如何在程序中将类CClrComboBox的对象与对话框模板中的现存组合框相关联,这是使用函数SubclassDlgItem来实现的。首先在类CComboDemoDlg中添加一个类型为CClrComboBox的成员变量m_clrCombo,其访问限制在本工程中是不重要的,可以将它设置为protected。然后,在类CComboDemoDlg的OnInitDialog成员函数中的// TODO注释之后添加下面的一行代码,这行代码将对象m_clrCombo与ID为IDC_CLRCOMBO相关联,第一个参数为控件的父窗口的指针。

    m_clrCombo.SubclassDlgItem(IDC_CLRCOMBO, this);

    这样就可以通过CWnd的消息映射机制和消息传递路径在类CClrComboBox中处理IDC_CLRCOMBO中事件了。比如当组合框中的项需要重绘时,在CClrComboBox中定义的DrawItem成员函数将被调用,在正确的绘制组合框中的内容。

    4. 这里,我们在初始时没有为组合框添加任何选择项,用户可以单击如图6.54的对话框中所示的“添加颜色”按钮向组合框的列表框中添加新颜色项。单击该按钮首先将弹出一个颜色选择对话框,用户如果从颜色选择对话框中选择了一种具体的颜色,该颜色将被添加到组合框的列表框中以供选择。基于这个要求,我们为按钮IDC_ADDCLR的BN_CLICKED事件添加如下的命令处理成员函数OnAddClr:

    void CComboDemoDlg::OnAddClr() 

    {

    CColorDialog dlg(0, 0, this);

    int iRes=dlg.DoModal();

    if (iRes==IDOK)

    {

    COLORREF cr=dlg.GetColor();

    m_clrCombo.AddString( (LPCTSTR)cr );

    }

    else

    {

    }

    }

    虽然使用颜色对话框在本书的前面内容中没有讲述过,但即使是对初学者而言,上面的代码也是非常之简单的,我们这里就不过多的作讲解了。

    下面来看如何为“改变颜色”按钮(IDC_CHGCLR)添加单击命令处理成员函数。我们希望用户在单击该按钮时,改变静态文本控件IDC_CLRSTATIC的颜色以反映用户所选择的颜色。如果改变静态文本控件的颜色呢?我们这里使用了将自绘制静态文本控件的办法。这并不是最简单的方法。最简单的方法是处理对话框的WM_CTLCOLOR消息,该消息在控件将要被重绘前发送给该控件的父窗口。这里我们舍近而求远,主要是为了附带讲述一下自绘制静态文本控件的用法,它和自绘制组合框的用法存在一些区别。但是,在资源编辑器中我们不可以设置一个静态文本控件的自绘制样式,不过这并不意味将不可以使用自绘制静态控件。方法并不复杂。首先,为静态文本控件添加自绘制样式,将下面的代码添加到类CComboDemoDlg的OnInitDialog成员函数中的// TODO注释之后:

    GetDlgItem(IDC_CLRSTATIC)->ModifyStyle(0, SS_OWNERDRAW);

    上面的代码将静态文本控件修改为具有SS_OWNERDRAW样式的自绘制静态控件。下面我们来看如何在需要的时候重新绘制静态文本控件IDC_CLRSTATIC,方法是在类CComboDemoDlg中为消息WM_DRAWITEM添加处理函数OnDrawItem,而使用ClassWizard很容易办到这一点。重载版本的OnDrawItem成员函数的定义如下:

    void CComboDemoDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) 

    {

    CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);

    if (nIDCtl==IDC_CLRSTATIC)

    {

    CDC *pDC=CDC::FromHandle(lpDrawItemStruct->hDC);

    CBrush br(m_crClrStatic);

    CRect rc=lpDrawItemStruct->rcItem;

    pDC->FillRect(&rc, &br);

    }

    }

    要使上面的代码正常工作,我们还需要在类CComboDemoDlg中定义类型为COLORREF的成员变量m_crClrStatic,该成员变量保存了静态文本控件应该具有的颜色。我们注意到了在重载版本的OnDrawItem成员变量调用了基类的OnDrawItem成员函数,这是必要的,不要忘记在我们的对话框中还有一个自绘制组合框,基类的OnDrawItem成员函数调用自绘制组合框所对应的CComboBox的派生类的DrawItem成员函数来绘制组合框中的各个项。

    下面来看下压按钮IDC_CHGCLR的BN_CLICKED事件的处理函数OnChgClr,其代码如下:

    void CComboDemoDlg::OnChgClr() 

    {

    int nSel=m_clrCombo.GetCurSel();

    COLORREF cr=(COLORREF)m_clrCombo.GetItemData(nSel);

    if (cr!=-1)

    {

    DRAWITEMSTRUCT drawItemStruct;

    drawItemStruct.CtlID=IDC_CLRSTATIC;

    drawItemStruct.hwndItem=GetDlgItem(IDC_CLRSTATIC)->GetSafeHwnd();

    drawItemStruct.hDC=::GetDC(drawItemStruct.hwndItem);

    GetDlgItem(IDC_CLRSTATIC)->GetClientRect(&(drawItemStruct.rcItem));

    m_crClrStatic=cr;

    OnDrawItem(IDC_CLRSTATIC, &drawItemStruct);

    }

    }

    该成员函数将当前选中的颜色值(如果不为CB_ERR的话)放入成员变量m_crClrStatic中,然后构造一个DRAWITEMSTRUCT结构变量,并对它进行必要的初始化,最后调用该结构对象调用OnDrawItem成员函数重绘对话框。以后在需要重绘时,OnDrawItem成员函数会由框架自动调用。

    这时即可编辑并运行上面的示例程序了,其运行结果如图6.56所示。单击“添加颜色”向组合框的列表框中添加几种颜色选项,再来调试程序的各项功能是否正常。还可以不同的窗口之前进行切换和相互覆盖或移开,以观察自绘制组合框和自绘制静态文本控件是否正确的绘制了自身。

    图6. 56 示例程序ComboDemo的运行结果

    相比较标准的组合框而言,自绘制组合框要复杂得多,我们得自己考虑很多特殊的问题,但是如示例程序所示,它的确可以实现一些很有趣的特性,因此在很多程序中得到广泛的使用。而掌握了自绘制控件的使用,就可以使你所编写的应用程序界面更加的缤纷多彩,但是,要注意一切事物的使用都有一个“度”,不适宜的将应用程序的用户界面做得过分的“花哩呼哨”,很多时候只会适得其反。

    第八节 滚动条控件

    滚动条(如图6.57所示)本身也可以作为一种控件,通常我们使用这种控件来进行如定位之类的操作。滚动条控件分为水平滚动条和垂直滚动条两种,它们对应于Controls工具箱中的图标分别为和。

    图6. 57 滚动条控件

    对于滚动条控件,可以在Properties对话框的Styles选项卡内设置的属性只有一种:即Align属性,该属性可以为三种值之一:None、Top/Left和Bottom/Right。其中,Top/Left表示将滚动条控件的左上边与由CreateWindowEx函数的参数定义的矩形的左上边对齐,而Botton/Right则表示以右下边进行对齐。该属性的默认值为None,即不进行任何对齐操作。

    Windows标准滚动条的行为由MFC类CScrollBar封装。表中列出了在类CScrollBar中定义的成员函数及其说明。

    表6. 31 在类CScrollBar中定义的成员函数

    成员函数

    描述

    CScrollBar

    构造一个CScrollBar对象

    Create

    创建一个Windows滚动条,并将它与CScrollBar对象相关联

    GetScrollPos

    获得滚动条的当前位置

    SetScrollPos

    设置滚动条的当前位置

    GetScrollRange

    获得给定滚动条的当前最大和最小位置

    SetScrollRange

    设置给定滚动条的当前最大和最小位置

    ShowScrollBar

    显示或隐藏滚动条

    EnableScrollBar

    允许或禁止滚动条上的一个或两个箭头

    SetScrollInfo

    设置关于滚动条的信息

    GetScrollInfo

    获得滚动条的信息

    GetScrollLimit

    获得滚动条的限制

    当用户单击了滚动条时,父窗口将收到WM_HSCROLL或WM_VSCROLL消息,在CWnd类的定义了处理该消息的成员函数为OnHScroll和OnVScroll。成员函数OnHScroll的原型如下:

    afx_msg void OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar );

    第一个参数nSBCode指定如下之一的滚动条代码,这些代码代表用户所作的滚动请求:

    SB_LEFT:

    向左滚动较远距离

    SB_ENDSCROLL:

    结束滚动

    SB_LINELEFT:

    向左滚动

    SB_LINERIGHT:

    向右滚动

    SB_PAGELEFT:

    向左滚动一页

    SB_PAGERIGHT:

    向右滚动一页

    SB_RIGHT:

    向右滚动较远距离

    SB_THUMBPOSITION:

    滚动到绝对位置。当前位置由nPos参数指定

    SB_THUMBTRACK:

    拖动滚动条到指定的位置。当前位置由nPos参数指定

    通常,SB_THUMBTRACK滚动条代码由应用程序使用,以便在滚动条被拖动时给以反馈。如果应用程序滚动了由滚动条控制的内容,它必须使用SetScrollPos来重置滚动条的位置。

    传递给函数OnHScroll的参数反映了当收到消息时由框架获得的值,如果在重载版本的函数中调用了基类的实现,该实现将使用最初由消息传递的参数,而不是向函数提供的参数。

    消息WM_VSCROLL的处理函数OnVScroll与OnHScroll类似,我们这里就不再重复讲述了。下面我们来看一个例子:

    1. 创建一个名为ScrollDemo的基于对话框的MFC工程,按图设置对话框的各控件。其中水平滚动条控件的ID为IDC_SCROLL,编辑框控件的ID为IDC_CURPOS。

    图6. 58 示例程序ScrollDemo的主对话框的设计

    2. 使用ClassWizard为编辑框控件IDC_CURPOS映射类型为int的成员变量m_iCurPos,并设置其最大值为100,最小值为-100。

    3. 使用ClassWizard在类CScrollDemoDlg中为消息WM_HSCROLL添加处理函数OnHScroll,其代码如下:

    void CScrollDemoDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 

    {

    // 获得原有的滚动条位置

    int iPos=pScrollBar->GetScrollPos();

    // 根据不同的拖动方式设置新的滚动条位置

    switch (nSBCode)

    {

    // 向右滚动一行

    case SB_LINERIGHT:

    iPos+=1;

    break;

    // 向左滚动一行

    case SB_LINELEFT:

    iPos-=1;

    break;

    // 向右滚动一页

    case SB_PAGERIGHT:

    iPos+=10;

    break;

    // 向左滚动一页

    case SB_PAGELEFT:

    iPos-=10;

    break;

    // 直接拖动滚动块

    case SB_THUMBTRACK:

    iPos=nPos;

    break;

    default:

    break;

    }

    // 滚动条的最大位置不超过 100, 最小位置不小于 -100

    if (iPos<-100) iPos=-100;

    if (iPos>100) iPos=100;

    // 必须手动的更新滚动条的当前位置

    pScrollBar->SetScrollPos(iPos);

    // 在编辑框中显示滚动条的当前位置

    SetDlgItemInt(IDC_CURPOS, iPos);

    CDialog::OnHScroll(nSBCode, nPos, pScrollBar);

    }

    上面的代码暗示了一点,这就是在被拖动时,滚动条不会自动更新其位置,我们必须自己在程序中做到这一点,即通过分析不同的滚动方式来改变并设置新的滚动条位置,上面的代码演示了这一过程。

    编译上面的程序代码,我们发现滚动条不能正常工作!这是因为在默认情况下,滚动条的滚动范围为从0到0。这时,我们根本不可能对滚动条进行有意义的操作。因此,我们需要将下面的代码添加到OnInitDialog成员函数:

    CScrollBar *pScroll=(CScrollBar*)GetDlgItem(IDC_SCROLL);

    pScroll->SetScrollRange(-100, 100);

    pScroll->SetScrollPos(0);

    SetDlgItemInt(IDC_CURPOS, 0);

    上面的代码设定了滚动条的滚动范围和默认的滚动条位置,然后,将当前滚动条位置显示在编辑控件IDC_CURPOS中。

    4. 最后我们来实现一个功能,这就是我们希望当编辑控件中的文本发生改变时,滚动条上的滑块的位置也相应的变化。要实现这一点,使用ClassWizard为控件IDC_CURPOS的通知消息EN_CHANGE添加消息处理函数OnChangeCurPos。

    void CScrollDemoDlg::OnChangeCurPos() 

    {

    CString str;

    GetDlgItemText(IDC_CURPOS, str);

    str.TrimLeft();

    str.TrimRight();

    int iPos=0;

    if (str!="-" && str!="")

    {

    if (!UpdateData())

    {

    return;

    }

    iPos=m_iCurPos;

    }

    CScrollBar *pScroll=(CScrollBar*)GetDlgItem(IDC_SCROLL);

    pScroll->SetScrollPos(iPos);

    }

    由于需要检验用户输入数据的有效性,上面的代码比较长。首先,如果用户只输入一个负号“?”或刚将原有的数据删除,此时不应该报错。这里我们可以将滚动条的位置设置为0。由于用户可能在所输入的数据之前或之后插入一些空格,这种情况下我们也不应该报错,因此,我们使用了一些额外的代码来避免了这种情况。最后,我们使用了UpdateData函数来使用控件IDC_CURPOS的值更新成员变量m_iCurPos,这样的目的是便于使用MFC提供的对话框数据检验机制。但有个不好的地方是,如果用户输入的数据有错,出现的报错消息是英文的。如果我们需要的是一个完全中文化的软件,这不能不算是一个瑕疵,这时,我们应该编写自己的数据检验代码。但是在本示例程序中,并不需要这样要求,这里使用MFC的对话框数据检验机制是很有效的。回到程序代码中去,如果用户在编辑控件中输入的值有效的话,使用这个值去更新滚动条的当前位置,这是通过类CScrollBar的成员函数SetScrollPos来实现的。

    其它的一些控件,如CSliderCtrl类所封装的滑块控件等,与滚动条控件的使用有很大的共通之处,读者完全可以根据本章中所讲述的内容通过举一反三来用于其它的场合。

    · 注意: 

    · 由于篇幅有限,在本章中我们不打算介绍更多的Windows控件。事实上,Windows控件的使用的有规律可寻的。只需要弄清楚几种控件的用法,以及MFC在处理控件时的机制,就很容易借助Visual C++所提供的丰富的联机文档来学习其它控件的使用。本章中所介绍的控件,还只是所有控件中很小的一个部分,而且,即使是对所介绍的几种控件的讲述也不是面面俱到的。我们的目的不再于详尽的罗列各种控件的使用方法,而在于起到一种“抛砖引玉”的作用。 

    展开全文
  • windows常用控件

    千次阅读 2018-04-06 17:01:25
    控件的分类和作用:控件分类作用文本类控件可以在控件上显示文本选择类控件主要为客户提供选择的项目分组控件可以将窗体中的控件进行分组处理菜单控件为系统制作功能菜单,将应用程序命令分组,使他们更容易进行查询...
    控件的分类和作用:
    控件分类
    作用
    文本类控件
    可以在控件上显示文本
    选择类控件
    主要为客户提供选择的项目
    分组控件
    可以将窗体中的控件进行分组处理
    菜单控件
    为系统制作功能菜单,将应用程序命令分组,使他们更容易进行查询
    工具栏控件
    提供了主菜单中常用的相关工具
    状态栏控件
    用于显示窗体上的对象的相关信息,或者可以显示应用程序的相关信息
    锁定控件:单击Locked属性并选择true,还可以右击控件,选择“锁定控件”命令,如果要锁定所有控件,则:“格式/锁定控件”。
    文本类控件
    (Label标签,Button按钮,TextBox文本框控件,RichTextBox有格式文本控件)
    设置可见性:Label1.Visible=true;
    将按钮设置为窗体”接受“按钮,就是按下回车键就相当于单击该按钮
    private void Form1_Load(object sender,EventArgs e)
    {
    this.AcceptButton=button1;
    }
    将按钮设置为窗体”取消“按钮,就是按下ESC键就相当于单击该按钮
    private void Form1_Load(object sender,EventArgs e)
    {
    this.CancelButton=button1;
    }
    创建为只读框:
    private void Form1_Load(object sender,EventArgs e)
    {
    TextBox1.ReadOnlyRead=true;
    }
    创建密码文本框:
    private void Form1_Load(object sender,EventArgs e)
    {
    TextBox1.PasswordChar='@';
    TextBox1.UseSystemPasswordChar=true;
    }

    突出显示文本框的文本:
    private void Form1_Load(object sender,EventArgs e)
    {
    textBox1.Multiline=true;
    textBox1.Text="春眠不觉晓,处处闻啼鸟,夜来风雨声,花落知多少";
    textBox1.Height=100;
    textBox1.SelectionStart = 5;//选中文本开始位置
    textBox1.SelectionLength = 5;//选中文本长度
    textBox1.Focus();
    }
    响应文本框的文本更改事件:
    private void textBox1_TextChanged(object sender, EventArgs e)
    {
    label1.Location = new Point(5, 5);
    label1.Text = textBox1.Text;
    }
    有格式文本控件RichTextBox:
    RichTextBox用于显示输入操作带有格式的文本。RichTextBox除了可以显示textBox的全部格式,还可以显示字体,颜色和链接,从文件加载文本和嵌入的图像,撤销和重复编辑操作以及查找指定的字符。
    1.用RichTextBox显示滚动条
    通过设置RichTextBox控件的multiline属性,可以控制控件是否显示滚动条,multiline设置为true,则显示滚动条,设为false则不显示滚动条。下面是multiline属性的属性值及说明。
    属性值
    说明
    Both
    只有文本长度超过文本框的长度时,显示两条滚动条
    None
    从不显示任何滚动条
    Horizontal
    只有当文本长度超过文本框宽度的时候,显示水平文本框。WordWrap为false时才会出现这种情况
    Vertical
    只有当文本高度超过文本框高度时才会显示垂直滚动条
    ForceHorizontal
    WordWrap为false时,显示水平滚动条,文本未超过长度,滚动条为灰色
    ForceVertical
    始终显示垂直滚动条
    ForceBoth
    始终显示垂直滚动条,WordWrap为false时,显示水平的,如果未超过长度,则灰色

    wordwrap指多行文本框控件在必要的时候是否自动换行到下一行的开始。为true时,无论ScrollBars属性是什么,也永远不会显示水平滚动条。
    实现代码:
    private void Form2_Load(object sender, EventArgs e)
    {
    richTextBox1.Multiline = true;
    richTextBox1.ScrollBars = RichTextBoxScrollBars.Both;

    }

    RichTextBox控件中设置字体属性:

    private void Form2_Load(object sender, EventArgs e)
    {
    richTextBox1.Multiline = true;
    richTextBox1.ScrollBars = RichTextBoxScrollBars.Both;

    }
    RichTextBox控件中设置超链接:
    private void richTextBox1_LinkClicked(object sender, LinkClickedEventArgs e)
    {
    System.Diagnostics.Process.Start(e.LinkText);//设置超链接
    }
    RichTextBox控件中设置段落格式:
    可以通过SelectionBullet属性将选定的段落设置为项目符号列表的格式。也可以用SelectionIndent和SelectionHangingIndent属性设置段落相对于控件的左右边缘进行缩进。
    具体实现:
    richTextBox1.SelectionBullet = true;
    设置控件中数据左边缘和右边缘为8:
    richTextBox1.SelectionHangingIndent = 8;
    richTextBox1.SelectionIndent = 8;
    选择类控件:
    (ComBox下拉框控件,CheckBox复选框控件,RadioButton单选按钮控件,NumericUpDown数值选择控件,ListBox列表控件)

    ComBox下拉框控件,用于在下拉组合框中显示数据,由两部分组成:第一部分,允许用户输入列表项的文本框;第二部分,一个列表框,显示一个选项列表,用户可以从中选择一项。
    1创建只可以选择的下拉框
    通过设置DropDownStyle属性,将ComBox控件设置为可以选择的下拉框。DropDownStyle属性有3个属性,这3个属性对应不同的样式。
    Simple:使ComBox控件的列表部分总是可见的
    DropDown:DropDownStyle属性的默认值。使用户可以编辑ComBox控件的文本框部分,只有单击右侧的箭头才能显示列表部分。
    DropDownList:用户不能编辑ComBox控件的文本框部分。呈现下拉框的样式。
    将控件的DropDownStyle属性设置为DropDownList,用户就只能是进行下拉的操作,不能编辑文本内容框内容部分的内容。
    private void Form4_Load(object sender, EventArgs e)
    {
    comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
    comboBox1.Items.Add("陈亚乔");
    comboBox1.Items.Add("李璇");
    comboBox1.Items.Add("在一起");
    }
    2.选中下拉组合框中可编辑的所有文本
    实现方法:public void SelectAll();
    使用前将DropDownStyle属性设置为DropDown.才能进行此操作。
    3.响应下拉组合框的选项值更改事件
    其实就是在comboBox1_SelectedIndexChanged方法中写要响应的事件。
    CheckBox复选框控件
    1.判断复选框是否被选中
    通过在控件的Click事件中判断控件的CheckState属性,来判断复选框是否被选中。CheckStatus属性有两个值Checked和Unchecked。
    private void checkBox1_Click(object sender, EventArgs e)
    {
    if(checkBox1.CheckState==CheckState.Checked)
    {
    MessageBox.Show("CheckBox控件被选中");
    }
    else
    {
    MessageBox.Show("CheckBox控件选择被取消。");
    }
    }
    2.当控件状态发生改变,触发checkBox1_CheckStateChanged事件。
    private void checkBox1_CheckStateChanged(object sender, EventArgs e)
    {
    MessageBox.Show("控件状态发生改变");
    }
    RadioButton单选按钮控件
    1.判断单选按钮是否选中
    通过在控件中的Click事件中判断控件的Checked属性的返回值是否为true。
    private void radioButton1_Click(object sender, EventArgs e)
    {
    if(radioButton1.Checked==true)
    {
    MessageBox.Show("RadioButton1控件被选中");
    }
    }

    private void radioButton2_Click(object sender, EventArgs e)
    {
    if(radioButton2.AutoCheck==true)
    {
    MessageBox.Show("RadioButton2控件被选中");
    }
    }
    2.相应单选按钮选中状态更改事件
    当控件的选中状态发生更改时,会引发控件的CheckChangeed事件。
    private void radioButton_1CheckChanged(object sender,EventArgs e)
    {
    MessageBox.Show("RadioButton1控件的选中状态发生更改。")
    }
    private void button1_Click(object sender,EventArgs e)
    {
    radioButton1.Checked=true;
    }
    private void button2_Click(object sender,EventArgs e)
    {
    radioButton1.Checked=false;
    }
    private void From_Load(object sender,EventArgs e)
    {
    radioButton1.Checked=false;
    }
    MumericUpDown数值选择控件
    MunericUpDown控件是一个显示和输入数值的控件,该控件具有一对向上和向下的箭头,点上下和输入都可以修改其中的数值,该控件有Maximum和Mininum两个属性,分别设置最大和最小值。如果输入的数值超过其最大和最小值。就会一直保持该数值。
    1获取MunericUpDown控件中显示的值
    private void Form1_Load(object sender,EventArgs e)
    {
    numericUpDown1.Maximum=20;
    numericUpDown1.Minimum=1;
    }
    provate void numericUpDown1_ValueChanged(object sender,EventArgs e)
    {
    label.Text="当前控件中的值是:"+numericUpDown1.Value;
    }
    2设置NumericUpDown控件中数值的显示方式
    NumericUpDown控件的DecimalPlaces属性用于确定在小数点后显示几位数。默认为0,ThousandsSeparator属性用于确定是否每3个十进制数字位就插入一个分隔符,默认为false。如果将ThousandsSeparator属性设置为true,则该控件可以用十六位进制显示值,默认设置位false。
    设置方法:numericUpDown1.DecimalPlces=2;

    ListBox列表控件
    1在list控件中添加和移除项
    分别对应LsitBox控件的Item属性的Add和Remove方法。可以添加或者移除ListBox控件中的项目。
    private void button1_Click(object sender,EventArgs e)
    {
    if(textBox1.Text=="")
    {
    MessageBox.Show("输入要添加的数据");
    }
    else
    {
    listBox1.item.add(textbox1.text);
    textbox1.Text="";
    }
    }
    private void button2_Click(object sender,EventArgs e)
    {
    if(listBox1.SelectedItems.Count==0)
    {
    MessageBox.Show("输入要删除的数据");
    }
    else
    {
    listBox.Items.Remove(listBox1.SelectedItem);
    }

    2创建总显示滚动条的列表控件
    通过设置控件的HorizontalScrolBar属性和ScrollAlwaysVisible属性可以使控件总显示滚动条。如果将HorizontalScrolBar属性设置为true则显示水平,如果将ScrollAlwaysVisible属性设置为true则显示垂直。
    设置方法:listBox1.ScrollAlwaysVisible=true;
    。。。
    listBox控件中可以使用MultiColumn属性指示该控件是否支持显示多列。
    3在listBox控件中选择多列
    在listBox控件中的SelectionMode属性可以实现。
    设置方法:
    listBox1.SelectionMode=SelectionMode.(上面的枚举成员);
    显示选择项目的数量:
    listBox1.SelectedItems.Count.Tostring();
    分组类控件
    分组类控件主要包括:Panel容器控件、GroupBox分组框控件、TabControl选项卡控件。
    Panel容器控件
    使用Panel控件的show方法可以显示控件。
    public void Show()
    GroupBox分组框控件
    GroupBox控件主要为其他控件提供分组。按照窗体的分组来细分窗体的功能。其在所包含的控件集周围总是显示边框,并且可以显示标题。GroupBox没有滚动条。
    语法:public override string Text{get;set;}
    TabControl选项卡控件
    TabControl控件可以添加多个选项卡,然后在选项卡上添加子控件。这样就可以把窗体设计成多页,选项卡控件还可以用于创建用于设置一组相关属性的属性页。
    TabControl控件包含选项卡页,TabPage控件表示选项卡,TabControl控件的TabPages属性表示其中的所有TabPage控件的集合,TabPages集合中的TabPage选项卡的顺序反映了TabControl控件中的选项卡的设置。
    1改变选项卡的显式样式
    举例:创建一个windows应用程序,向窗体中添加一个ImageLsit控件,然后将图像添加到ImageList控件的图像列表中,将TabControl控件的ImageList属性设置为ImageList控件,将TabPage的ImageIndex属性设置为列表中相应的图像的索引。
    private void Form1_Load(object sender,EventArgs e)
    {
    tabControl1.ImageList=imageList1;
    //设置控件的ImageLsit属性为ImageList1
    tabPage1.ImageIndex=0;
    tabPage1.Text=“选项卡1”;
    tabPage2.ImageIndex=1;
    tabPage2.Text=“选项卡2”;
    }
    备注:为了使用户更加了解选项卡的作用,可以在鼠标移入选项卡时,弹出一个提示信息,对当前选项卡的作用或者操作步骤有一个描述的相关说明,设置步骤为:将tabPage属性中的ShowToolTips属性设置为true,然后在tabPage属性的ToolTipText属性输入相关描述信息。
    将选项卡设置为按钮
    tabControl控件的Appearance属性设置为Buttons或FlatButtons,即可将选项卡设置位按钮样式。如果设置位Buttons,则有三维按钮外观,如果设置为FlatButtons,则具有平面按钮外观。
    设置方法:tabControl1.Apprearance=TabApprearance.Buttons;
    2在选项卡中添加控件
    如果要在选项卡中添加控件,可以通过TabPage的Control属性的Add方法进行实现。
    private void Form1_Load(object sender,EventArgs e)
    {
    tabControl1.ImageList=ImageList1;
    tabPage1.ImageIndex=0;
    tabPage2.ImageIndex=1;
    Button btn1=new Button();
    btn1.Text="新增的按钮";
    tabPage1.Controls.Add(btn1);
    }
    3添加和移除选项卡
    在默认情况下,TabControl控件包含两个TabPage控件,可以使用TabPages属性的Add方法添加新的选项卡。
    实现方法:
    string Title="新增选项卡"+(tabControl.TabCount+1).ToString();
    //声明一个字符串变量,用于生成新增选项卡的名称
    TabPage myTab=new TabPage(Title);
    tabControl.TabPages.Add(myTab);
    可以使用TabPages属性的Remove方法进行移除控件中的选项卡。
    实现方法:
    if(tabControl1.SelectedIndex==0)
    {
    MessageBox.Show("请选择需要删除的选项卡");
    }
    else
    {
    tabControl1.TabPages.Remove(tabControl1.SelectedTab);
    }
    删除控件中的所有选项卡:
    实现方法:tabControl1.TabPages.Clear();

    菜单、工具栏和状态控件

    菜单是窗体应用程序主要的用户要素,工具栏为应用程序提供了操作系统的界面,状态栏显示系统的一些状态信息。
    MenuStrip菜单控件
    MenuStrip控件支持多文档界面、菜单合并,工具提示和溢出,可以通过添加访问键、快捷键、选中标记、图像和分隔条,来增强菜单的可用性和可读性。
    (输入名称&F就会变成F,然后可以使用ALT+F打开)
    ToolStrip工具栏控件
    可以创建具有windows XP、Office、Internet Explorer或自定义的外观和行为的工具栏及其他用户界面元素。这些元素支持溢出以及运行时重新排序。
    StatusStrip状态栏控件
    StatusStrip控件通常处于窗体最底部,用于显示窗体上对象的相关信息,或者显示应用程序的信息。通常,StatusStrip控件由ToolStripStatusLabel对象组成,每个这样的对象都可以显示文本、图标或者同时显示这两者。StatusStrip还可以包括ToolStripDropDownButton、ToolStripSplitButton和ToolStripProgressBar控件。
    举例:创建一个windows应用程序,使用StatusStrip控件制作状态栏,在状态栏中显示当前日期。以及ToolStripProgressBar控件,单击”加载“,加载进度条。
    private void Form1_Load(object sender,EventArgs e)
    {
    //在任务栏显示系统当前日期
    this.toolStripStatusLabel2.Text=DateTime.Now.ToShortDateString();
    }
    private void button1_Click(object sender,EventArgs e)
    {
    this.toolStripProgressBar1.Minmum=0;//进度条最小值
    this.toolStripProgressBar1.Maxmum=5000;
    this.toolStripProgressBar1.Step=2;//进度条增值
    for(int i=0;i<=4999;i++)
    {
    this.toolStripProgressBar1.PerformStep();
    //按照Step属性增加进度条当前位置
    }
    }


    展开全文
  • 使用 Windows 标准控件 为了提高常用代码的复用性,VC 使用控件将常用的诸如用户输入、操作数据等功能封装起来。控件通常放在对话框或工具栏中,分为 3 种:Windows 标准控件、ActiveX 控件和 MFC 支持的其他控件...

    使用 Windows 标准控件


    • 为了提高常用代码的复用性,VC 使用控件将常用的诸如用户输入、操作数据等功能封装起来。控件通常放在对话框或工具栏中,分为 3 种:Windows 标准控件、ActiveX 控件和 MFC 支持的其他控件类。

    一、Windows 标准控件

    1、常用 Windows 控件

    控件 MFC 类 说明
    按钮控件 CButton 按钮控件,可以产生单击事件;也可以扩展为复选框、单选框按钮分组框
    组合框 CComboBox 编辑框和列表框的组合
    日期时间选择框 CDateTimeCtrl 可以选择日期或时间值
    编辑控件 CEdit 文本输入框
    扩展组合框 CComboBoxEx 可以显示图片的组合框
    标题控件 CHeaderCtrl 列头按钮,用于控制文本的显示
    热键控件 CHotKeyCtrl 用户热键控件
    图像列表 CImageList 图像列表,用于管理一组图标或位图
    列表视图控件 CListCtrl 显示带有图标的文本列表
    列表控件 CListBox 显示带有字符串列表的控件
    月历 CMonthCalCtrl 显示日期信息的控件
    进度条控件 CProgressCtrl 指示操作过程进度的控件
    控件工具栏 CRebarCtrl 包含子控件的工具栏
    扩展编辑框 CRichEditCtrl 带有段落和字符格式的编辑框
    滚动条 CScrollBar 对话框中用于滚动查看的滚动条
    滑块控件 CSliderCtrl 用于定位选项位置的滑块控件
    微调按钮 CSpinButtonCtrl 用于定量增加或定量减少的微调按钮
    静态控件 CStatic 用于标记其他控件的文本控件
    状态栏控件 CStatusBarCtrl 显示状态信息的状态栏
    工具栏 CToolBarCtrl 包含命令按钮的工具栏
    工具提示 CToolTipCtrl 小的弹出对话框,用于描述工具栏按钮或其他工具功能的控件
    树形图控件 CTreeCtrl 显示树形列表项的属性视图控件

    2、使用对话框编辑器创建控件

    • a、使用 new 关键字在堆上创建控件对象,使用此种方式创建控件,需要在退出程序时,调用 delete 关键字销毁对象。

    • b、在对话框编辑器中创建控件对象,此种方式直观,所见即所得,并且在程序退出时系统会自动销毁 Windows 控件。具体步骤:

      (1)打开对话框资源编辑器

      (2)展开“工具箱”,单击要添加的控件,将鼠标移到对话框主窗体,单击鼠标添加控件;或是按下需要添加的控件,移动鼠标到对话框主窗体的合适位置,松开鼠标添加控件。

      (3)单击要设置大小的控件,将鼠标移动到控制点进行拖动,直到控件大小符合需要。

      (4)右击已经添加的控件,单击“属性”命令,弹出属性对话框,在 ID 组合框中指定控件 ID,在Caption 文本框中指定控件显示的文本。

      (5)重复(2)~(4)步,依次添加所需的控件。例:添加月历控件:

    月历控件.PNG

    3、控件基类 CWnd

    • CWnd 类是 MFC 中所有窗体类包括控件类的基类。

    • CWnd 对象由构造函数和析构函数创建和销毁。

    • Windows 对话框是 Windows 内部数据结构,由 Create() 成员函数创建并由 CWnd 的析构函数销毁。

    • CWnd 类和消息映射机制隐藏在 WndProctor() 函数中,当 Windows 通知消息到来时,会自动路由到相应的 CWnd 的 OnMessage() 函数中。

    • CWnd 类可以继承,创建派生自 CWnd 的子控件分为两步:

      (1)调用 CWnd 的构造函数构造 CWnd 对象。

      (2)调用 Create() 成员函数创建子对话框,并将其附加到 CWnd 对象中。

    4、控件的消息以及处理

    • a、代码形式

      • 要处理控件消息,则在父对话框中为每条消息条目增加以下代码:

        ON_Notification(id,memberFunction)   //消息映射
         
        //此处 id 表示发送消息的控件 ID,memberFunction 是父类中处理此消息的成员函数,父类中的控件消息的处理函数如下:
        afx_msg void memberFunction();
        
      • 具体例子:

        afx_msg void OnClickedButtonTest();
        
        BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
        	ON_BN_CLICKED(IDC_BUTTON_TEST, &CAboutDlg::OnClickedButtonTest)
        END_MESSAGE_MAP()
            
        void CAboutDlg::OnClickedButtonTest()
        {
        	// TODO: 在此添加控件通知处理程序代码
        	MessageBox(L"单击了按钮", L"提示");
        }
        

    控件消息处理测试.PNG

    • b、使用可视化操作:

      (1)在对话框资源编辑器中,右键正在编辑的对话框,在弹出的菜单中选择类向导。

      (2)在对象 ID 列表框中选择要处理发送消息的控件 ID;在消息列表框中选择要处理的消息;然后单击添加处理程序或删除处理程序。

      (3)单击编辑代码按钮跳转到代码编辑器,编辑消息处理函数中的代码。

      (4)单击确定按钮退出类向导对话框。

    5、创建控件对象

    • 在程序代码中要操作控件,需要使用控件对应的控件对象进行操作。创建控件对象的步骤:

      1)在 MFC 类向导对话框中,选择成员变量选项卡。

    控件成员变量.PNG

    2)选择要增加变量的,单击添加变量按钮,打开添加变量的对话框:

    添加控件变量.PNG

    3)在添加变量对话框中的填上成员变量名以及必要的注释信息。

    4)若要删除控件变量,则在类向导对话框的成员变量选项卡中选定要删除变量的控件,然后单击删除变量按钮。

    6、按钮

    • 在 Windows 程序中最常见的操作是单击某个对象触发一组操作,实现此功能的控件称为按钮控件。

    6.1、按钮简介

    • 按钮控件是一个只有按下和抬起两种状态的小的窗口,按钮控件分为复选框、单选按钮和命令按钮。

    6.2、按钮类 CButton

    • VC 中使用 CButton 类对象表示按钮控件,继承自对话框类 CWnd;CButton 类的派生类 CBitmapButton 类支持图像按钮控件,其提供了一组独立的位图分别表示按钮按下、按钮抬起、按钮选中和按钮不可用 4 种状态。

    6.3、按钮的属性与消息

    • 按钮控件没有特殊的属性,常用的消息主要有:
    • ON_BN_CLICKED 消息:当用户单击按钮时,发送给父窗体此消息。
    • ON_BN_DOUBLECLICKED 消息:当用户双击按钮时,给父窗体发送此消息。

    6.5、设定和获取按钮状态

    • 对于单选按钮和复选框,有选择和未选择两个按钮状态;对于单选按钮,用黑色圆圈表示选择;对于复选框,在方框中有个对勾表示选择。按钮控件状态可通过 CButton 的 4 个函数使用。

      1)GetState()函数:获取按钮控件的当前状态,函数返回值的意义:0-表示按钮没有选择,1-按钮被选择,2-中间状态,4-当前按钮被用户按下并高亮显示,8-按钮获得输入焦点。

      2)SetState()函数:设置按钮控件是否高亮显示。

      3)Getcheck()函数:返回按钮控件的当前状态。返回值:0-没有选择按钮控件,1-选择了按钮控件,2-中间状态。

      4)SetCheck()函数:设置按钮控件的当前状态。返回值:0-没有选择按钮控件,1-选择了按钮控件,2-中间状态。

    二、静态控件和编辑控件

    • 静态控件是常用的信息提示控件,编辑控件是常用的用户输入控件。

    1、创建与使用静态控件

    • 创建静态控件的方法见“使用对话框编辑器创建控件”。

    1.1、静态控件类 CStatic

    • CStatic 类提供 Windows 静态控件的功能。静态控件显示文本字符串、矩形、图标、光标、位图或增强型图元文件。可用作标记、分组或分隔其他控件。通常情况下,静态控件不接收输入也不提供输出。但是如果使用 SS_NOTIFY,则可以通知父窗口鼠标单击事件,在静态控件的属性对话框将 Notify 选项设置为 True。

    • 常用静态类成员函数:

      成员函数 功能
      SetBitmap() 指定在静态控件上显示的位图
      GetBitmap() 获取在静态控件上显示的位图的句柄
      SetIcon() 指定在静态控件上显示的图标
      GetIcon() 获取在静态控件显示的图标的句柄
      SetCursor() 指定在静态控件上显示的光标
      GetCursor() 获取在静态控件显示的光标的句柄
      SetEnhMetaFile() 指定在静态控件上显示的增强型元文件
      GetEntMetaFile() 获取在静态控件显示的增强型元文件的句柄

    2、创建编辑控件

    • 编辑控件是一个用于输入文本文件的长方形子对话框,可以提供用户与程序之间的数据交互。其创建方法与 Windows 控件的创建方法相同。

    2.1、编辑控件类 CEdit

    • CEdit 类提供对话框编辑控件功能。CEdit 类常用成员函数。

      成员函数 功能
      CanUndo() 确定编辑控件是否可以撤销
      GetLineCount() 获取多行编辑器中当前的行数
      GetModify() 确定编辑控件中的内容是否被修改过
      SetModify() 设置或清除编辑控件修改标记
      GetRect() 获取编辑控件的矩形框
      GetSel() 获取编辑控件中当前选择的内容
      GetHandle() 获取多行控件分配的内存句柄
      SetHandle() 设置多行控件使用的本地内存的句柄
      SetMargins() 设置 CEdit 类的左边和右边边白
      GetMargins() 获取 CEdit 类的左边和右边边白
      SetLimitText() 设置 CEdit 类中可以存放的最大文本数。
      GetLimitText() 获取 CEdit 类中可以存放的最大文本数
      GetLine() 获取编辑控件指定行 的内容
      GetPasswordChar() 获取当编辑控件作为密码控件时,显示的字符
      ReplaceSel() 使用指定文本替换当前编辑控件选中的内容
      SetPasswordChar() 设置当编辑控件作为密码控件时,显示的字符
      SetSel() 选在编辑控件中的指定范围
      SetReadOnly() 设置编辑控件为只读控件
      Undo() 撤销最后一次操作
      Clear() 删除编辑控件中当前选中的内容
      Copy() 将当前选择的编辑控件中的内容复制到剪贴板
      Cut() 将当前选择的编辑控件中内容剪切到剪切板
      Paste() 粘贴当前剪贴板中的内容到编辑控件中

    3.编辑控件的消息

    • 常用的编辑控件消息有以下几个:

      1)ON_EN_CHANGE 消息:当用户修改编辑控件中的内容时,发送此消息。EN_UPDATE 通知消息则是当对话框更新时才发送此通知消息。

      2)ON_EN_ERRSPACE 消息:当控件不能分配足够的内存处理特殊请求时发送此消息。

      3)ON_EN_HSCROLL 消息:当用户单击编辑控件的水平滚动条时,在屏幕更新前,编辑控件向父对话框发送此消息。

      4)ON_EN_KILLFOCUS 消息:当编辑控件失去输入焦点时发送此消息。

      5)ON_EN_MAXTEXT 消息:当前输入框中的内容超过编辑控件指定的最大字符数时,触发此消息,并将多余的内容删除。当编辑控件没有水平滚动条,而当前输入的内容超过编辑控件的宽度时,也会发送此消息。当编辑控件没有垂直滚动条时,而当前编辑框中输入的内容超过编辑控件的高度时,也会发送此消息。

      6)ON_EN_SETFOCUS 消息:当编辑控件接收到输入焦点时,发送此消息。

      7)ON_EN_UPDATE 消息:编辑控件格式化完文本,但是还没有在屏幕上显示前,发送此消息。

      8)ON_EN_VSCROLL 消息:当用户单击编辑控件的垂直滚动条时,在屏幕更新前,编辑控件向父对话框发送此消息。

    4、编辑控件应用实例

    //首先在菜单栏添加一个菜单命令用来弹出测试对话框
    //接着在主程序的.h文件,增加一个菜单命令消息映射
    afx_msg void OnTestDlg();
    //其次在主程序的.cpp文件
    ON_COMMAND(IDM_ABOUTBOX, OnTestDlg)
    //接下来编写测试对话框的实现代码
    //静态控件和编辑控件测试
    class CStaticAndEditSampleDlg :public CDialog  //对话框类声明
    {
    public:
    	void WriteLog(CString message, CString title);//记录日志函数声明
    	CStaticAndEditSampleDlg(CWnd* pParent = NULL);//标准构造函数
    	//{{AFX_DATA(CStaticAndEditSampleDlg)
    	enum 
    	{
    		IDD = IDD_STATICANDEDITSAMPLE_DIALOG
    	};
    	CEdit m_editTestScroll; //带滚动条的编辑控件对应的对象
    	CEdit m_editTest; //测试编辑控件对应的对象
    	CStatic m_staticLog; //日志静态框
    	//}}AFX_DATA
    	//{{AFX_VIRTUAL(CStaticAndEditSampleDlg)
    protected:
    	virtual void DoDataExchange(CDataExchange* pDX); //DDX/DDV 支持
    	//}}AFX_VIRTUAL
    protected:
    	HICON m_hIcon;  //图标变量
    	//{{AFX_MSG(CStaticAndEditSampleDlg)//消息映射
    	virtual BOOL OnTestInitDialog(); //初始化对话框函数声明
    	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);//系统命令函数声明
    	afx_msg void OnPaint(); //重绘函数声明
    	afx_msg HCURSOR OnQueryDragIcon(); //查询拖放图标函数声明
    	afx_msg void OnChangeEditTest();  //改变编辑框内容函数声明
    	afx_msg void OnErrspaceEditTest();  //擦除编辑框内容函数声明
    	afx_msg void OnKillfocusEditTest();  //编辑框失去焦点函数声明
    	afx_msg void OnMaxtextEditTest();   //编辑框内容达到最大值函数声明
    	afx_msg void OnSetfocusEditTest();  //设置编辑框检点函数声明
    	afx_msg void OnUpdateEditTest();  //更新编辑框函数声明
    	afx_msg void OnHscrollEditTestScroll();  //水平滚动条滚动事件函数声明
    	afx_msg void OnVscrollEditTestScroll();  //垂直滚动条滚动事件函数声明
    	afx_msg void OnButtonGetedittext();  //获取文本内容时间函数声明
    	afx_msg void OnButtonSetedittext(); //设置文本内容事件函数声明
    	afx_msg void OnButtonGetline(); //获取文本行内容事件函数声明
    	afx_msg void OnButtonGetsel();  //获取选择的文本内容事件函数声明
    	afx_msg void OnButtonSetsel();  //设置选择的文本内容事件函数声明
    	afx_msg void OnButtonReplacesel();  //替换选择的文本内容事件函数声明
    	afx_msg void OnStaticTest();  //静态控件测试事件函数声明
    	//}}AFX_MSG
    	DECLARE_MESSAGE_MAP()  //结束消息映射
    public:
    	/*DECLARE_MESSAGE_MAP()
    	afx_msg void OnEnChangeEditTest();
    	afx_msg void OnBnClickedButtonGetline();
    	afx_msg void OnEnChangeEditTestscroll();*/
    	/*afx_msg void OnAboutbox();
    	afx_msg void OnStnClickedStaticLog();*/
    };
    
    
    //对话框初始化函数
    CStaticAndEditSampleDlg::CStaticAndEditSampleDlg(CWnd* pParent/*=NULL*/) :CDialog(CStaticAndEditSampleDlg::IDD, pParent)
    {
    	//{{AFX_DATA_INIT(CStaticAndEditSampleDlg)
    	//}}AFX_DATA_INIT
    	m_hIcon = AfxGetApp()->LoadIconW(IDR_MAINFRAME); //装载应用程序图标
    }
    
    //数据交换函数
    void CStaticAndEditSampleDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX); //执行基类的数据交换函数
    	//{{AFX_DATA_MAP(CStaticAndEditSampleDlg) //控件和数据映射对应关系
    	DDX_Control(pDX, IDC_EDIT_TESTSCROLL, m_editTestScroll);
    	DDX_Control(pDX, IDC_EDIT1_TEST, m_editTest);
    	//日志静态框变量声明
    	DDX_Control(pDX, IDC_STATIC_LOG, m_staticLog);
    	//}}AFX_DATA_MAP
    }BEGIN_MESSAGE_MAP(CStaticAndEditSampleDlg, CDialog) //消息映射表开始
    //{{AFX_MSG_MAP(CStaticAndEditSampleDlg)
    
    ON_WM_SYSCOMMAND()  //系统命令消息
    ON_WM_PAINT() //重绘消息
    ON_WM_QUERYDRAGICON()  //查询拖动图标消息
    //编辑框内容改变消息映射
    ON_EN_CHANGE(IDC_EDIT1_TEST, &CStaticAndEditSampleDlg::OnChangeEditTest)
    //编辑框内容擦除消息映射
    ON_EN_ERRSPACE(IDC_EDIT1_TEST, &CStaticAndEditSampleDlg::OnErrspaceEditTest)
    //编辑框失去焦点消息映射
    ON_EN_KILLFOCUS(IDC_EDIT1_TEST, &CStaticAndEditSampleDlg::OnKillfocusEditTest)
    //编辑框内容改变消息映射
    ON_EN_MAXTEXT(IDC_EDIT1_TEST, &CStaticAndEditSampleDlg::OnMaxtextEditTest)
    //编辑框获得焦点消息映射
    ON_EN_SETFOCUS(IDC_EDIT1_TEST, &CStaticAndEditSampleDlg::OnSetfocusEditTest)
    //编辑框内容更新消息映射
    ON_EN_UPDATE(IDC_EDIT1_TEST, &CStaticAndEditSampleDlg::OnUpdateEditTest)
    //水平滚动消息映射
    ON_EN_HSCROLL(IDC_EDIT_TEST_SCROLL, &CStaticAndEditSampleDlg::OnHscrollEditTestScroll)
    //垂直滚动消息
    ON_EN_VSCROLL(IDC_EDIT_TEST_VSCROLL, &CStaticAndEditSampleDlg::OnVscrollEditTestScroll)
    //获取文本消息
    ON_BN_CLICKED(IDC_BUTTON_GETEDITTEXT, &CStaticAndEditSampleDlg::OnButtonGetedittext)
    //设置文本消息
    ON_BN_CLICKED(IDC_BUTTON_SETEDITTEXT, &CStaticAndEditSampleDlg::OnButtonSetedittext)
    ON_BN_CLICKED(IDC_BUTTON_GETLINE, &CStaticAndEditSampleDlg::OnButtonGetline) //获取行
    //获取选择内容
    ON_BN_CLICKED(IDC_BUTTON_GETSEL, &CStaticAndEditSampleDlg::OnButtonGetsel)
    //设置选择内容
    ON_BN_CLICKED(IDC_BUTTON_SETSEL, &CStaticAndEditSampleDlg::OnButtonSetsel)
    //文本替换
    ON_BN_CLICKED(IDC_BUTTON_REPLACESEL, &CStaticAndEditSampleDlg::OnButtonReplacesel)
    ON_BN_CLICKED(IDC_STATIC_TEST, &CStaticAndEditSampleDlg::OnStaticTest)
    //}}AFX_MSG_MAP
    
    END_MESSAGE_MAP()
    
    void CMFCApplication1App::OnTestDlg()
    {
    	CStaticAndEditSampleDlg aboutDlg;
    	aboutDlg.DoModal();
    }
    //初始对话框
    BOOL CStaticAndEditSampleDlg::OnTestInitDialog()
    {
    	//调用基类对话框初始化函数
    	CDialog::OnInitDialog();
    	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);  //判断是否关于命令
    	ASSERT(IDM_ABOUTBOX < 0xF000);
    	CMenu* pSysMenu = GetSystemMenu(FALSE);
    	if (pSysMenu != NULL)
    	{
    		//定义存放菜单名称的字符串变量
    		CString strAboutMenu;
    		strAboutMenu.LoadStringW(IDD_STATICANDEDITSAMPLE_DIALOG); //装载对话框的菜单
    		if (!strAboutMenu.IsEmpty())
    		{
    			pSysMenu->AppendMenu(MF_SEPARATOR);//增加分隔符
    			//增加“关于”菜单命令
    			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    		}
    	}
    	SetIcon(m_hIcon, TRUE); //设置大图标
    	SetIcon(m_hIcon, FALSE); //设置小图标
    	return TRUE;
    }
    
    void CStaticAndEditSampleDlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
    	if ((nID & 0xFFF0) == IDM_ABOUTBOX)  //判断单击选择的命令是否为“关于”命令
    	{
    		CAboutDlg dlgAbout; //定义关于对话框
    		dlgAbout.DoModal();  //显示“关于”对话框
    	}
    	else
    		CDialog::OnSysCommand(nID, lParam);  //如果不是“关于”命令,则处理命令消息
    }
    
    void CStaticAndEditSampleDlg::OnPaint()  //对话框绘制函数
    {
    	if (IsIconic())  //判断是否是图标状态
    	{
    		CPaintDC dc(this);  //进行绘制的设备上下文
    		//发送图标背景绘制消息
    		SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0);
    		//将图标放置在客户端矩形中间
    		int cxIcon = GetSystemMetrics(SM_CXICON);//获取小图标的x长度
    		int cyIcon = GetSystemMetrics(SM_CYICON);//获取小图标的y高度
    		CRect rect; //定义矩形区域
    		GetClientRect(&rect);  //获取客户区矩形
    		int x = (rect.Width() - cxIcon + 1) / 2;  //计算客户区中心点的X值
    		int y = (rect.Height() - cyIcon + 1) / 2;  //计算客户区中心点y值
    		dc.DrawIcon(x, y, m_hIcon);  //绘制图标
    	}
    	else
    		CDialog::OnPaint();
    }
    
    //获取拖动图标消息处理函数
    HCURSOR CStaticAndEditSampleDlg::OnQueryDragIcon()
    {
    	return (HCURSOR)m_hIcon;
    }
    
    //文本内容改变消息处理函数
    void CStaticAndEditSampleDlg::OnChangeEditTest()
    {
    	// TODO:  如果该控件是 RICHEDIT 控件,它将不
    	// 发送此通知,除非重写 CDialog::OnInitDialog()
    	// 函数并调用 CRichEditCtrl().SetEventMask(),
    	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
    	WriteLog(L"接收到ON_EN_CHANGE消息", CString("左边的编辑控件"));
    	// TODO:  在此添加控件通知处理程序代码
    }
    //文本内容擦除消息处理函数
    void CStaticAndEditSampleDlg::OnErrspaceEditTest()
    {
    	WriteLog(L"接收到ON_EN_ERRSPACE消息", CString("左边的编辑控件"));
    }
    //失去焦点消息处理函数
    void CStaticAndEditSampleDlg::OnKillfocusEditTest()
    {
    	WriteLog(L"接收到ON_EN_KILLFOCUS消息", CString("左边的编辑控件"));
    }
    //达到最大文本数消息处理函数
    void CStaticAndEditSampleDlg::OnMaxtextEditTest()
    {
    	WriteLog(L"接收到ON_EN_MAXTEXT消息", CString("左边的编辑控件"));
    }
    //获取焦点 消息处理函数
    void CStaticAndEditSampleDlg::OnSetfocusEditTest()
    {
    	WriteLog(L"接收到ON_EN_SETFOCUS消息", CString("左边的编辑控件"));
    }
    //更新消息处理函数
    void CStaticAndEditSampleDlg::OnUpdateEditTest()
    {
    	WriteLog(L"接收到ON_EN_UPDATE消息", CString("左边的编辑控件"));
    }
    //水平滚动消息处理函数
    void CStaticAndEditSampleDlg::OnHscrollEditTestScroll()
    {
    	WriteLog(L"接收到ON_EN_HSCROLL消息", CString("右边的编辑控件"));
    }
    //垂直滚动消息处理函数
    void CStaticAndEditSampleDlg::OnVscrollEditTestScroll()
    {
    	WriteLog(L"接收到ON_EN_VSCROLL消息", CString("右边的编辑控件"));
    }
    //显示日志函数
    void CStaticAndEditSampleDlg::WriteLog(CString message, CString title)
    {
    	//获取当前日志静态框的文本内容
    	m_staticLog.SetWindowText(title + "--" + message);
    }
    //获取编辑框内容处理函数
    void CStaticAndEditSampleDlg::OnButtonGetedittext()
    {
    	CString content; //定义编辑框内容字符串
    	m_editTest.GetWindowText(content);
    	//在弹出对话框中显示获取的编辑内容
    	MessageBox(content, L"获取左边编辑框的内容");
    }
    //设置编辑框内容处理函数
    void CStaticAndEditSampleDlg::OnButtonSetedittext()
    {
    	m_editTest.SetWindowText(L"你好,这是在测试");
    }
    //获取编辑框指定行内容处理函数
    void CStaticAndEditSampleDlg::OnButtonGetline()
    {
    	TCHAR content[256]; //存放内容的字符串变量
    	memset(content, 0x00, sizeof(content));//初始化字符串数组
    	int iCount = m_editTest.GetLine(1, content, sizeof(content));//获取第二行的内容
    	if (iCount > 0)
    		MessageBox(content, L"GETLINE 获取第二行内容");
    	else
    		MessageBox(L"失败", L"GETLINE 获取第二行内容");
    }
    //获取选择的内容
    void CStaticAndEditSampleDlg::OnButtonGetsel()
    {
    	int iStart = 0, iEnd = 0;  //定义开始位置和结束位置的变量
    	//获取选择的内容所在的开始位置和结束位置
    	m_editTest.GetSel(iStart, iEnd);
    	CString log;  //日志字符串
    	log.Format(L"选择的内容从%d个字符到第%d个字符", iStart, iEnd);//格式化信息提示
    	MessageBox(log, L"GetSel");
    }
    //设置选择的内容
    void CStaticAndEditSampleDlg::OnButtonSetsel()
    {
    	m_editTest.SetSel(5, 10, TRUE);//设置选择第6~11个字符
    	MessageBox(L"选择第6个字符到第11个字符", L"SetSel");//显示提示信息
    }
    //文本替换命令
    void CStaticAndEditSampleDlg::OnButtonReplacesel()
    {
    	m_editTest.ReplaceSel(L"若道天涯无回路,漫漫黄沙掩枯骨");
    }
    //静态控件处理函数
    void CStaticAndEditSampleDlg::OnStaticTest()
    {
    	MessageBox(L"如果使用 SS_NOTIFY 创建静态控件, \n则可以接收单击事件,\n此处就是  例子。", L"静态控件");
    }
    

    5、单选按钮和复选框

    • 单选框和复选框是特殊的按钮控件。单选按钮控件允许用户在一组选项中,选择其中的一项;复选按钮控件允许用户在一组选项中,选择其中多项。

    5.1、单选按钮控件创建

    1)在工具箱中选择 “Group Box” 添加分组框。

    2)在工具箱中选择 “Radio Button” 向分组框中添加单选按钮。

    3)将组合框里的第一个单选按钮的 Group 属性、Tab stop 属性和 Auto 属性都设置为 True;其余的单选按钮将 Tab stop 属性和 Auto 属性设置为 True 就可以了。

    5.2 单选控件的消息

    • 单选控件的消息主要有两个:
    • ON_BN_CLICKED 消息:当用单击单选按钮时,发送此消息给父窗体。
    • ON_BN_DOUBLECLICKED 消息:当用户双击单选按钮时,发送此消息给父窗体。

    5.3 复选框的创建

    1)在工具箱中选择 “Group Box” 添加分组框。

    2)在工具箱中选择 “Chick Box” 向分组框添加复选框。

    • 复选框的消息同单选按钮一样。

    5.4 单选按钮和复选框示例

    afx_msg void OnButtoGetstate();
    ON_BN_CLICKED(IDC_BUTTON_CH, &CStaticAndEditSampleDlg::OnButtoGetstate)
    
    //单选按钮和复选框测试
    void CStaticAndEditSampleDlg::OnButtoGetstate()
    {
    	//颜色选择
    	UINT iColor[] = { IDC_RADIO_RED,IDC_RADIO_GREEN,IDC_RADIO_BLUE };
    	CString sColor[] = { L"红色",L"绿色",L"蓝色" };
    	CString sResualtColor;
    	CButton *pBtn = NULL;
    	for (int i = 0; i < 3; i++)
    	{
    		pBtn = (CButton*)GetDlgItem(iColor[i]);
    		if (!pBtn)
    			continue;
    		if (pBtn->GetCheck() == 1)
    			sResualtColor = L"颜色选择:" + sColor[i];
    	}
    
    	//性别选择
    	UINT iSex[] = { IDC_RADIO_BOY,IDC_RADIO_GIRL };
    	CString sSex[] = { L"男",L"女" };
    	CString sResualtSex;
    	for (int i = 0; i < 2; i++)
    	{
    		pBtn = (CButton*)GetDlgItem(iSex[i]);
    		if (!pBtn)
    			continue;
    		if (pBtn->GetCheck() == 1)
    			sResualtSex = L"\n性别选择:" + sSex[i];
    	}
    
    	//喜好选择
    	UINT iLike[] = { IDC_CHECK_BOOK,IDC_CHECK_MUSIC,IDC_CHECK_SPORT,IDC_CHECK_DANCE };
    	CString sLike[] = { L"读书",L"听音乐",L"运动",L"跳舞" };
    	CString sResualtLike = L"\n爱好:";
    	for (int i = 0; i < 4; i++)
    	{
    		pBtn = (CButton*)GetDlgItem(iLike[i]);
    		if (!pBtn)
    			continue;
    		if (pBtn->GetCheck() == 1)
    			sResualtLike = sResualtLike + sLike[i] + L"、";
    	}
    
    	//总结输出
    	MessageBox(sResualtColor + sResualtSex + sResualtLike, L"选择结果");
    }
    

    选择按钮示例.PNG

    三、列表框和组合框

    • 列表框控件是用于从已知选项中选择选项的控件;组合框控件是编辑控件和列表控件的组合,既有编辑控件的输入文本功能,又具有列表框控件的选项选择功能。

    1、创建列表框

    • 列表框显示数据项的列表,如文件名等,用户可以选择和浏览数据项。创建列表框的步骤:

      1)在工具箱中选择 “List Box” 向对话框中添加列表框。

      2)使用类向导将控件与变量连接起来。

      3)通过变量调用 CListBox 类的成员方法操作列表框

      4)列表框类 CListBox 常用成员函数

      成员函数 功能
      GetCount() 返回列表框控件中的字符串选项的个数
      GetHorizontalExtent() 设置可以水平滚动的宽度像素数
      SetHorizontalExtent() 设置可以垂直滚动的宽度像素数
      GetTopIndex() 返回列表框控件中第一个可视字符串的索引
      SetTopIndex() 设置列表框控件中第一个可视字符串的索引
      GetItemData() 返回与列表框控件项相关的32位的值
      SetItemData() 设置与列表框控件项相关的32位的值
      GetItemDataPtr() 返回与列表框控件项相关的指针
      SetItemDataPtr() 设置与列表框控件项相关的指针
      SetItemHeight() 设置列表框控件中项的高度
      GetItemHeight() 获取列表框控件中项的高度
      GetText() 复制列表框控件中项的内容到缓冲区中
      GetTextLen() 返回列表框控件项的内容的长度
      SetColumnWidth() 设置多列列表框控件的列宽
      GetCurSel() 返回列表框控件中当前选择的字符串的索引
      SetCurSel() 选择列表框控件字符串
      SetSel() 选择或取消多列列表框控件中的列表项
      GetSelCount() 返回列表框中当前选择的字符串的个数
      GetSelItems() 返回列表框控件中当前选择的字符串
      AddString() 向列表框中增加字符串
      DeleteString() 从列表框中删除字符串
      InsertString() 向列表框指定位置增加字符串
      ResetContent() 清除列表框控件中的所有选项
      Dir() 从当前路径增加文件名到列表框控件
      FindString() 从列表框中查找字符串
      SelectString() 在单选列表框空间中查找和选择字符串

    2、列表框消息

    • 列表框控件常用的消息有:
    • ON_LBN_DBLCLK 消息:当用户双击列表框控件中选项时,列表框向父对话框发送此消息;但只有具有 LBS_NOTIFY 属性的列表框控件才会发送此消息。
    • ON_LBN_ERRSPACE 消息:当列表框控件不能分配足够的内存处理特殊请求时发送此消息。
    • ON_LBN_KILLFOCUS 消息:当列表框控件失去输入焦点时发送此消息。
    • ON_LBN_SELCANCEL 消息:取消列表框的当前选择,只有具有 LBS_NOTIFY 属性的列表框控件才会发送此消息。
    • ON_LBN_SELCHANGE 消息:当列表框控件的选择发生变化时,发送此消息;只有具有 LBS_NOTIFY 属性的列表框控件才会发送此消息;当用户按下方向键,即使选择没有发生变化也会发送此消息。
    • ON_LBN_SETFOCUS 消息:当列表框获得输入焦点时发送此消息。
    • ON_WM_CHARTOITEM 消息:没有字符串的自绘列表框控件会接受 WM_CHAR 消息。
    • ON_WM_VKEYTOITEM 消息:具有 LBS_WANTKEYBOARDINPUT 属性的列表框控件会接收 WM_KEYDOWN 消息。

    3、列表框示例

    // MFCDiaLog 消息处理程序
    BOOL MFCDiaLog::OnInitDialog()
    {
    	CDialog::OnInitDialog();
    	CString items[5] = { L"地名",L"北京",L"上海",L"广州",L"肇庆" };
    	for (int i = 0; i < 5; i++)
    	{
    		m_listTest.AddString(items[i]);
    	}
    	return TRUE;
    }
    void MFCDiaLog::OnSelChangeTest()
    {
    	int index = m_listTest.GetCurSel();
    	CString result;
    	m_listTest.GetText(index, result);
    	MessageBox(result, L"当前列表框选择的内容");
    }
    

    4、创建组合框

    • 组合框是编辑控件与列表框的组合,组合框控件有三种样式:

      样式 何时显示列表框部分 静态控件还是编辑控件
      简单样式 总是显示列表框部分 编辑控件
      下拉样式 当单击下拉箭头时 编辑控件
      下拉列表样式 当单击下拉箭头时 静态控件
    • 创建组合框的步骤:

      1)打开要添加组合框的对话框,在对话框编辑器中的工具箱对话框中选择 ”Combo Box“。

      2)在对话框的合适位置单击鼠标左键添加组合框

      3)右键组合框控件打开属性对话框,设置控件 ID 与相关属性。

    • 组合框类 CComboBox 类实现 Windows 组合框控件的功能,组合框控件具有 CListBox 类和 CEdit 类的部分函数,此外还有独有的成员函数:

      成员函数 功能
      SetDroppedWidth() 设置组合框控件中下拉列表框部分允许的最小宽度
      GetDroppedWidth() 获取组合框控件中下拉列表框部分允许的最小宽度
      ShowDropDown() 显示或隐藏组合框控件的列表框部分
      GetDroppedControlRect() 组合框控件的列表框部分可视的屏幕区域
      GetDroppedState() 设定组合框控件的列表框部分是否可见

    5、组合框消息

    • 组合框控件除了可以处理 CWnd 的消息,还能处理以下消息:
    • ON_CBN_CLOSEUP 消息:当组合框控件不是 CBS_SIMPLE 样式且组合框控件的列表框部分关闭时,发送此消息给父窗体。
    • ON_CBN_DBLCLK 消息:当用户双击选项时发送此消息,此消息仅对使用 CBS_SIMPLE 样式的组合框控件有效。
    • ON_CBN_DROPDOWN 消息:当用户要下拉组合框的列表框部分时发送此消息,此消息只对具有 CBS_DROPDOWN 和 CBS_DROPDOWNLIST 样式的组合框有效。
    • ON_CBN_EDITCHANGE 消息:当用户修改组合框的编辑控件的内容时发送此消息,并且是在 Windows 更新完屏幕后发送此消息;对 CBS_DROPDOWNLIST 的组合框无效。
    • ON_CBN_EDITUPDATE 消息:当组合框的编辑控件部分要显示修改的文本时,在控件格式化完文本内容但是显示文本前,发送此消息;对 CBS_DROPDOWNLIST 的组合框无效。
    • ON_CBN_ERRSPACE 消息:当组合框控件不能分配足够的内存处理特殊请求时发送此消息。
    • ON_CBN_SELENDCANCEL 消息:表示取消用户的选择。当用户单击某一项,然后单击其他窗体或控件隐藏的列表框部分,在发送 CBN_CLOSEUP 消息之前发送此消息,用于表示忽略用户的选择;当组合框是 CBS_SIMPLE 样式时,即使不发送 CBN_CLOSEUP 通知消息,也会发送 CBN_SELENDCANCEL 消息或 CBN_SELENDOK 通知消息。
    • ON_CBN_SELENDOK 消息:当用户选择其中一项,并且按下 Enter 键或单击下拉箭头隐藏列表框部分时,发送此消息。
    • ON_CBN_KILLFOCUS 消息:当组合框失去输入焦点时,发送此消息。
    • ON_CBN_SELCHANGE 消息:当组合框的选择发生变化时,触发此消息;在处理池消息时,如果要获取组合框中编辑控件的文本内容时,则 X 要通过 GetLBText() 函数获取,而不是 GetWindowText() 函数。
    • ON_CBN_SETFOCUS 消息:当组合框获得输入焦点时,发送此消息。

    6、组合框示例

    CComboBox m_combotest;
    	afx_msg void OnSelChangeCombotest();
    BEGIN_MESSAGE_MAP(MFCDiaLog, CDialog)
    	ON_CBN_SELCHANGE(IDC_COMBO,OnSelChangeCombotest)
    END_MESSAGE_MAP()
    BOOL MFCDiaLog::OnInitDialog()
    {
    	CDialog::OnInitDialog();
    	m_combotest.AddString(L"汉族");
    	m_combotest.AddString(L"回族");
    	m_combotest.AddString(L"满族");
    	m_combotest.AddString(L"白族");
    	m_combotest.AddString(L"其他");
    	return TRUE;
    }
    void MFCDiaLog::OnSelChangeCombotest()
    {
    	CString result;
    	m_combotest.GetLBText(m_combotest.GetCurSel(),result);
    	MessageBox(result, L"当前组合框选择的内容");
    }
    

    四、微调控件、滑块控件和进度条控件

    • Windows 中提供了三种带有刻度功能的控件,分别是微调控件、滑块控件和进度条控件。
    • 微调控件用于控制连续的整数值调整;滑块控件通过拖放滑块控件表示进度;进度条控件以动态滚动的方式显示当前程序的进度。

    1、微调控件的创建和使用

    • 微调控件也称上下文控件,提供一组箭头可以调整其值,此值称为当前位置。

    • 创建步骤:

      1)在工具箱中选择 “Spin Control” 添加微调控件。

      2)将编辑控件的 Tab 顺序值与微调控件的顺序值相邻,且编辑控件的更大。

      3)取消微调控件的 Tab属性。

      4)将微调控件的 Auto Buddy 属性设为 True。

    • MFC 中使用 CSpinButtonCtrl 类实现微调控件的功能;微调控件的默认范围是0~100,按向上箭头时减少位置值,按下向下箭头时增加位置值;可使用 CSpinButtonCtrl::SetRange() 成员函数调整范围值。

    2、创建和使用滑块控件

    • 滑块又称为跟踪条,包含滑块和可选的标记线;当用户移动滑块时,发送改变取值的消息给父对话框。
    • 滑块的创建与微调控件的创建相似,只不过在工具箱中选择 “slide control”。
    • 滑块的 Orientation 用来设置滑块是水平还是滚动。
    • Point 属性设置滑块箭头的方向。
    • Tick marks 属性设置是否具有标记的滑块。
    • Auto ticks 属性设置是否在滑块上添加等分标记。
    • Enable selection 属性表示是否带有选择部分。
    • Border 属性设置滚动条是否有边框。

    3、创建和使用进度条控件

    • 创建方法同上面的类似,在工具箱中选择 “Progress Control”。
    • MFC 中使用 CProgressCtrl 类完成进度条功能,最重要的方法有下面4个:
    • SetRange() 函数:可以设置进度条控件的范围值。
    • SetStep() 函数:可以设置进度条控件的增量间隔值。
    • SetPOS() 函数:可以设置进度条当前的位置值。
    • GetPOS() 函数:获取进度条当前位置值。

    5、示例

    // 微调控件测试
    	CSpinButtonCtrl m_spin;
    	// 滑块控件测试
    	CSliderCtrl m_slider;
    	// 进度条测试
    	CProgressCtrl m_progress;
    	afx_msg void OnReleasedcaptureSliderPercent(NMHDR* pNMHDR, LRESULT* pResult);
    	afx_msg void OnButtonTimer();
    	afx_msg void OnTimer(UINT nIDEvent);
    	// 微调控件所附的编辑控件
    	CEdit m_editPrecent;
    void MFCDiaLog::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	DDX_Control(pDX, IDC_SPIN1, m_spin);
    	DDX_Control(pDX, IDC_SLIDER1, m_slider);
    	DDX_Control(pDX, IDC_PROGRESS1, m_progress);
    	DDX_Control(pDX, IDC_EDIT2, m_editPrecent);
    }
    BEGIN_MESSAGE_MAP(MFCDiaLog, CDialog)
    	ON_NOTIFY(NM_CUSTOMDRAW, IDC_SLIDER1, OnReleasedcaptureSliderPercent)
    	ON_BN_CLICKED(IDC_BUTTON1,OnButtonTimer)
    	ON_WM_TIMER(IDC_PROGRESS1,OnTimer)
    END_MESSAGE_MAP()
        
    void MFCDiaLog::OnReleasedcaptureSliderPercent(NMHDR* pNMHDR, LRESULT* pResult)
    {
    	CString text;  //定义字符串变量
    	//获取滑块控件当前位置
    	text.Format(L"%d", m_slider.GetPos());
    	//在编辑控件中显示当前选择值
    	m_editPrecent.SetWindowText(text);
    	*pResult = 0;
    }
    //定时器按钮
    void MFCDiaLog::OnButtonTimer()
    {
    	m_progress.SetPos(0);
    	SetTimer(100, 100, NULL);
    }
    //定时器处理函数
    void MFCDiaLog::OnTimer(UINT nIDEvent)
    {
    	//如果定时器是滑块滑动定时器
    	if (nIDEvent == 100)
    	{
    		int pos = m_progress.GetPos();//获取进度条位置
    		if (pos < 100)
    			m_progress.SetPos(m_progress.GetPos() + 1);
    		else
    			KillTimer(100);//关闭计时器
    	}
    	CDialog::OnTimer(nIDEvent);
    }
    

    五、列表视图控件和树形视图控件

    • 列表视图控件扩展了列表框控件的功能,用于显示并列级别的数据信息;树形视图控件用于显示层次结构的数据项。

    1、创建列表视图控件

    • 列表视图控件显示包含图标和标签的项的集合,每项在图标和标签的右边显示信息,最常见的列表视图控件是 Windows 系统的资源管理器。

    • 列表视图控件支持以下四种显示方式(视图样式):

      1)Icon 视图:图标视图,此种显示方式下,每个数据项显示时,在完整尺寸的图标下显示标签。用户可以拖动数据项到列表视图对话框的任意位置。

      2)Small Icon 视图:(16 x 16)小图标视图,每个数据项以小视图的方式显示,并在右边显示标签,用户可以拖动数据项到列表视图对话框的任意位置。

      3)List 视图:列表视图,每个数据项以小图标样式按列方式排列,标签显示在图标右边,不能任意拖动。

      4)Report 视图:报表视图,每个数据项显示一行,除了名称外,其他信息在名称的右边列出,从左向右依次是图标列、标签列、其他信息列;此种样式内置了(CHeaderCtrl)来实现这些列。

    2、CListCtrl 类

    • CListCtrl 类封装了列表视图控件的功能。

    • CListCtrl 类常用的成员方法有:

    • CListCtrl::GetItem() 方法:获取指定索引处的项的数据。

    • CListCtrl::InsertItem() 方法:在指定索引出添加新项。

    • CListCtrl::FindItem() 方法:查找指定项。

    • 列表视图控件用 CImageList 类实现图像列表,每个控件有四个不同的图像列表:大图标、小图标、用户自定义状态和标题头项。

    • 消息:

      HDN:Header Notify
      
      LVN:ListView control Notify
      
      NM:Notify Message
      
      TVN:TreeView control Notify
      
       
      
      HDN_BEGINTRACK 开始拖动控件顶部的分割线
      
      HDN_BEGINDRAG 开始拖动控件顶部的分栏(item)
      
      HDN_BEGINFILTEREDIT 开始过滤器编辑(filter edit)
      
      LVN_BEGINDRAG 鼠标左键正在被触发以便进行拖放操作(当鼠标左键开始拖拽列表视图控件中的项目时产生)
      
      LVN_BEGINRDRAG 鼠标右键正在被触发以便进行拖放操作(当鼠标右键开始拖拽列表视图控件中的项目时产生)
      
      LVN_BEGINLABELEDIT 开始编辑项的文本
      
      LVN_BEGINSCROLL 开始滚动操作
      
      LVN_COLUMNCLICK 单击列(当鼠标单击列表视图控件列标题时产生)
      
      NM_CLICK 当鼠标单击列表视图控件时产生
      
      NM_CUSTOMDRAW 自定义绘图操作
      
      LVN_COLUMNCLICK 单击列
      
      HDN_DIVIDERDBLCLICK 双击顶部的分割线
      
      LVN_DELETEALLITEMS 删除所有项
      
      LVN_DELETEITEM 删除某个项
      
      NM_DBLCLK 当鼠标双击列表视图控件时产生
      
      HDN_ENDTRACK 停止拖动顶部的分割线
      
      HDN_ENDDRAG 停止拖动控件顶部的分栏(item)
      
      HDN_ENDFILTEREDIT 结束过滤器的编辑
      
      LVN_ENDLABELEDIT 结束对项文本的编辑
      
      LVN_ENDSCROLL 结束滚动操作
      
      HDN_FILTERBTNCLICK 单击过滤器按钮
      
      HDN_FILTERCHANGE 顶部过滤器的属性正被改变/编辑
      
      NM_FONTCHANGED 控件更换字体
      
      HDN_GETDISPINFO 控件需要标题项的回调信息
      
      LVN_GETDISPINFO 请求需要显示的信息
      
      LVN_GETINFOTIP 请求显示在工具提示窗口内的附加的文本信息
      
      LVN_GETEMPTYMARKUP 列表控件没有任何项(用于向父窗口请求标注文本markup text)
      
      LVN_HOTTRACK 鼠标滑过某个项
      
      NM_HOVER 鼠标悬停于某项(item)上
      
      HDN_ITEMCLICK 鼠标单击标题项
      
      HDN_ITEMCHANGED 标题项的属性被改变
      
      HDN_ITEMCHANGING 标题项的属性将被改变
      
      HDN_ITEMDBLCLICK 双击标题项
      
      HDN_ITEMKEYDOWN 标题项被选中的同时按下某个按键
      
      HDN_ITEMSTATEICONCLICK 用户点击标题项的状态图标
      
      LVN_INSERTITEM 当向列表视图控件插入项目时产生
      
      lVN_ITEMACTIVATE 激活某个项
      
      LVN_ITEMCHANGED 某个项已经发生变化
      
      LVN_ITEMCHANGING 某个项目正在发生变化
      
      NM_KILLFOCUS 当视表列图控件失去焦点时产生
      
      LVN_KEYDOWN 某个键被按下
      
      LVN_LINKCLICK 单击一个链接
      
      LVN_MARQUEEBEGIN 开始某个边框选择
      
      NM_OUTOFMEMORY 当内存溢出时产生
      
      LVN_ODCACHEHINT 虚拟列表控件的显示区域的内容发生了变化
      
      LVN_ODSTATECHANGED 虚拟列表的控件的某个项或某个范围内的项已经发生变化
      
      LVN_ODFINDITEM 需要拥有者查找一个特定的回调项
      
      NM_RCLICK 当鼠标右键单击列表视图控件时产生
      
      NM_RDBLCLK 当鼠标右键双击列表视图控件时产生
      
      NM_RELEASEDCAPTURE 控件正在释放鼠标捕捉(releasing mouse capture)
      
      NM_RETURN 控件获取输入焦点且用户按下return按键
      
      NM_SETFOCUS 当列表视图控件获得焦点时产生
      
      LVN_SETDISPINFO 父窗口必须更新控件为项所维护的信息
      
      HDN_TRACK 用户正在拖动控件顶部的分割线
      
      NM_THEMECHANGED 主题已经改变
      

    3、CTreeCtrl 类

    • CTreeCtrl 类提供树形视图控件的功能,是实现层次项的窗口,如磁盘的文件项。每项包括一个标签和一个可选的位图图片,并且每项都可以包含与之相连的子项。通过单击每项可以展开和收缩与之相关的子项的列表。

    • CTreeCtrl 类成员函数

      成员函数 功能
      GetCount() 返回与视图控件相连的项的数目。
      GetNextItem() 返回视图控件中下一个符合要求的项。
      ItemHasChildren() 返回指定项是否有子项。
      GetChildItem() 返回执行项的子项。
      GetNextSiblingItem() 返回下一个兄弟项。
      GetPrevSiblingItem() 返回上一个兄弟项。
      GetParentItem() 返回指定项的父项。
      GetFirstVisibleItem() 返回指定项的第一个可视项。
      GetNextVisible() 返回指定项的下一个可视项。
      GetPrevVisible() 返回指定项的前一个可视项。
      GetSelectItem() 返回当前选择的项。
      GetRootItem() 返回根项。
      GetItem() 返回视图项的属性。
      SetItem() 设置视图项的属性。
      GetItemImage() 返回与指定项相关的图像。
      SetItemImage() 设置指定项的图像。
      GetItemText() 返回指定项的文本。
      SetItemText() 设置指定项的文本。
      InsertItem() 向控件中插入新项。
      DeleteItem() 从控件中删除项。
      DeleteAllItems() 删除所有项。
      Expand() 展开或收缩指定项下的子项。

    4、树形视图控件的消息

    • CTreeCtrl 类发送的 WM_NOTIFY 消息。

      消息 含义
      TVN_BEGINDRAG 开始拖动操作时的通知消息。
      TVN_BEGINLABELEDIT 开始编辑标签内容时的通知消息。
      TVN_BEGINRDRAG 使用右键开始拖动操作时的通知消息。
      TVN_DELETEITEM 删除指定项时的通知消息。
      TVN_ENDLABELEDIT 结束编辑标签内容时的通知消息。
      TVN_GETDISPINFO 树形视图控件请求显示项时的通知消息。
      TVN_ITEMEXPANDED 展开或收缩项时的通知消息。
      TVN_ITEMEXPANDING 要展开或收缩项时的通知消息。
      TVN_KEYDOWN 按下键盘时的通知消息。
      TVN_SELCHANGED 选项变化时的通知消息。
      TVN_SELCHANGING 要变化选项时的通知消息。
      TVN_SETDISPINFO 通知要更新项包含的信息。

    5、示例:

    BOOL MFCDiaLog::OnInitDialog()
    {
    	//列表视图控件
    	m_listview.InsertItem(0, L"张三", 0);
    	m_listview.InsertItem(1, L"李四", 1);
    	m_listview.InsertItem(2, L"王五", 2);
    	//树形视图
    	HTREEITEM hProvince = m_filectrl.InsertItem(L"广东省", 0, 0);
    	HTREEITEM hcity1 = m_filectrl.InsertItem(L"肇庆市", 1, 1, hProvince);
    	m_filectrl.InsertItem(L"端州区", 2, 2, hcity1);
    	m_filectrl.InsertItem(L"星湖区", 2, 2, hcity1);
    	m_filectrl.InsertItem(L"鼎湖区", 2, 2, hcity1);
    	m_filectrl.InsertItem(L"高要区", 2, 2, hcity1);
    	hcity1 = m_filectrl.InsertItem(L"汕尾市", 1, 1, hProvince);
    	HTREEITEM city2 = m_filectrl.InsertItem(L"陆丰市", 2, 2, hcity1);
    	m_filectrl.InsertItem(L"海丰县", 2, 2, hcity1);
    	m_filectrl.InsertItem(L"城区", 2, 2, hcity1);
    	m_filectrl.InsertItem(L"陆河县", 2, 2, hcity1);
    	m_filectrl.InsertItem(L"河西街道", 3, 3, city2);
    	return TRUE;
    }
    
    

    树形视图.PNG

    六、ActiveX 控件

    • ActiveX 控件,也称为 OLE 控件,是提供连接点和主机标准接口的 COM 组件。这些标准接口定义可以在包含器中处理控件的协议、交换信息和处理事件。

    1、使用 ActiveX 控件

    • 使用对话框编辑器可以往对话框中添加 ActiveX 控件,具体方法是:在对话框中右键,在弹出的右键菜单中选择“插入 ActiveX 控件”,然后在 ActiveX 控件添加对话框中选择要添加的 ActiveX 控件。控件可以在设计时设置控件属性,接着资源编辑器便会用相关的指定值初始化控件,但是这些属性值在编程时仍然可以修改。

    2、ActiveX 控件的结构

    • 作为 COM 服务器,ActiveX 控件的结构有以下几个方面:
    • 属性:ActiveX 控件使用成员变量表示中间状态成员变量通过 Get() 和 Set() 访问函数实现后称为属性。idl 文件使用 progget 标识的每个访问方法都有对应的 Get() 函数,idl 文件中使用 propput 或 propputref 标识的每个访问方法都有对应的 Set() 函数。
    • 方法:使用公共方法定义的控件行为。包装类提供了访问控件方法的途径。如果使用包装类,通过获取接口的指针访问控件的方法。
    • 事件:空间可以使事件通知宿主程序“有事情发生”。如 Button 按钮控件的 OnClick 事件,当用户单击控件按钮时,按钮控件就会触发 OnClick 事件,然后调用相关的处理函数。
    • 类型库:类型库告诉控件包含器,控件支持的属性、方法和事件。控件库可以放在单独的文件中,即扩展名为.tlb 的文件,或放在控件内部。控件库还可以包含控件的组件类信息。组件类是使用 GUID 定义的 COM 类,包含控件定义的一个或多个接口。

    3、包装类

    • 使用控件时,类向导会每个控件的内部组件类生成包装类,这些包装类为组件提供了简单的编程接口。
    展开全文
  • 作者:张善民,华清远见嵌入式培训中心讲师。界面和交互的设计决定了应用程序在移动设备上的用户...本文将详细介绍Windows Phone 7常用的布局和控件,以及控件外观自定义的方法。正如任何一个C#程序都会以Main()方法为
  • windows通用控件

    千次阅读 2008-06-02 16:14:00
    WIN95相对于WIN3X有几个加强的用户界面控件...以前程序员要自己去编程使用它们,现在微软已经把它们包含到了WIN9X和WINNT中了。 Toolbar ---工具条 Tooltip ---提示文本 Status bar ---状态条 Property sheet ---属性页
  • windows标准控件的介绍与使用

    千次阅读 2014-07-06 16:23:17
    Windows系统提供的标准控件主要包括静态控件、按钮控件、编辑框控件、列表框控件、组合框控件等,如表所示。 Windows标准控件的类型 类别 MFC类控件类型 静态控件...
  • Windows static控件(静态文本框控件

    千次阅读 2016-06-20 06:37:27
    使用 TextOut 和 DrawText 函数有时候会方便,例如: 文本能自动换行,超出窗口范围会被隐藏;每次更改文本都要先擦除背景...除了静态文本框,Windows的标准控件还有很多种,例如按钮、下拉菜单、单选按钮、复选
  • Windows控件 概述

    千次阅读 2011-11-30 20:00:40
    本文将要介绍的Windows控件指的是Windows系统预定义的标准控件,如按钮控件、编辑控件和列表控件等。这些预定义控件实际是一种特殊的子窗口,主要供用户同应用程序的交互之用。和普通窗口类一样,每一个预定义控件也...
  • 复合控件包含与每个包含Windows 窗体控件相关联的所有固有功能,允许您有选择地公开和绑定它们的属性。复合控件还提供了大量的默认键盘处理功能,您需要任何额外的开发。 扩展控件是通过从现有的 Windows
  • Windows窗体与控件

    万次阅读 2016-05-11 11:20:39
    学习下Window的窗体与控件,UI,我的IDE是VS2012,通过学习这些基本控件,如果以后要用到别的控件,就能够较快上手。 Windows窗体窗体是应用程序的基本单元,是非常重要的。它实质上是一块白板,通过添加控件可以...
  • Windows 各种控件使用心得

    千次阅读 2011-07-18 20:14:02
    管理控件函数:ShowWindow()MoveWindow()CreateWindow()CreateWindowEx()系统预定义的窗口类:BUTTON 按钮控件COMBOBOX 组合框控件EDIT 编辑框控件LISTBOX 列表框控件SCROLLBAR 滚动条控件
  • 如题,使用ToolStripControlHost。 先看MSDN上介绍的: ToolStripControlHost 是 ToolStripComboBox、... ToolStripControlHost 可以通过两种方法承载其他控件包括自定义控件): •从派生自 Control 的类
  • Windows Phone 7框架、控件和开源项目

    千次阅读 2012-03-17 00:17:54
    Windows Phone 7的开发中,可避免地需要使用到很多方面的技术和资料。轩辕在这里给你总结下Windows Phone 7开发中对你有帮助的开发框架、控件和开源项目,以便以后的学习和开发过程中作为参考。   ...
  • 在VS2015中,可以通过API函数获取Windows窗口中控件的信息,包括控件句柄、控件显示的文字以及控件类型等。其流程为,首先获取Windows指定窗口的句柄,之后通过回调函数遍历该窗口中的控件句柄,最后通过控件句柄...
  • 网上搜集整理:    注意:VS2010已经发布几个月了,手机类编程需要安装...本文将详细介绍Windows Phone 7常用的布局和控件,以及控件外观自定义的方法。正如任何一个C#程序都会以Main()方法为程
  • ++++++++++++++++++++++++++++++++++++++++++ 本文系本站原创,欢迎转载! 转载请注明出处: ... ++++++++++++++++++++++++++++++++++++++++++   在Silverlight中,基本上所有的控件都在Syste
  • 如果有两个或多个线程操作某一控件的状态,则可能会迫使该控件进入一种一致的状态。还可能出现其他与线程相关的 bug,包括争用情况和死锁。确保以线程安全方式访问控件非常重要。 很多人遇到过工作线程...
  • Windows Phone 的控件

    千次阅读 2013-05-08 16:25:50
    转自:http://msdn.microsoft.com/zh-cn/library/windowsphone/develop/ff402561(v=vs.105).aspx#tag_navigation_controls   适用于: Windows Phone...Windows Phone 应用有几种不同类型的可用控件。本主题对 Windo
  • 通过继承,可以创建不仅保留了标准 Windows 窗体控件的所有内在功能,而且还包含自定义功能的控件。在本演练中,将创建一个名为 ValueButton 的简单继承控件。此按钮将继承标准 Windows 窗体 Button
  • 参考自:http://msdn.microsoft.com/ZH-CN/library/SYSTEM.WINDOWS.FORMS.CONTROL.INVOKE.aspx 如果使用多线程来提高 Windows ...如果有两个或多个线程操作某一控件的状态,则可能会迫使该控件进入一种一致的状态。
  • 扩展你的WIndows标准控件

    千次阅读 2006-12-15 13:33:00
    扩展你的WIndows标准控件 作者:ShellEx www.shellex.cn && blog.csdn.net/shellex 版权所有。标准控件嘛,意味着他们默认的功能和表现力都是有限的.比如说,当鼠标点击Edit控件时,虽然作为子窗体的Edit控件(Edit...
  • 如何:对 Windows 窗体控件进行线程安全调用 使用多线程提高 Windows 窗体应用程序的性能时,必须注意以线程安全方式调用控件。 示例 访问 Windows 窗体控件本质上不是线程安全的。如果有两个或多个线程操作某...
  • vs2005的windows 窗体控件

    千次阅读 2007-10-04 18:52:00
    功能 控件 说明 数据显示
  • 一、控件含义 在C#中可视化界面(WinForm)中的组件统称为...二、常用的Windows窗体控件 控件名称 含义 Label 标签控件 LinkLabel 链接标签控件 Button 按钮控件 TextBox 文本框控件 Radio...
  • Windows SDK中的标准控件和通用控件

    千次阅读 2010-12-23 09:13:00
    控件包括:静态控件、按钮控件、编辑框控件、列表框控件、组合框控件,滚动条等如表所示。 Windows标准控件的类型 Static Group Box Button Check Box Radio Button Edit ...
  • 访问 Windows 窗体控件本质上不是线程安全的。如果有两个或多个线程操作某一控件的状态,则可能会迫使该控件进入一种一致的状态。还可能出现其他与线程相关的 bug,包括争用情况和死锁。确保以线程安全方式访问...
  • 允许使用鼠标进行拖曳,以便选择一段连续的时间,此段连续的时间包括起始和结束时间 (1)MonthCalendar控件以粗体显示特定日期 步骤: 创建一个DateTime对象,该对象中指定需要以粗体显示的日期 使用...
  • VC中Windows常用控件的创建和使用

    千次阅读 2006-03-06 17:38:00
    VC中Windows常用控件的创建和使用 引言 本文将要介绍的Windows控件指的是Windows系统预定义的标准控件,如按钮控件、编辑控件和列表控件等。这些预定义控件实际是一种特殊的子窗口,主要供用户同应用程序的交互之用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 139,453
精华内容 55,781
关键字:

windows7的控件不包括