第 5章对话框和常用控件
5.1 对话框的使用
5.2 控件的创建和使用方法作业 1
5.3 常用控件
5.4 通用对话框和消息对话框作业 2
5.1对话框的使用
5.1.1模式和无模式对话框
模式对话框
指当对话框被弹出,用户必须在对话框中作出相应的操作,在退出对话框之前,对话框所在的应用程序不能继续执行。
无模式对话框
指当对话框被弹出后,一直保留在屏幕上,可继续在对话框所在的应用程序中进行其它操作;需要使用对话框时,单击对话框所在的区域即可激活。
在创建和退出对话框窗口时的方式不同,
创建时,模式对话框由系统自动分配内存空间,对话框退出时,对话框对象自动删除。无模式对话框需要来指定内存,退出时还需删除对话框对象。
退出时,两种对话框所使用的终止函数不一样。模式对话框通过调用
CDialog:,EndDialog来终止,无模式对话框则是调用
CWnd::DestroyWindow来终止。
函数 CDiaolog::OnOK和 CDiaolog::OnCancel是调用 EndDialog的,因此无模式对话框必须用 DestroyWindow来重载 OnOK 和 OnCancel两个函数。
需要正确删除表示对话框的对象。对模式对话框,在创建函数返回后即可删除对象。无模式对话框不是同步的,在创建函数调用后立即返回,因而不知道何时删除对象,但可以通过重载 CWnd::PostNcDestroy函数并执行清除操作。
5.1对话框的使用
5.1.2使用对话框编辑器
打开对话框编辑器将项目工作区窗口切换到 ResourceView页面,双击 Dialog目录下任意一个对话框 ID。或者,选择,Insert”?“Resource”菜单命令 (或按快捷键 Ctrl+R),
选择 Dialog项,单击 New。
图 5.1 打开的对话框编辑器控件工具栏布局工具栏默认对话框资源 ID号默认对话框模板基准线标尺
5.1对话框的使用在对话框中添加和编辑控件
(1)控件添加的方法在对话框中添加一个控件的方法有下列几种:
在控件工具栏中单击某控件,鼠标箭头在对话框内变成,十,字形状;在对话框指定位置单击鼠标左键,再拖动选择框可改变控件的大小和位置。
在控件工具栏中单击某控件,鼠标箭头对话框内变成,十,字形状;在指定位置处单击鼠标左键不放,拖动鼠标至满意位置,释放鼠标键。
用鼠标左键点中控件工具栏中的某控件,并按住鼠标键不放;在移动鼠标到对话框的指定位置的过程中,会看到一个虚线框,下面带有该控件的标记;释放鼠标键。
控件的选择静态文本组框复选框组合框水平滚动条旋转按钮滑动条列表视图标签复合编辑月历用户 定制 工具静态图片编辑框按钮单选框列表框垂直滚动条进展条热键树形视图动画日期选择
IP地址组合框的扩展图 5.2 控件工具栏和各按钮含义
5.1对话框的使用
(2)单个控件的选取
鼠标选取保证选择按钮 ( )是被选中的,移动鼠标指针至指定的控件上,单击鼠标左键。
助记符选取在相应的控件上右击。选择,Properties”菜单项,对话框中的,Caption”框是用来输入控件的标题,在标题中的某个字母之前键入,&”符号,则该字母就是此控件的助记符。
Tab键选取利用 Tab键,可在对话框内的控件中进行选择。每按一次 Tab键依次选取对话框中的下一个控件,若按住 Shift键,再单击 Tab键则选取上一个控件。
(3)多个控件的选取
在对话框内按住鼠标左键不放,拖出一个大的虚框,释放鼠标,则被该虚框所包围的控件都将被选取。
先按住 Shift键不放,用鼠标选取控件,直到所需要的多个控件选取之后再释放 Shift键。若在选取时,对已选取的控件再选取一下,则该控件取消选取。
一旦单个控件被选取后,其四周由选择框包围着,选择框上还有几个 (通常是八个 )蓝色实心小方块,拖动它可改变控件的大小,如图。
多个控件被选取后,其中只有一个控件的选择框有几个蓝色实心小方块,这个控件称为主要控件,而其他控件的选择框的小方块是空心的。如图。
(b)
图 5.3 单个控件和多个控件的选择框
(a)
5.1对话框的使用
(4)控件的移动、删除和复制当单个控件或多个控件被选取后,按方向键或用鼠标拖动控件的选择框可移动控件。若在鼠标拖动过程中还按住 Ctrl键则复制控件。若按 Del键可将选取的控件删除。
(5)设定控件的 Tab键次序一是改变用 Tab键选择控件的次序,二是当两个或两个以上的控件构成一组时,需要它们的 Tab键次序连续。
对话框内控件的 Tab键次序设定步骤如下:
首先,选择,Layout”?“Tab Order”命令,或按 Ctrl+D,此时每个控件的左上方都有一个数字,表明了当前 Tab键次序,如图。
其次,按新的次序依次用鼠标单击各个控件,新的 Tab键即可生成。
最后,单击对话框或按 Enter键结束 Tab Order 方式。
图 5.4 控件的 Tab键次序
5.1对话框的使用对话框内的控件的布局图 5.6 Layout菜单命令项靠齐上边左右间隔相等 大小相同靠齐左边 上下 居中宽度相同 显 示 标尺靠齐右边 左右居中高度相同测试对话框 靠齐下边 上 下 间隔相等 显示网格图 5.5 控件布局工具栏
5.1对话框的使用
大多布置控件的命令使用前,需要选取多个控件,且,主要控件,起到了关键作用。多个控件的布置过程中,常需要重新设置,主要控件,。设置的方法是按住 Ctrl或 Shift键,用鼠标单击所要指定的控件。
系统提供了网格、标尺等辅助工具。在图 5.5的控件布局工具栏的最后两个按钮分别用来网格和标尺的切换。一旦网格显示,添加或移动控件时都将自动定位在网格线上。,Layout”菜单下的,Guide Settings”命令提供了设置网格单元大小的功能,如图。
测试对话框图 5.7 Guide Settings对话框
5.1对话框的使用
5.1.3对话框的编程
添加对话框资源选择,Insert”?“Resource”菜单命令 (或按 Ctrl+R),若单击 Dialog项左边的
,+”号,将展开对话框资源的不同类型选项,如图。
图 5.8,Insert Resource”对话框
5.1对话框的使用
改变对话框的属性在对话框模板的非控件的区域内左击,用下列方式之一打开属性对话框:
选择,View”菜单?,Properties”命令或按 Alt+Enter健。
用鼠标右击对话框模板,选取 Properties命令。
如图,General是对话框属性的默认显示页面,其中列有对话框的标识符名称框、标题框等,具体说明如表。
图 5.9 属性对话框
5.1对话框的使用
向对话框内添加控件
添加一个类在对话框模板的非控件的区域内双击,如图的对话框。
单击 [OK],弹出如图的对话框。可以为对话框资源定义一个新类名。
图 5.11,Adding a Class”对话框图 5.12,New Class”对话框
5.1对话框的使用
消息映射单击 [OK]按钮,出现,MFC ClassWizard”对话框,如图。
图 5.13,MFC ClassWizard”对话框
5.1对话框的使用选定 IDC_BUTTON1的 BN_CLICKED,双击左键或单击 [Add Function]按钮,
如图。
对话框中,可以为添加的成员函数名重新定义,单击 [OK]。选定成员函数
OnButton1项,双击左键或单击 [Edit Code]按钮,在此成员函数添加代码。
不同资源对象 (控件、菜单命令等 )的消息是不相同的。例如,按钮控件
IDC_BUTTON1的消息有两个,BN_CLICKED和 BN_DOUBLECLICKED,分别表示当用户单击或双击该按钮时产生的消息。
一般不需要对图 5.10对话框中的 [OK](确定 )与 [Cancel](取消 )按钮进行消息映射,因为系统已自动设置了这两个按钮的动作,当用户单击这两个按钮都将自动关闭对话框。
图 5.14,Add Member Function”对话框
5.1对话框的使用
添加用户代码
(1)在头文件 (MyDlg.h文件 )中声明消息处理函数 OnButton1:
protected:
//{{AFX_MSG(CMyDlg)
afx_msg void OnButton1();
//}}AFX_MSG
(2)在 MyDlg.cpp源文件开头部分的消息映射入口,添加消息映射宏:
BEGIN_MESSAGE_MAP(CMyDlg,CDialog) // 消息映射开始
//{{AFX_MSG_MAP(CMyDlg)
ON_BN_CLICKED(IDC_BUTTON1,OnButton1)
//}}AFX_MSG_MAP
END_MESSAGE_MAP() // 消息映射结束表明消息及其处理函数之间的联系。单击按钮控件 IDC_BUTTON1时,系统将自动调用 OnButton1函数。
(3)在 MyDlg.cpp文件中写入一个空的消息处理函数的模板,以便用户填入具体代码,如下面的框架:
void CMyDlg::OnButton1()
{
// TODO,Add your control notification handler code here
}
5.1对话框的使用
在程序中使用对话框
(1)利用项目工作区的 ClassView标签项,将 Ex_SDIHello.cpp源文件打开;
(2)在 Ex_SDIHello.cpp源文件的前面加上包含类 CMyDlg的头文件:
#include "MyDlg.h"
(3)在 InitInstance函数体中的,return TRUE;”语句之前添加下列代码:
CMyDlg dlg;
dlg.DoModal();
DoModal是模式对话框最常用的函数,它负责对话框的显示和终止。
(4)编译并运行。在程序的一开始就出现用户自己设计的对话框,单击
[Button1]按钮将弹出,欢迎进入对话框的设计!,的消息对话框来。
5.2控件的创建和使用方法
5.2.1控件的创建方法控件的创建方式有以下两种:
一种是在对话框模板中用编辑器指定控件,也就是说,将控件的父窗口指定为对话框,这样做的好处是明显的,因为当应用程序启动该对话框时,
Windows系统就会为对话框创建控件;而当对话框消失时,控件也随之清除。
另一种方式是将控件看作是任一窗口的子窗口,并通过调用相应的 Create
函数来创建。
[例 Ex_SDIHello] 在上例 Ex_SDIHello的基础上用子窗口方式创建控件。
(1)打开 CMyDlg的头文件 MyDlg.h,添加一个按钮类 CButton指针变量:
class CMyDlg,public CDialog
{
// Construction
public:
CMyDlg(CWnd* pParent = NULL); // standard constructor
CButton *m_btnWnd;
…
}
5.2控件的创建和使用方法
(2)按 Ctrl+W快捷键打开对话框,切换到 Message Maps页面,在 Object IDs
列表中选定,CMyDlg”项,并在 Message列表中找到 WM_INITDIALOG消息,
双击鼠标左键,然后单击 [Edit Code]按钮,添加下列代码:
BOOL CMyDlg::OnInitDialog()
{ CDialog::OnInitDialog();
// TODO,Add extra initialization here
m_btnWnd = new CButton(); // 构造按钮控件
m_btnWnd ->Create("你好 ",WS_CHILD | WS_VISIBLE |
BS_PUSHBUTTON,
CRect(20,20,120,60),this,201); // 创建
CFont *font = this->GetFont(); // 获取对话框的字体
m_btnWnd->SetFont(font); // 设置控件字体
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION,OCX Property Pages should return FALSE
}
Create用来创建一个按钮控件,第一个参数指定按钮的标题,第二个参数指定控件的风格,第三个参数指定它在父窗口中的位置和大小,第四个参数指定父窗口指针,最后一个参数是指定该控件的标识值。
(3)编译并运行,
5.2控件的创建和使用方法
5.2.2控件的数据交换和数据校验例如,为 CMyDlg类的按钮控件 IDC_BUTTON1添加并使用其成员变量
m_MyBtn,则其相应的过程如下:
(1)启动 MFC ClassWizard,切换到 Member Variables页面,如图。
(2)选定 Class name为 CMyDlg,然后在 Control IDs列表中,选定所要关联的控件 ID号 IDC_BUTTON1,双击鼠标左键或单击 [Add Variable]按钮,如图。
图 5.16 ClassWziard的,Member Variables”页面图 5.17,Add Member Variable”对话框
5.2控件的创建和使用方法
(3)在 Member variable name框中填好与控件相关联的成员变量 m_MyBtn,单击 [OK],在 Control IDs列表中出现刚才添加的内容。
需要说明的是,
DDV/DDX技术中,允许为同一个控件关联多个数据成员变量,但必须保证这些变量名是互不相同的,且这些变量在同一个类型不能有多个变量。
如果添加的成员变量是一个数值类型,则在 MFC ClassWizard对话框的
Member Variables页面下方还要求用户输入变量的范围,这就是控件的数据校验设置。
(4)单击 [OK],发现 ClassWizard作了以下三方面的修改。
在 MyDlg.h文件中,添加与控件关联的成员变量的声明,代码如下:
// Dialog Data
//{{AFX_DATA(CMyDlg)
enum { IDD = IDD_DIALOG1 };
CButton m_MyBtn;
CString m_strEdit;
//}}AFX_DATA
5.2控件的创建和使用方法
在 MyDlg.cpp文件中的 CMyDlg构造函数实现代码处,添加数据成员变量的初始代码:
CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/)
,CDialog(CMyDlg::IDD,pParent)
{ //{{AFX_DATA_INIT(CMyDlg)
m_strEdit = _T("");
//}}AFX_DATA_INIT
}
在 MyDlg.cpp文件中的 DoDataExchange函数体内,添加控件的 DDX/DDV
代码。
void CMyDlg::DoDataExchange(CDataExchange* pDX)
{ CDialog::DoDataExchange(pDX); // 调用此函数作为 DDX的开始
//{{AFX_DATA_MAP(CMyDlg)
DDX_Control(pDX,IDC_BUTTON1,m_MyBtn);
DDX_Text(pDX,IDC_EDIT1,m_strEdit);
DDV_MaxChars(pDX,m_strEdit,20);
//}}AFX_DATA_MAP
}
5.2控件的创建和使用方法
(5)为一个控件定义一个关联的数据成员变量后,就可以使用
CWnd::UpdateData函数实现控件的控制,包括控件相关数据的输入和读取。
运行该程序,当在编辑框中输入,Hello”后,单击 [Button1]按钮,则此时该按钮的名称就变成了编辑框控件中的内容,Hello”,如图。
图 5.19 使用控件的数据成员变量
5.2控件的创建和使用方法
5.2.3控件的通用属性图 5.20 按钮控件的属性对话框
5.2控件的创建和使用方法
5.2.4控件的消息控件的编程和使用过程中,可以向控件发送消息来完成特定的任务,或者是根据控件产生的消息执行自己的代码。
应用程序创建一般控件或公共控件之后,控件的状态发生改变时,控件就会向其父窗口发送消息,这个消息称为,通知消息,。对于每个消息,系统都会用一个 MSG结构来记录,MSG具有下列结构:
typedef struct tagMSG { // msg
HWND hwnd; // 接收到消息的窗口句柄
UINT message; // 消息
WPARAM wParam; // 消息的附加信息,它的含义取决于 message
LPARAM lParam; // 消息的附加信息,它的含义取决于
message
DWORD time; // 消息传送时的时间
POINT pt; // 消息传送时,光标的屏幕坐标
} MSG;
对于一般控件来说,通知消息通常是一条 WM_COMMAND消息,这条消息的
wParam参数的低位字中含有控件标识符,wParam参数的高位字则为通知代码,lParam参数则是指向控件的句柄。
5.2控件的创建和使用方法对于公共控件,通知消息通常是一条 WM_NOTIFY消息,wParam参数是发送通知消息的控件的标识符,lParam参数是指向 NMHDR结构的指针。对于有些控件的通知消息,lParam参数是指向一个更大的结构,且结构中的第一个成员还必须具有 NMHDR结构。
对于控件的 WM_COMMAND或是 WM_NOTIFY消息,都可以用 ClassWizard对它们加以映射。
尽管控件的各自通知消息并不相同,但下列的通知消息是所有 Windows控件所共有的:
NM_CLICK 在控件中单击鼠标左按钮
NM_DBLCLK 在控件中双击鼠标左按钮
NM_RCLICK 在控件中单击鼠标左按钮
NM_RDBLCLK 在控件中双击鼠标右按钮
NM_RETURN 当控件具有输入焦点时按下 ENTER键
NM_SETFOCUS 控件得到输入焦点
NM_KILLFOCUS 控件失去输入焦点
NM_OUTOFMEMORY 没有足够的内存使控件完成操作
5.3常用控件根据控件的特性和功能,一般可将其分为三类,Windows公共控件、
ActiveX控件以及 MFC新增的一些控件等。
5.3常用控件
5.3.1静态控件和按钮
静态控件一个静态控件是用来显示一个字符串、框、矩形、图标、位图或增强的图元文件。它可以被用来作为标签、框或用来分隔其它的控件。一个静态控件一般不接收用户输入,也不产生通知消息。
在对话框编辑器的控件工具栏中,属于静态控件的有:静态文本 ( )、组框
( )和静态图片 ( )三种。
图 5.21 静态图片控件的 General和 Style属性对话框
5.3常用控件
按钮
(1)按键按钮通常可以立即产生某个动作,执行某个命令,常被称为命令按钮。两种风格:标准按键按钮和默认按键按钮。从外观上来说,默认按键按钮是在标准按键按钮的周围加上一个黑色边框,这个黑色边框表示该按钮已接受到键盘的输入焦点,只须按回车键就能按下该按钮。具体设定的方法是在按键按钮属性对话框的 Style页面中选中,Default button”项。
(2)单选按钮外形是在文本前有一个圆圈,被选中时,就标上一个黑点,可分为一般和自动两种类型。自动类型中,若选中同组按钮中的某个单选按钮,则其余的单选按钮的选中状态就会清除,保证了多个选项始终只有一个被选中。
(3)复选框外形是在文本前有一个空心方框,被选中时,复选框中就加上一个,?” 标记,三态复选框还有种处于灰框状态,表示,不确定,。设定成三态复选框的方法是在复选框属性对话框的 Style页面中选中,Tri-state”项。
图 5.22 按钮的不同类型三态复选框
5.3常用控件
按钮的消息常见的只有两个,BN_CLICKED和 BN_DOUBLE- CLICKED。
按钮选中操作
最常用的按钮操作是设置或获取一个或多个按钮的选中状态。 CButton类的成员函数 SetCheck和 GetCheck设置或获取指定按钮的选中状态,原型:
void SetCheck( int nCheck );
int GetCheck( ) const;
nCheck和 GetCheck函数返回的值可以是,0表示不选中,1表示选中,2表示不确定 (仅用于三态按钮 )。
对于多个单选按钮的选中状态的设置或获取,需要使用 CWnd类的成员函数
CheckRadioButton和 GetCheckedRadioButton,原型:
void CheckRadioButton( int nIDFirstButton,int nIDLastButton,int
nIDCheckButton );
int GetCheckedRadioButton( int nIDFirstButton,int nIDLastButton );
nIDFirstButton和 nIDLastButton指定这组单选按钮的第一个和最后一个按钮
ID值,nIDCheckButton指定要设置选中状态的按钮 ID值,函数
GetCheckedRadioButton返回被选中的按钮 ID值。
5.3常用控件
[例 Ex_Ctrls1] 用静态图片、单选按钮、复选框和按键按钮控件,设计界面。开始,所有单选按钮都是灰显的,不能选择,选中,允许,复选框后,所有单选按钮可以使用,选定一个单选框后,单击 [应用 ]。
(1)用 MFC AppWizard(exe)创建一个名为 Ex_CommCtrls的基于对话框的应用程序。在创建的第一步,将应用程序类型选择为 Dialog Based,按 [Finish]。自动显示出该程序的对话框资源模板内容。
(2)打开属性对话框将其标题改为,使用 Windows常用控件,。
(3)用编辑器为对话框添加如下表所示的一些控件。
(4)四个单选按钮的 Tab次序应连续,从 IDC_RADIO1到 IDC_RADIO4依次增加。
(5)按 Ctrl+W快捷键,切换到 Member Variables页面,在 Class name中选择
CEx_CommCtrlstDlg,选中复选框控件 ID号 IDC_CHECK1,双击鼠标或单击 Add
Variables按钮。
5.3常用控件
(6)切换到 ClassWizard的 Messsage Maps页面,为复选框 IDC_CHECK1和按钮
IDC_BUTTON1增加 BN_CLICKED的消息映射,添加代码:
void CEx_CommCtrlsDlg::OnCheck1()
{ UpdateData();
for (int i=0; i<4; i++)
GetDlgItem(IDC_RADIO1 + i)->EnableWindow(m_bEnabled);
}
void CEx_CommCtrlsDlg::OnButton1()
{ UpdateData();
if (!m_bEnabled) return;
int nID = GetCheckedRadioButton(IDC_RADIO1,IDC_RADIO4);
if (nID == IDC_RADIO1)
{ MessageBox("1"); }
if (nID == IDC_RADIO2)
{ MessageBox("2"); }
if (nID == IDC_RADIO3)
{ MessageBox("3"); }
if (nID == IDC_RADIO4)
{ MessageBox("4"); }
}
5.3常用控件
(7)定位到 CEx_CommCtrlsDlg::OnInitDialog函数体中,添加下列代码:
BOOL CEx_CommCtrlsDlg::OnInitDialog()
{ CDialog::OnInitDialog();
…
CheckRadioButton(IDC_RADIO1,IDC_RADIO4,IDC_RADIO1); //设置第一个单选按钮为选中
OnCheck1();
return TRUE; // return TRUE unless you set the focus to a control
}
(8)编译并运行。
图 5.23 按钮示例运行结果
5.3常用控件
5.3.2编辑框
编辑框的属性和风格图 5.24 编辑框的属性对话框
5.3常用控件
编辑框的基本操作
(1)口令设置默认的口令字符是,*”,应用程序可以用成员函数
CEdit::SetPasswordChar 来定义自己的口令字符,其函数原型如下:
void SetPasswordChar( TCHAR ch );
(2)选择文本用鼠标来选择文本的操作方法,在要选择的文本的一端按下鼠标左键并拖动鼠标,到另一端释放鼠标键。
用键盘来选择文本的方法,在按光标方向移动键的同时,按住 Shift键。
应用程序中可以通过编程选择文本,需要通过调用成员函数 CEdit::SetSel
来实现。与该函数相对应的还有 CEdit::GetSel和 CEdit::ReplaceSel,分别用来获取编辑框中前选择的开始和结束的位置以及替换被选择的文本。
(3)设置编辑框的页面边距设置编辑框的页面边距可以使文本在编辑框显示更具满意效果,应用程序可通过调用成员函数 CEdit::SetMargins来实现,函数原型:
void SetMargins( UINT nLeft,UINT nRight );
(4)剪帖板操作编辑框自动支持文本的复制、粘贴、剪切的键盘操作,对应的快捷健为
Ctrl+C,Ctrl+V和 Ctrl+X。若应用程序调用 CEdit::Undo函数时,还可撤消当前的操作,再调用一次该函数,则恢复刚才的操作。
5.3常用控件
(5)获取多行编辑框文本一种是使用 DDX/DDV,将编辑框控件所关联的变量类型选定为 CString后,
则不管多行编辑框的文本有多少都可用此变量来保存。这种方法不能单独获得多行编辑框中的某一行文本。
另一种方法是使用编辑框 CEdit类的相关成员函数来获取文本。例如,下面的代码将显示编辑框中第二行的文本内容:
char str[100];
if (m_Edit.GetLineCount()>=2) // 判断多行编辑框的文本是否有两行以上
{ int nChars;
nChars = m_Edit.LineLength(m_Edit.LineIndex(1)); // 获取第二行文本的字符个数
// 0表示第一行,1表示第二行,依次类推。 LineIndex用于将文本行转换成
// 能被 LineLength识别的索引
m_Edit.GetLine(1,str,nChars); // 获取第二行文本
str[nChars] = '\0';
MessageBox(str);
}
5.3常用控件
编辑框的通知消息
[例 Ex_Ctrls2] 使用静态文本、组框、编辑框以及按钮等控件,设计界面。
用户在,成绩 1”,,成绩 2”和,成绩 3”编辑框中输入成绩后,单击 [计算平均分 ]按钮,将显示出这三个成绩的平均分。
(1)打开前面的 Ex_CommCtrls。
(2)向应用程序中添加一个对话框资源,打开属性对话框将其标题改为,使用编辑框,,ID号改为 IDD_EDIT。
(3) 用编辑器为对话框添加如下表所示的一些控件。
(4)双击对话框模板或按 Ctrl+W快捷键,为对话框资源 IDD_EDIT创建一个对话框类 CEditDlg。
5.3常用控件
(5)打开 ClassWizard的 Member Variables标签,在 Class name中选择
CEditDlg,选中所需的控件 ID号,双击鼠标或单击 Add Variables按钮。依次为控件增加成员变量。
(6)切换到 ClassWizard的 Messsage Maps标签页,为 CEditDlg增加
WM_INITDIALOG的消息映射,并添加下列代码:
BOOL CEditDlg::OnInitDialog()
{ CDialog::OnInitDialog();
m_strAve = "0.00";
UpdateData(FALSE);// 将成员变量数据传给控件,并在控件中显示
return TRUE;
}
5.3常用控件
(7)用 ClassWziard为按钮 IDC_BUTTON1添加 BN_CLICKED的消息映射,并增加下列代码:
void CEditDlg::OnButton1()
{ UpdateData(); // 将控件显示的数据传给成员变量
double ave = (double)(m_nScore1+m_nScore2+m_nScore3)/3.0;
m_strAve.Format("%6.2f",ave);
UpdateData(FALSE); // 将成员变量数据传给控件并显示
}
(8)定位到 CEx_CommCtrlsDlg::OnButton1函数处,修改代码如下:
if (nID == IDC_RADIO1) {
CEditDlg dlg;
dlg.DoModal();
}
(9)在 Ex_CommCtrlsDlg.cpp文件的开始处,增加包含 CEditDlg的头文件。
#include,EditDlg.h”
(10)编译运行并测试。
作业
1.P375:1,3,6,8,10
2.P412:实验 9
5.3常用控件
5.3.3列表框
列表框的风格图 5.25 列表框的属性对话框
5.3常用控件
列表框的基本操作
(1)添加列表项列表框创建时是一个空的列表,需要添加或插入一些列表项。 CListBox类成员函数 AddString 和 InsertString用来向列表框增加列表项,原型:
int AddString( LPCTSTR lpszItem );
int InsertString( int nIndex,LPCTSTR lpszItem );
CListBox的 SetItemData和 SetItemDataPtr能使数据和某个列表项关联起来。
int SetItemData( int nIndex,DWORD dwItemData );
int SetItemDataPtr( int nIndex,void* pData );
(2)删除列表项
CListBox类成员函数 DeleteString和 ResetContent分别用来删除指定的列表项和清除列表框所有项目。它们的函数原型如下:
int DeleteString( UINT nIndex ); // nIndex指定要删除的列表项的索引
void ResetContent( );
若在添加列表项时使用 SetItemDataPtr函数,不要忘记在进行删除操作时及时将关联数据所占的内存空间释放出来。
5.3常用控件
(3)查找列表项
CListBox类成员函数 FindString 和 FindStringExact分别用来在列表框中查找所匹配的列表项,其中 FindStringExact的查找精度最高。
int FindString( int nStartAfter,LPCTSTR lpszItem ) const;
int FindStringExact( int nIndexStart,LPCTSTR lpszFind ) const;
lpszFind和 lpszItem指定要查找的列表项文本,nStartAfter和 nIndexStart指定查找的开始位置,若为 -1,则从头至尾查找。查到后,这两个函数都将返回所匹配列表项的索引,否则返回 LB_ERR。
(4)列表框的单项选择当选中列表框中某个列表项,可以使用 CListBox::GetCurSel来获取这个结果,
与该函数相对应的 CListBox::SetCurSel 函数是用来设定某个列表项呈选中状态 (高亮显示 )。
int GetCurSel( ) const; // 返回当前选择项的索引
int SetCurSel( int nSelect );
nSelect指定要设置的列表项索引,错误时这两个函数都将返回 LB_ERR。
若要获取某个列表项的字符串,可使用下列函数:
int GetText( int nIndex,LPTSTR lpszBuffer ) const;
void GetText( int nIndex,CString& rString ) const;
nIndex指定列表项索引,lpszBuffer 和 rString是用来存放列表项文本。
5.3常用控件
(5)列表框的多项选择在列表框的 Style属性对话框中选中多选 (Multiple)或扩展多选 (Extended)类型后,就可以在列表框中进行多项选择。要想获得选中的多个选项,通过需要用 ClassWizrd映射 LBN_SELCHANGE消息,添加类似代码:
void CListBoxDlg::OnSelchangeList1()
{ int nCount = m_list.GetSelCount(); // 获取用户选中的项数
if (nCount != LB_ERR)
{ int *buffer = new int[nCount]; // 开辟缓冲区
m_list.GetSelItems(nCount,buffer);
CString allStr,str;
allStr.Empty(); // 字符串清空
for (int i=0; i<nCount; i++)
{ m_list.GetText(buffer[i],str);
allStr = allStr +,[” + str +,]”;
}
delete []buffer; // 释放内存
// MessageBox(allStr); // 处理获得的文本
}
}
5.3常用控件
列表框的通知消息
[例 Ex_Ctrls3] 将一个 SCORE结构 (含有三门成绩的数据成员 )数据和列表框中每一个学生姓名列表关联起来。用户单击 [添加记录 ]按钮时,学生成绩记录中的,姓名,被添加在列表框中,该学生的成绩与该列表项关联。单击
[删除记录 ]时,列表框中当前选择项被删除,相关联的数据所占的内容空间被释放。任何时候选中列表框中某个学生,相应的记录数据都被显示出来。
(1)打开前面创建的基于对话框应用程序程序项目 Ex_CommCtrls。
(2)向应用程序中添加一个对话框资源 IDD_LISTBOX,标题定为,使用列表框,,用 ClassWizard为此对话框类定义为 CListBoxDlg。
(3)删除原来的 Cancel按钮,用编辑器为对话框添加如下表所示的控件。
5.3常用控件
(4)打开 ClassWizard的 Member Variables页面,在 Class name中选择 CListBoxDlg,选中所需的控件 ID号,双击鼠标或单击 Add Variables按钮。
(5)切换到 ClassWizard的 Messsage Maps标签页,为按钮 IDC_DATA_ADD添加
BN_CLICKED的消息映射,增加代码:
void CListBoxDlg::OnDataAdd()
{ UpdateData(TRUE);
if (m_strName.IsEmpty()) // 判断 m_strName是否为空
{ MessageBox("姓名不能为空! ");
return; }
m_strName.TrimLeft(); // 裁剪 m_strName左边的空格
m_strName.TrimRight(); // 裁剪 m_strName右边的空格
if ((m_List.FindString(-1,m_strName)) != LB_ERR)
{ MessageBox("列表框中已有相同姓名,不能添加! ");
return; }
int nIndex = m_List.AddString(m_strName); // 向列表框添加学生姓名
// 将该学生成绩与新增的列表项关联起来
SCORE data;
data.score1 = m_nScore1;
data.score2 = m_nScore2;
data.score3 = m_nScore3;
m_List.SetItemDataPtr(nIndex,new SCORE(data));
}
5.3常用控件
(6)用 ClassWizard为按钮 IDC_DATA_DEL添加 BN_CLICKED的消息映射,增加代码:
void CListBoxDlg::OnDataDel()
{ int nIndex = m_List.GetCurSel(); // 获得当前选择项的索引
if (nIndex != LB_ERR)
{ m_List.DeleteString(nIndex); // 删除当前选择项
m_strName.Empty();
m_nScore1 = m_nScore2 = m_nScore3 = 0;
UpdateData(FALSE);
}
else MessageBox("当前没有选择项或列表框操作失败! ");
}
(7)用 ClassWizard为按钮 IDC_LIST1添加 LBN_SELCHANGE的消息映射,增加代码:
void CListBoxDlg::OnSelchangeList1()
{ int nIndex = m_List.GetCurSel();
if (nIndex != LB_ERR)
{ m_List.GetText(nIndex,m_strName);
SCORE *data=(SCORE *)m_List.GetItemDataPtr(nIndex);
m_nScore1 = data->score1;
m_nScore2 = data->score2;
m_nScore3 = data->score3;
UpdateData(FALSE);
}
}
5.3常用控件
(8)用 ClassWizard为对话框添加 WM_DESTROY的消息映射,增加代码:
void CListBoxDlg::OnDestroy() // 此消息是当对话框关闭时发送的
{ for (int nIndex = m_List.GetCount()-1; nIndex>=0; nIndex--)
{// 删除所有与列表项相关联的 SCORE结构数据,并释放内存
delete (SCORE *)m_List.GetItemDataPtr(nIndex);
}
CDialog::OnDestroy(); // 关闭对话框
}
对话框被清除时发送 WM_DESTROY消息。用户在此消息的映射函数中添加一些对象删除代码,以便在对话框清除前有效地释放内存空间。
5.3常用控件
(9)打开 ListBoxDlg.h源文件,在类 CListBoxDlg定义的 public处添加下列代码:
public:
struct SCORE
{ int score1;
int score2;
int score3;
};
(10) 定位到 CEx_CommCtrlsDlg::OnButton1函数处,修改代码如下:
if (nID == IDC_RADIO2)
{ CListBoxDlg dlg;
dlg.DoModal();
}
(11)在 Ex_CommCtrlsDlg.cpp文件的开始处,增加包含 CListBoxDlg的头文件。
#include,ListBoxDlg.h”
(12) 编译运行并测试。
5.3常用控件
5.3.4组合框
组合框的风格及类型图 5.27 组合框的属性对话框
5.3常用控件
组合框常见操作组合框的操作大致分为两类,一类是对组合框中的列表框进行操作,另一类是对组合框中的编辑框进行操作。这些操作都可以调用 CComboBox成员函数来实现。
组合框的通知消息绘图时还需要下列一些技巧:
需要更新或重新绘制窗口的外观时,应用程序就会发送 WM_PAINT消息。用
ClassWizard在对话框中映射 WM_PAINT消息的目的是执行绘图代码。
防止用系统默认的颜色向对话框进行重复绘制,须调用 UpdateWindow函数。
UpdateWindow是 CWnd的无参数的成员函数,目的是绕过系统的消息列队,直接发送或停止发送 WM_PAINT消息。窗口没有需要更新的区域时,就停止发送。绘制完图形时,没有 WM_PAINT消息的发送,系统不会用默认的颜色对窗口进行重复绘制。
如果对话框中的任何部分变为无效时,对话框的 OnPaint函数都会自动调用。可以通过调用 Invalidate函数来通知系统此时的窗口状态已变为无效,强制系统调用
WM_PAINT消息函数 OnPaint重新绘制。
5.3常用控件
[例 Ex_Ctrls4] 根据用户从组合框中选择的填充样式,在对话框中绘制一个矩形区域,如图。
(1)打 开前面创建的基于对话框应用程序程序项目 Ex_CommCtrls。
(2)向应用程序中添加一个对话框资源 IDD_COMBO,标题定为,使用组合框,,用 ClassWizard为此对话框类定义为 CComboDlg。
(3) 删除原来的 Cancel按钮,用编辑器为对话框添加控件。
图 5.28 组合框示例运行结果 图 5.29 组合框控件布局
5.3常用控件
(4)打开 ClassWizard的 Member Variables标签,为组合框 IDC_PATTERN增加成员变量 m_Pattern,其类型为 Control类的 CComboBox 。
(5)为 CComboDlg类添加一个 int类型的成员变量 m_nDrawPattern。
(6)切换到 ClassWizard的 Messsage Maps标签页,为组合框 IDC_PATTERN
添加 CBN_SELCHANGE(组合框中的当前选项发生改变 )的消息映射,并增加下列代码:
void CComboDlg::OnSelchangePattern()
{ int nIndex = m_Pattern.GetCurSel();// 获得当前选项的索引
if (nIndex != CB_ERR)
{ m_nDrawPattern = m_Pattern.GetItemData(nIndex);
// 获得与当前选项相关联的数据
Invalidate(); // 强制系统调用 OnPaint函数重新绘制
}
}
5.3常用控件
(7)用 ClassWizard为对话框添加 WM_PAINT的消息映射,并增加下列代码:
void CComboDlg::OnPaint()
{ CPaintDC dc(this); // device context for painting(绘图所必须的设备环境 )
CWnd* pWnd = GetDlgItem(IDC_DRAW);// 获得控件 IDC_DRAW的窗口指针
pWnd->UpdateWindow(); // 避免系统自动重绘
CDC* pDC = pWnd->GetDC(); // 获得所需要的绘图设备环境
CBrush drawBrush; // 定义一个画刷
drawBrush.CreateHatchBrush(m_nDrawPattern,RGB(0,0,0));// 创建画刷
CBrush* pOldBrush = pDC->SelectObject(&drawBrush);
// 将画刷选入当前设备环境中
CRect rcClient; // 定义一个 CRect变量
pWnd->GetClientRect(rcClient); // 获得窗口客户区大小
pDC->Rectangle(rcClient); // 用当前画刷绘制一个矩形区域
pDC->SelectObject(pOldBrush); // 恢复设备环境原来的画刷设置
}
5.3常用控件
(8)用 ClassWizard为对话框添加 WM_INITDIALOG的消息映射,增加代码:
BOOL CComboDlg::OnInitDialog()
{ CDialog::OnInitDialog();
CString str[6] = {"水平线 ","竖直线 ","向下斜线 ","向上斜线 ","十字线
","交叉线 "};
int nIndex;
for (int i=0; i<6; i++)
{
nIndex = m_Pattern.AddString(str[i]);
m_Pattern.SetItemData(nIndex,i);
}
m_Pattern.SetCurSel(0);
m_nDrawPattern = 0;
return TRUE;
}
5.3常用控件
(9)定位到 CEx_CommCtrlsDlg::OnButton1函数处,修改代码如下:
if (nID == IDC_RADIO3)
{
CComboDlg dlg;
dlg.DoModal();
}
(10)在 Ex_CommCtrlsDlg.cpp文件的开始处,增加包含 CComboDlg的头文件。
#include,ComboDlg.h”
(11)编译运行并测试。
5.3常用控件
5.3.5滚动条和进展条
滚动条
(1)滚动条的基本操作
在 MFC的 CScrollBar类中,函数 SetScrollRange是用来设置滚动条的滚动范围的,其原型如下:
SetScrollRange( int nMinPos,int nMaxPos,BOOL bRedraw = TRUE );
在 CScrollBar类中,设置滚动块位置操作是由 SetScrollPos函数来完成的,其原型如下:
int SetScrollPos( int nPos,BOOL bRedraw = TRUE );
与 SetScrollRange 和 SetScrollPos相对应的两个函数是分别用来获取滚动条的当前范围以及当前滚动位置:
void GetScrollRange( LPINT lpMinPos,LPINT lpMaxPos ) ;
int GetScrollPos();
需要说明的是:在 CScrollBar类的成员函数中,还可以用 SetScrollInfo和
GetScrollInfo来代替上面提到的四个函数。与前面的函数相比,使用
SetScrollInfo函数还能使滚动块的大小随内容的多少而改变。
图 5.30 滚动条外观滚动箭头按钮滚动条 滚动块
5.3常用控件
(2) WM_HSCROLL或 WM_VSCROLL消息滚动条进行操作时,会向父窗口发送 WM_HSCROLL或 WM_VSCROLL消息。
通过 ClassWziard在其对话框中进行映射,产生相应的消息映射函数
OnHScroll和 OnVScroll,函数原型:
afx_msg void OnHScroll( UINT nSBCode,UINT nPos,CScrollBar* pScrollBar );
afx_msg void OnVScroll( UINT nSBCode,UINT nPos,CScrollBar* pScrollBar );
SB_LINELEFT SB_LINERIGHT
SB_PAGELEFT SB_PAGERIGHT
图 5.31 滚动条通知代码与位置的关系
SB_LINEUP
SB_PAGEUP
SB_THUMBTRACK和
SB_THUMBPOSITION
SB_PAGEDOWN
SB_LINEDOWN
5.3常用控件
进展条
(1)进展条的风格打开进展条的属性对话框。 Border指定进展条是否有边框,Vertical指定进展是水平还是垂直的。 Smooth表示平滑地填充进展条。
(2)进展条的基本操作基本操作:设置范围、当前位置、增量等。通过相关的 CProgressCtrl类成员函数实现。
int SetPos( int nPos );
int GetPos();
这两个函数分别用来设置和获取进展条的当前位置。
void SetRange( short nLower,short nUpper );
void SetRange32(int nLower,int nUpper );
void GetRange( int & nLower,int& nUpper );
分别用来设置和获取进展条范围的上限和下限值。
int SetStep( int nStep );
该函数用来设置进展条的步长并返回原来的步长。
int StepIt();
该函数将当前位置向前移动一个步长并重画进展条以反映新的位置。
5.3常用控件
5.3.6旋转按钮控件和滑动条
旋转按钮控件
(1)旋转按钮控件常用的风格图 5.35 旋转按钮控件属性对话框
5.3常用控件
(2)旋转按钮控件的基本操作成员函数 SetBase是用来设置其基数的,函数的原型如下:
int SetBase( int nBase );
成员函数 SetPos和 SetRange设置旋转按钮控件的当前位置和范围,它们的函数原型如下:
int SetPos( int nPos );
void SetRange( int nLower,int nUpper );
成员函数 SetAccel和 GetAccel用来设置和获取旋转按钮控件的加速度。其中函数 SetAccel的原型如下:
BOOL SetAccel( int nAccel,UDACCEL* pAccel );
参数 nAccel表示由 pAccel指定的 UDACCEL结构的数目。 pAccel指向一个
UDACCEL结构数组的指针,该数组包含了加速信息,其结构如下:
typedef struct {
UINT nSec; // 位置改变前所等待的秒数。
UINT nInc; // 位置增量。
}UDACCEL,FAR *LPUDACCEL;
(3)旋转按钮控件的通知消息旋转按钮控件的通知消息只有一个,UDN_DELTAPOS,它是当控件的当前数值将要改变时向其父窗口发送的。
5.3常用控件
滑动条
(1)滑动条的风格图 5.36 带刻度线的滑动条滑动块刻度线图 5.37 滑动条属性对话框
5.3常用控件
(2)滑动条的基本操作
成员函数 SetPos和 SetRange用来设置滑动条的位置和范围,原型如下:
void SetPos( int nPos );
void SetRange( int nMin,int nMax,BOOL bRedraw = FALSE );
成员函数 SetTic用来设置滑动条控件中的一个刻度线的位置。函数成功调用后返回非零值;否则返回 0。函数原型如下:
BOOL SetTic( int nTic );
成员函数 SetTicFreq设置显示在滑动条中的刻度线的疏密程度。原型如下:
void SetTicFreq( int nFreq );
成员函数 ClearTics用来从滑动条控件中删除当前的刻度线。函数原型如下:
void ClearTics( BOOL bRedraw = FALSE );
成员函数 SetSelection用来设置一个滑动条控件中当前选择的开始和结束位置。其函数原型如下:
void SetSelection( int nMin,int nMax );
(3)滑动条的通知消息消息代码都来自于 WM_HSCROLL或 WM_VSCROLL消息。
5.3常用控件
[例 Ex_Ctrls5]用滚动条、滑动条和旋转按钮控件分别来调整 RGB的三个颜色分量,根据指定的颜色填充一个矩形区域。
(1)打开前面创建的基于对话框应用程序程序项目 Ex_CommCtrls。
(2)向应用程序中添加一个对话框资源 IDD_SCROLL,标题定为,使用滚动条、
旋转按钮控件和滑动条,,用 ClassWizard为此对话框类定义为 CScrollDlg。
(3)删除原来的 Cancel按钮,用编辑器为对话框添加如下表所示的一些控件。
5.3常用控件
(4)打开 ClassWizard的 Member Variables标签,在 Class name中选择
CScrollDlg,选中所需的控件 ID号,双击鼠标或单击 Add Variables按钮。依次为下列控件增加成员变量。
(5)切换到 ClassWizard的 Messsage Maps标签页,为编辑框 IDC_EDIT1、
IDC_EDIT2和 IDC_EDIT3添加 EN_CHANGE的消息映射,使用它们的消息处理函数名都设为 OnChangeEdit,并增加下列代码:
void CScrollDlg::OnChangeEdit()
{ if (!m_bEditOK) return;
UpdateData();
m_Scroll.SetScrollPos(m_RValue);
m_Slider.SetPos(m_GValue);
Draw();
}
5.3常用控件
(6)用 ClassWizard为对话框添加 WM_PAINT的消息映射,增加代码:
void CScrollDlg::OnPaint()
{ CPaintDC dc(this); // device context for painting
CWnd* pWnd=GetDlgItem(IDC_DRAW);
pWnd->UpdateWindow();
Draw();
}
(7)用 ClassWizard为对话框添加 WM_INITDIALOG的消息映射,增加代码:
BOOL CScrollDlg::OnInitDialog()
{ CDialog::OnInitDialog();
// 设置滚动条和滑动条的范围和当前位置
m_Scroll.SetScrollRange(0,255);
m_Scroll.SetScrollPos(m_RValue);
m_Slider.SetRange(0,255);
m_Slider.SetPos(m_GValue);
// 设置旋转按钮的范围
m_Spin.SetRange(0,255);
UpdateData(FALSE); // 将数据传给控件
m_bEditOK = TRUE;
return TRUE;
}
5.3常用控件
(8)用 ClassWizard为对话框添加 WM_HSCROLL的消息映射,增加代码:
void CScrollDlg::OnHScroll(UINT nSBCode,UINT nPos,CScrollBar* pScrollBar)
{ int nID = pScrollBar->GetDlgCtrlID();
if (nID == IDC_SLIDER1) // 是滑动条产生水平滚动消息
{ m_GValue = m_Slider.GetPos();// 获得滑动条当前的位置 }
if (nID == IDC_SCROLLBAR1) // 是滚动条条产生水平滚动消息
{ switch(nSBCode)
{ case SB_LINELEFT:m_RValue--; break;
case SB_LINERIGHT:m_RValue++; break;
case SB_PAGELEFT,m_RValue -= 10; break;
case SB_PAGERIGHT:m_RValue += 10; break;
case SB_THUMBTRACK:m_RValue = nPos;break;
}
if (m_RValue<0) m_RValue = 0;
if (m_RValue>255) m_RValue = 255;
m_Scroll.SetScrollPos(m_RValue);
}
UpdateData(FALSE);
Draw();
CDialog::OnHScroll(nSBCode,nPos,pScrollBar);
}
5.3常用控件
(9)将项目工作区切换到 ClassView页面,用鼠标右击,CScrollDlg”项,在弹出的快捷菜单中选中,Add Member Function”,将要增加的函数名设为
Draw,函数类型为 void,并添加下列代码:
void CScrollDlg::Draw()
{ CWnd* pWnd = GetDlgItem(IDC_DRAW);
CDC* pDC = pWnd->GetDC(); // 获得窗口当前的设备环境指针
CBrush drawBrush; // 定义画刷变量
drawBrush.CreateSolidBrush(RGB(m_RValue,m_GValue,m_BValue));
// 创建一个填充色画刷。
// 颜色分量转换成一个 32位的 RGB颜色值
CBrush* pOldBrush = pDC->SelectObject(&drawBrush);
CRect rcClient;
pWnd->GetClientRect(rcClient);
pDC->Rectangle(rcClient);
pDC->SelectObject(pOldBrush);
}
5.3常用控件
(10)为 CScrollDlg类添加一个 BOOL型成员变量 m_bEditOK,并在其构造函数中将其初值设为 FALSE。
(11)定位到 CEx_CommCtrlsDlg::OnButton1函数处,修改代码如下:
if (nID == IDC_RADIO4)
{ CScrollDlg dlg;
dlg.DoModal();
}
(12)在 Ex_CommCtrlsDlg.cpp文件的开始处,增加包含 CScrollDlg的头文件。
#include,ScrollDlg.h”
(13)编译运行并测试。
在同时使用编辑框和旋转按钮控件时,有时会出现运行错误。为了解决这个问题,本例使用一个办法,即使用一个 BOOL型成员变量 m_bEditOK作为控制条件,使得所有初始化代码 (包括设置旋转控件范围 )执行后,才允许编辑框工作。
由于滚动条和滑动条等许多控件都能产生 WM_HSCROLL或 WM_VSCROLL消息,因此当它们是处在同一方向 (水平或垂直 )时,就需要添加相应代码判断消息是谁产生的。
由于滚动条中间的滚动块在默认时是不会停止在用户操作的位置处的,因此需要调用 SetScrollPos函数来进行相应位置的设定。
5.3常用控件
5.3.7图像列表和标签控件
图像列表控件
(1)图像列表的创建由于 Create函数的重载很多,故这里给出最常用的一个原型:
BOOL Create( int cx,int cy,UINT nFlags,int nInitial,int nGrow );
(2)图像列表的基本操作常见的图像列表的基本操作有:增加、删除和绘制等,成员函数:
int Add( CBitmap* pbmImage,CBitmap* pbmMask );
int Add( CBitmap* pbmImage,COLORREF crMask );
int Add( HICON hIcon );
BOOL Remove( int nImage );
该函数用来从图像列表中删除一个由 nImage指定的图像,
BOOL Draw( CDC* pdc,int nImage,POINT pt,UINT nStyle );
该函数用来在由 pt指定的位置处绘制一个图像。
HICON ExtractIcon( int nImage );
该函数用来将 nImage指定的图像扩展为图标。
COLORREF SetBkColor( COLORREF cr );
该函数用来设置图像列表的背景色,
5.3常用控件
标签控件
(1)标签控件的风格图 5.39 标签控件属性对话框
5.3常用控件
(2)标签控件的基本操作
GetItemRect是用来获取标签的边界大小,原型如下:
CSize SetItemSize( CSize size );
void SetPadding( CSize size );
int SetMinTabWidth( int cx );
BOOL GetItemRect( int nItem,LPRECT lpRect ) const;
成员函数 InsertItem,DeleteItem表示在一个标签控件中插入、删除某一标签项,
DeleteAllItems删除所有的项。原型如下:
BOOL InsertItem( int nItem,LPCTSTR lpszItem );
BOOL InsertItem( int nItem,LPCTSTR lpszItem,int nImage);
BOOL DeleteItem( int nItem );
BOOL DeleteAllItems( );
标签控件中使用图像列表时,必须调用 CTabCtrl::SetImageList函数来指定一个已创建的图像列表。函数原型如下:
CImageList * SetImageList( CImageList * pImageList );
成员函数 SetCurSel和 GetCurSel用来设置和获取当前选择的标签项,原型如下:
int SetCurSel( int nItem );
int GetCurSel( ) const;
成员函数 DeselectAll用来重新设置一个标签控件中的项,清除任何被按下的项,函数
HighlightItem是使某一个标签项处于高亮状态。原型如下:
void DeselectAll( BOOL fExcludeFocus );
BOOL HighlightItem( int idItem,BOOL fHighlight = TRUE );
(3)标签控件的通知消息
5.3常用控件
[例 Ex_Ctrls6] 使用无模式对话框来构造某个标签页面,一开始将所有的标签页面创建好,然后根据所选择的当前标签选项决定哪个页面需要显示,哪个页面需要隐藏和禁用。
(1)用 MFC AppWizard(exe)创建一个基于对话框的应用程序项目 Ex_TabCtrl。
(2)打开属性对话框将对话框标题改为,使用标签控件,。
(3) 添加一个默认标签控件 IDC_TAB1,调整其大小和布局。
(4)按 Ctrl+W,打开 ClassWizard对话框,切换到 Member Variables页面,在
Class name中选择 CEx_TabCtrlDlg,选中标签控件 ID号 IDC_TAB1,双击鼠标或单击 Add Variables按钮,为其添加一个 CTabCtrl类型的成员变量 m_Tab。
(5)添加三个对话框资源 IDD_DIALOG1,IDD_DIALOG2和 IDD_DIALOG3,并用 ClassWizard依次为此三个对话框类定义为 CTab1Dlg,CTab2Dlg和 CTab3Dlg。
5.3常用控件
(6)将上述三个对话框的属性设为 Child Style和 None Border(其他默认 ),且将对话框尽量缩小,如图。
图 5.41 设置对话框属性
5.3常用控件
(7) 为三个对话框添加如下表所示的一些控件。
5.3常用控件
(8)在 ClassView中的 CEx_TabCtrlDlg类名处右击鼠键,从弹出的快捷菜单中选择 Add Member Variables,添加下列数据成员:
public:
CTab1Dlg *m_pTab1Dlg;
CTab2Dlg *m_pTab2Dlg;
CTab3Dlg *m_pTab3Dlg;
CImageList m_ImageList;
(9)打开 Ex_TabCtrlDlg.h文件,在 class CEx_TabCtrlDlg前添加下列头文件:
#include "Tab1Dlg.h"
#include "Tab2Dlg.h"
#include "Tab3Dlg.h"
5.3常用控件
(10)在 ClassView中的 CEx_TabCtrlDlg类名处右击鼠键,选择 Add Member Function,添加成员函数 SetDlgState和 DoTab,并增加下列代码:
void CEx_TabCtrlDlg::SetDlgState(CWnd *pWnd,BOOL bShow)
{ pWnd->EnableWindow(bShow);
if (bShow)
{ pWnd->ShowWindow(SW_SHOW);
pWnd->CenterWindow(); // 居中显示
}
else pWnd->ShowWindow(SW_HIDE);
}
void CEx_TabCtrlDlg::DoTab(int nTab)
{ if (nTab>2) nTab = 2; // 确定 nTab值不能超过范围
if (nTab<0) nTab = 0;
BOOL bTab[3];
bTab[0] = bTab[1] = bTab[2] = FALSE;
bTab[nTab] = TRUE;
// 切换对话框的显示和隐藏
SetDlgState(m_pTab1Dlg,bTab[0]);
SetDlgState(m_pTab2Dlg,bTab[1]);
SetDlgState(m_pTab3Dlg,bTab[2]);
}
5.3常用控件
(11)用 ClassWizard为 IDC_TAB1映射 TCN_SELCHANGE消息,添加代码:
void CEx_TabCtrlDlg::OnSelchangeTab1(NMHDR* pNMHDR,LRESULT*
pResult)
{ int nSelect = m_Tab.GetCurSel();
if (nSelect >= 0)
DoTab(nSelect);
*pResult = 0;
}
(12)按下 Ctrl+R快捷键,单击 Import按钮,从外部磁盘中调入三个图标文件,并取默认的图标 ID号 IDI_ICON1,IDI_ICON2和 IDI_ICON3。
5.3常用控件
(13)在 CEx_TabCtrlDlg::OnInitDialog中添加下列代码:
BOOL CEx_TabCtrlDlg::OnInitDialog()
{ CDialog::OnInitDialog();
……
m_pTab1Dlg = new CTab1Dlg(); // 为无模式对话框分配空间
m_pTab2Dlg = new CTab2Dlg();
m_pTab3Dlg = new CTab3Dlg();
m_pTab1Dlg->Create(IDD_DIALOG1,&m_Tab);
m_pTab2Dlg->Create(IDD_DIALOG2,&m_Tab);
m_pTab3Dlg->Create(IDD_DIALOG3,&m_Tab);
m_ImageList.Create(16,16,ILC_COLOR|ILC_MASK,3,0); // 创建图像列表
m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON1));
m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON2));
m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON3));
m_Tab.SetImageList(&m_ImageList); // 设置 TAB控件所使用的图像列表
m_Tab.InsertItem(0,"基本信息 ",0);
m_Tab.InsertItem(1,"成绩 ",1);
m_Tab.InsertItem(2,"备注 ",2);
m_Tab.SetMinTabWidth(80); // 设置标签项的最小宽度
m_Tab.SetPadding(CSize(12,3)); // 设置标签项和图标周围的间隔
m_Tab.SetCurSel(0);
DoTab(0);
return TRUE;
}
5.3常用控件
(14)用 ClassWizard为 CEx_TabCtrlDlg类添加 WM_DESTROY的消息映射,
CEx_TabCtrlDlg对话框退出时,删除分配给无模式对话框的内存。代码:
void CEx_TabCtrlDlg::OnDestroy()
{ CDialog::OnDestroy();
if (m_pTab1Dlg) delete m_pTab1Dlg;
if (m_pTab2Dlg) delete m_pTab2Dlg;
if (m_pTab3Dlg) delete m_pTab3Dlg;
}
(15)用 ClassWizard为 CTab1lDlg类添加 WM_INITDIALOG消息的映射,增加下列代码:
BOOL CTab1Dlg::OnInitDialog()
{ CDialog::OnInitDialog();
CheckRadioButton(IDC_RADIO_MAN_1,IDC_RADIO_WOMAN_1,IDC
_RADIO_MAN_1);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION,OCX Property Pages should return FALSE
}
(16) 编译并运行。
5.3常用控件需要说明的是:
标签页面的切换可能还不止一种方法。例如,可以先将各个页面的控件与标签控件一起事先全部地添加到对话框模板中,然后再根据标签控件的当前选项确定控件的显示和隐藏,从而达到切换的效果。
在标签页面控件操作过程中,当按 Enter键或 Esc键,该页面的对话框就会退出,标签页面变成了一个空白,影响交互效果。解决这个问题的一个办法是在各页面的对话框中屏蔽掉 Enter键和 Esc键的按键消息,它是通过添加 PreTranslateMessage函数的重载来实现的,如下面的代码:
BOOL CTab1Dlg::PreTranslateMessage(MSG* pMsg)
{ if (pMsg->message == WM_KEYDOWN)
{ if (pMsg->wParam == VK_RETURN) return TRUE;
if (pMsg->wParam == VK_ESCAPE) return TRUE; }
return CDialog::PreTranslateMessage(pMsg);
}
5.4通用对话框和消息对话框
5.4.1通用对话框
Windows提供了一组标准用户界面对话框,它们都有相应的 MFC库中的类来支持。所有这些通用对话框类都是从一个公共的基类 CCommonDialog派生而来。表列出了这些通用对话框。
5.4通用对话框和消息对话框
5.4.2消息对话框是最简单的一类对话框,只是用来显示信息的。 MFC类库中提供相应的函数实现这样的功能,只要在程序任何地方调用它们。函数原型:
int AfxMessageBox( LPCTSTR lpszText,UINT nType = MB_OK,UINT
nIDHelp = 0 );
int MessageBox( LPCTSTR lpszText,LPCTSTR lpszCaption = NULL,UINT
nType = MB_OK );
作业
1.P375:12
2.P420:实验 10
5.1 对话框的使用
5.2 控件的创建和使用方法作业 1
5.3 常用控件
5.4 通用对话框和消息对话框作业 2
5.1对话框的使用
5.1.1模式和无模式对话框
模式对话框
指当对话框被弹出,用户必须在对话框中作出相应的操作,在退出对话框之前,对话框所在的应用程序不能继续执行。
无模式对话框
指当对话框被弹出后,一直保留在屏幕上,可继续在对话框所在的应用程序中进行其它操作;需要使用对话框时,单击对话框所在的区域即可激活。
在创建和退出对话框窗口时的方式不同,
创建时,模式对话框由系统自动分配内存空间,对话框退出时,对话框对象自动删除。无模式对话框需要来指定内存,退出时还需删除对话框对象。
退出时,两种对话框所使用的终止函数不一样。模式对话框通过调用
CDialog:,EndDialog来终止,无模式对话框则是调用
CWnd::DestroyWindow来终止。
函数 CDiaolog::OnOK和 CDiaolog::OnCancel是调用 EndDialog的,因此无模式对话框必须用 DestroyWindow来重载 OnOK 和 OnCancel两个函数。
需要正确删除表示对话框的对象。对模式对话框,在创建函数返回后即可删除对象。无模式对话框不是同步的,在创建函数调用后立即返回,因而不知道何时删除对象,但可以通过重载 CWnd::PostNcDestroy函数并执行清除操作。
5.1对话框的使用
5.1.2使用对话框编辑器
打开对话框编辑器将项目工作区窗口切换到 ResourceView页面,双击 Dialog目录下任意一个对话框 ID。或者,选择,Insert”?“Resource”菜单命令 (或按快捷键 Ctrl+R),
选择 Dialog项,单击 New。
图 5.1 打开的对话框编辑器控件工具栏布局工具栏默认对话框资源 ID号默认对话框模板基准线标尺
5.1对话框的使用在对话框中添加和编辑控件
(1)控件添加的方法在对话框中添加一个控件的方法有下列几种:
在控件工具栏中单击某控件,鼠标箭头在对话框内变成,十,字形状;在对话框指定位置单击鼠标左键,再拖动选择框可改变控件的大小和位置。
在控件工具栏中单击某控件,鼠标箭头对话框内变成,十,字形状;在指定位置处单击鼠标左键不放,拖动鼠标至满意位置,释放鼠标键。
用鼠标左键点中控件工具栏中的某控件,并按住鼠标键不放;在移动鼠标到对话框的指定位置的过程中,会看到一个虚线框,下面带有该控件的标记;释放鼠标键。
控件的选择静态文本组框复选框组合框水平滚动条旋转按钮滑动条列表视图标签复合编辑月历用户 定制 工具静态图片编辑框按钮单选框列表框垂直滚动条进展条热键树形视图动画日期选择
IP地址组合框的扩展图 5.2 控件工具栏和各按钮含义
5.1对话框的使用
(2)单个控件的选取
鼠标选取保证选择按钮 ( )是被选中的,移动鼠标指针至指定的控件上,单击鼠标左键。
助记符选取在相应的控件上右击。选择,Properties”菜单项,对话框中的,Caption”框是用来输入控件的标题,在标题中的某个字母之前键入,&”符号,则该字母就是此控件的助记符。
Tab键选取利用 Tab键,可在对话框内的控件中进行选择。每按一次 Tab键依次选取对话框中的下一个控件,若按住 Shift键,再单击 Tab键则选取上一个控件。
(3)多个控件的选取
在对话框内按住鼠标左键不放,拖出一个大的虚框,释放鼠标,则被该虚框所包围的控件都将被选取。
先按住 Shift键不放,用鼠标选取控件,直到所需要的多个控件选取之后再释放 Shift键。若在选取时,对已选取的控件再选取一下,则该控件取消选取。
一旦单个控件被选取后,其四周由选择框包围着,选择框上还有几个 (通常是八个 )蓝色实心小方块,拖动它可改变控件的大小,如图。
多个控件被选取后,其中只有一个控件的选择框有几个蓝色实心小方块,这个控件称为主要控件,而其他控件的选择框的小方块是空心的。如图。
(b)
图 5.3 单个控件和多个控件的选择框
(a)
5.1对话框的使用
(4)控件的移动、删除和复制当单个控件或多个控件被选取后,按方向键或用鼠标拖动控件的选择框可移动控件。若在鼠标拖动过程中还按住 Ctrl键则复制控件。若按 Del键可将选取的控件删除。
(5)设定控件的 Tab键次序一是改变用 Tab键选择控件的次序,二是当两个或两个以上的控件构成一组时,需要它们的 Tab键次序连续。
对话框内控件的 Tab键次序设定步骤如下:
首先,选择,Layout”?“Tab Order”命令,或按 Ctrl+D,此时每个控件的左上方都有一个数字,表明了当前 Tab键次序,如图。
其次,按新的次序依次用鼠标单击各个控件,新的 Tab键即可生成。
最后,单击对话框或按 Enter键结束 Tab Order 方式。
图 5.4 控件的 Tab键次序
5.1对话框的使用对话框内的控件的布局图 5.6 Layout菜单命令项靠齐上边左右间隔相等 大小相同靠齐左边 上下 居中宽度相同 显 示 标尺靠齐右边 左右居中高度相同测试对话框 靠齐下边 上 下 间隔相等 显示网格图 5.5 控件布局工具栏
5.1对话框的使用
大多布置控件的命令使用前,需要选取多个控件,且,主要控件,起到了关键作用。多个控件的布置过程中,常需要重新设置,主要控件,。设置的方法是按住 Ctrl或 Shift键,用鼠标单击所要指定的控件。
系统提供了网格、标尺等辅助工具。在图 5.5的控件布局工具栏的最后两个按钮分别用来网格和标尺的切换。一旦网格显示,添加或移动控件时都将自动定位在网格线上。,Layout”菜单下的,Guide Settings”命令提供了设置网格单元大小的功能,如图。
测试对话框图 5.7 Guide Settings对话框
5.1对话框的使用
5.1.3对话框的编程
添加对话框资源选择,Insert”?“Resource”菜单命令 (或按 Ctrl+R),若单击 Dialog项左边的
,+”号,将展开对话框资源的不同类型选项,如图。
图 5.8,Insert Resource”对话框
5.1对话框的使用
改变对话框的属性在对话框模板的非控件的区域内左击,用下列方式之一打开属性对话框:
选择,View”菜单?,Properties”命令或按 Alt+Enter健。
用鼠标右击对话框模板,选取 Properties命令。
如图,General是对话框属性的默认显示页面,其中列有对话框的标识符名称框、标题框等,具体说明如表。
图 5.9 属性对话框
5.1对话框的使用
向对话框内添加控件
添加一个类在对话框模板的非控件的区域内双击,如图的对话框。
单击 [OK],弹出如图的对话框。可以为对话框资源定义一个新类名。
图 5.11,Adding a Class”对话框图 5.12,New Class”对话框
5.1对话框的使用
消息映射单击 [OK]按钮,出现,MFC ClassWizard”对话框,如图。
图 5.13,MFC ClassWizard”对话框
5.1对话框的使用选定 IDC_BUTTON1的 BN_CLICKED,双击左键或单击 [Add Function]按钮,
如图。
对话框中,可以为添加的成员函数名重新定义,单击 [OK]。选定成员函数
OnButton1项,双击左键或单击 [Edit Code]按钮,在此成员函数添加代码。
不同资源对象 (控件、菜单命令等 )的消息是不相同的。例如,按钮控件
IDC_BUTTON1的消息有两个,BN_CLICKED和 BN_DOUBLECLICKED,分别表示当用户单击或双击该按钮时产生的消息。
一般不需要对图 5.10对话框中的 [OK](确定 )与 [Cancel](取消 )按钮进行消息映射,因为系统已自动设置了这两个按钮的动作,当用户单击这两个按钮都将自动关闭对话框。
图 5.14,Add Member Function”对话框
5.1对话框的使用
添加用户代码
(1)在头文件 (MyDlg.h文件 )中声明消息处理函数 OnButton1:
protected:
//{{AFX_MSG(CMyDlg)
afx_msg void OnButton1();
//}}AFX_MSG
(2)在 MyDlg.cpp源文件开头部分的消息映射入口,添加消息映射宏:
BEGIN_MESSAGE_MAP(CMyDlg,CDialog) // 消息映射开始
//{{AFX_MSG_MAP(CMyDlg)
ON_BN_CLICKED(IDC_BUTTON1,OnButton1)
//}}AFX_MSG_MAP
END_MESSAGE_MAP() // 消息映射结束表明消息及其处理函数之间的联系。单击按钮控件 IDC_BUTTON1时,系统将自动调用 OnButton1函数。
(3)在 MyDlg.cpp文件中写入一个空的消息处理函数的模板,以便用户填入具体代码,如下面的框架:
void CMyDlg::OnButton1()
{
// TODO,Add your control notification handler code here
}
5.1对话框的使用
在程序中使用对话框
(1)利用项目工作区的 ClassView标签项,将 Ex_SDIHello.cpp源文件打开;
(2)在 Ex_SDIHello.cpp源文件的前面加上包含类 CMyDlg的头文件:
#include "MyDlg.h"
(3)在 InitInstance函数体中的,return TRUE;”语句之前添加下列代码:
CMyDlg dlg;
dlg.DoModal();
DoModal是模式对话框最常用的函数,它负责对话框的显示和终止。
(4)编译并运行。在程序的一开始就出现用户自己设计的对话框,单击
[Button1]按钮将弹出,欢迎进入对话框的设计!,的消息对话框来。
5.2控件的创建和使用方法
5.2.1控件的创建方法控件的创建方式有以下两种:
一种是在对话框模板中用编辑器指定控件,也就是说,将控件的父窗口指定为对话框,这样做的好处是明显的,因为当应用程序启动该对话框时,
Windows系统就会为对话框创建控件;而当对话框消失时,控件也随之清除。
另一种方式是将控件看作是任一窗口的子窗口,并通过调用相应的 Create
函数来创建。
[例 Ex_SDIHello] 在上例 Ex_SDIHello的基础上用子窗口方式创建控件。
(1)打开 CMyDlg的头文件 MyDlg.h,添加一个按钮类 CButton指针变量:
class CMyDlg,public CDialog
{
// Construction
public:
CMyDlg(CWnd* pParent = NULL); // standard constructor
CButton *m_btnWnd;
…
}
5.2控件的创建和使用方法
(2)按 Ctrl+W快捷键打开对话框,切换到 Message Maps页面,在 Object IDs
列表中选定,CMyDlg”项,并在 Message列表中找到 WM_INITDIALOG消息,
双击鼠标左键,然后单击 [Edit Code]按钮,添加下列代码:
BOOL CMyDlg::OnInitDialog()
{ CDialog::OnInitDialog();
// TODO,Add extra initialization here
m_btnWnd = new CButton(); // 构造按钮控件
m_btnWnd ->Create("你好 ",WS_CHILD | WS_VISIBLE |
BS_PUSHBUTTON,
CRect(20,20,120,60),this,201); // 创建
CFont *font = this->GetFont(); // 获取对话框的字体
m_btnWnd->SetFont(font); // 设置控件字体
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION,OCX Property Pages should return FALSE
}
Create用来创建一个按钮控件,第一个参数指定按钮的标题,第二个参数指定控件的风格,第三个参数指定它在父窗口中的位置和大小,第四个参数指定父窗口指针,最后一个参数是指定该控件的标识值。
(3)编译并运行,
5.2控件的创建和使用方法
5.2.2控件的数据交换和数据校验例如,为 CMyDlg类的按钮控件 IDC_BUTTON1添加并使用其成员变量
m_MyBtn,则其相应的过程如下:
(1)启动 MFC ClassWizard,切换到 Member Variables页面,如图。
(2)选定 Class name为 CMyDlg,然后在 Control IDs列表中,选定所要关联的控件 ID号 IDC_BUTTON1,双击鼠标左键或单击 [Add Variable]按钮,如图。
图 5.16 ClassWziard的,Member Variables”页面图 5.17,Add Member Variable”对话框
5.2控件的创建和使用方法
(3)在 Member variable name框中填好与控件相关联的成员变量 m_MyBtn,单击 [OK],在 Control IDs列表中出现刚才添加的内容。
需要说明的是,
DDV/DDX技术中,允许为同一个控件关联多个数据成员变量,但必须保证这些变量名是互不相同的,且这些变量在同一个类型不能有多个变量。
如果添加的成员变量是一个数值类型,则在 MFC ClassWizard对话框的
Member Variables页面下方还要求用户输入变量的范围,这就是控件的数据校验设置。
(4)单击 [OK],发现 ClassWizard作了以下三方面的修改。
在 MyDlg.h文件中,添加与控件关联的成员变量的声明,代码如下:
// Dialog Data
//{{AFX_DATA(CMyDlg)
enum { IDD = IDD_DIALOG1 };
CButton m_MyBtn;
CString m_strEdit;
//}}AFX_DATA
5.2控件的创建和使用方法
在 MyDlg.cpp文件中的 CMyDlg构造函数实现代码处,添加数据成员变量的初始代码:
CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/)
,CDialog(CMyDlg::IDD,pParent)
{ //{{AFX_DATA_INIT(CMyDlg)
m_strEdit = _T("");
//}}AFX_DATA_INIT
}
在 MyDlg.cpp文件中的 DoDataExchange函数体内,添加控件的 DDX/DDV
代码。
void CMyDlg::DoDataExchange(CDataExchange* pDX)
{ CDialog::DoDataExchange(pDX); // 调用此函数作为 DDX的开始
//{{AFX_DATA_MAP(CMyDlg)
DDX_Control(pDX,IDC_BUTTON1,m_MyBtn);
DDX_Text(pDX,IDC_EDIT1,m_strEdit);
DDV_MaxChars(pDX,m_strEdit,20);
//}}AFX_DATA_MAP
}
5.2控件的创建和使用方法
(5)为一个控件定义一个关联的数据成员变量后,就可以使用
CWnd::UpdateData函数实现控件的控制,包括控件相关数据的输入和读取。
运行该程序,当在编辑框中输入,Hello”后,单击 [Button1]按钮,则此时该按钮的名称就变成了编辑框控件中的内容,Hello”,如图。
图 5.19 使用控件的数据成员变量
5.2控件的创建和使用方法
5.2.3控件的通用属性图 5.20 按钮控件的属性对话框
5.2控件的创建和使用方法
5.2.4控件的消息控件的编程和使用过程中,可以向控件发送消息来完成特定的任务,或者是根据控件产生的消息执行自己的代码。
应用程序创建一般控件或公共控件之后,控件的状态发生改变时,控件就会向其父窗口发送消息,这个消息称为,通知消息,。对于每个消息,系统都会用一个 MSG结构来记录,MSG具有下列结构:
typedef struct tagMSG { // msg
HWND hwnd; // 接收到消息的窗口句柄
UINT message; // 消息
WPARAM wParam; // 消息的附加信息,它的含义取决于 message
LPARAM lParam; // 消息的附加信息,它的含义取决于
message
DWORD time; // 消息传送时的时间
POINT pt; // 消息传送时,光标的屏幕坐标
} MSG;
对于一般控件来说,通知消息通常是一条 WM_COMMAND消息,这条消息的
wParam参数的低位字中含有控件标识符,wParam参数的高位字则为通知代码,lParam参数则是指向控件的句柄。
5.2控件的创建和使用方法对于公共控件,通知消息通常是一条 WM_NOTIFY消息,wParam参数是发送通知消息的控件的标识符,lParam参数是指向 NMHDR结构的指针。对于有些控件的通知消息,lParam参数是指向一个更大的结构,且结构中的第一个成员还必须具有 NMHDR结构。
对于控件的 WM_COMMAND或是 WM_NOTIFY消息,都可以用 ClassWizard对它们加以映射。
尽管控件的各自通知消息并不相同,但下列的通知消息是所有 Windows控件所共有的:
NM_CLICK 在控件中单击鼠标左按钮
NM_DBLCLK 在控件中双击鼠标左按钮
NM_RCLICK 在控件中单击鼠标左按钮
NM_RDBLCLK 在控件中双击鼠标右按钮
NM_RETURN 当控件具有输入焦点时按下 ENTER键
NM_SETFOCUS 控件得到输入焦点
NM_KILLFOCUS 控件失去输入焦点
NM_OUTOFMEMORY 没有足够的内存使控件完成操作
5.3常用控件根据控件的特性和功能,一般可将其分为三类,Windows公共控件、
ActiveX控件以及 MFC新增的一些控件等。
5.3常用控件
5.3.1静态控件和按钮
静态控件一个静态控件是用来显示一个字符串、框、矩形、图标、位图或增强的图元文件。它可以被用来作为标签、框或用来分隔其它的控件。一个静态控件一般不接收用户输入,也不产生通知消息。
在对话框编辑器的控件工具栏中,属于静态控件的有:静态文本 ( )、组框
( )和静态图片 ( )三种。
图 5.21 静态图片控件的 General和 Style属性对话框
5.3常用控件
按钮
(1)按键按钮通常可以立即产生某个动作,执行某个命令,常被称为命令按钮。两种风格:标准按键按钮和默认按键按钮。从外观上来说,默认按键按钮是在标准按键按钮的周围加上一个黑色边框,这个黑色边框表示该按钮已接受到键盘的输入焦点,只须按回车键就能按下该按钮。具体设定的方法是在按键按钮属性对话框的 Style页面中选中,Default button”项。
(2)单选按钮外形是在文本前有一个圆圈,被选中时,就标上一个黑点,可分为一般和自动两种类型。自动类型中,若选中同组按钮中的某个单选按钮,则其余的单选按钮的选中状态就会清除,保证了多个选项始终只有一个被选中。
(3)复选框外形是在文本前有一个空心方框,被选中时,复选框中就加上一个,?” 标记,三态复选框还有种处于灰框状态,表示,不确定,。设定成三态复选框的方法是在复选框属性对话框的 Style页面中选中,Tri-state”项。
图 5.22 按钮的不同类型三态复选框
5.3常用控件
按钮的消息常见的只有两个,BN_CLICKED和 BN_DOUBLE- CLICKED。
按钮选中操作
最常用的按钮操作是设置或获取一个或多个按钮的选中状态。 CButton类的成员函数 SetCheck和 GetCheck设置或获取指定按钮的选中状态,原型:
void SetCheck( int nCheck );
int GetCheck( ) const;
nCheck和 GetCheck函数返回的值可以是,0表示不选中,1表示选中,2表示不确定 (仅用于三态按钮 )。
对于多个单选按钮的选中状态的设置或获取,需要使用 CWnd类的成员函数
CheckRadioButton和 GetCheckedRadioButton,原型:
void CheckRadioButton( int nIDFirstButton,int nIDLastButton,int
nIDCheckButton );
int GetCheckedRadioButton( int nIDFirstButton,int nIDLastButton );
nIDFirstButton和 nIDLastButton指定这组单选按钮的第一个和最后一个按钮
ID值,nIDCheckButton指定要设置选中状态的按钮 ID值,函数
GetCheckedRadioButton返回被选中的按钮 ID值。
5.3常用控件
[例 Ex_Ctrls1] 用静态图片、单选按钮、复选框和按键按钮控件,设计界面。开始,所有单选按钮都是灰显的,不能选择,选中,允许,复选框后,所有单选按钮可以使用,选定一个单选框后,单击 [应用 ]。
(1)用 MFC AppWizard(exe)创建一个名为 Ex_CommCtrls的基于对话框的应用程序。在创建的第一步,将应用程序类型选择为 Dialog Based,按 [Finish]。自动显示出该程序的对话框资源模板内容。
(2)打开属性对话框将其标题改为,使用 Windows常用控件,。
(3)用编辑器为对话框添加如下表所示的一些控件。
(4)四个单选按钮的 Tab次序应连续,从 IDC_RADIO1到 IDC_RADIO4依次增加。
(5)按 Ctrl+W快捷键,切换到 Member Variables页面,在 Class name中选择
CEx_CommCtrlstDlg,选中复选框控件 ID号 IDC_CHECK1,双击鼠标或单击 Add
Variables按钮。
5.3常用控件
(6)切换到 ClassWizard的 Messsage Maps页面,为复选框 IDC_CHECK1和按钮
IDC_BUTTON1增加 BN_CLICKED的消息映射,添加代码:
void CEx_CommCtrlsDlg::OnCheck1()
{ UpdateData();
for (int i=0; i<4; i++)
GetDlgItem(IDC_RADIO1 + i)->EnableWindow(m_bEnabled);
}
void CEx_CommCtrlsDlg::OnButton1()
{ UpdateData();
if (!m_bEnabled) return;
int nID = GetCheckedRadioButton(IDC_RADIO1,IDC_RADIO4);
if (nID == IDC_RADIO1)
{ MessageBox("1"); }
if (nID == IDC_RADIO2)
{ MessageBox("2"); }
if (nID == IDC_RADIO3)
{ MessageBox("3"); }
if (nID == IDC_RADIO4)
{ MessageBox("4"); }
}
5.3常用控件
(7)定位到 CEx_CommCtrlsDlg::OnInitDialog函数体中,添加下列代码:
BOOL CEx_CommCtrlsDlg::OnInitDialog()
{ CDialog::OnInitDialog();
…
CheckRadioButton(IDC_RADIO1,IDC_RADIO4,IDC_RADIO1); //设置第一个单选按钮为选中
OnCheck1();
return TRUE; // return TRUE unless you set the focus to a control
}
(8)编译并运行。
图 5.23 按钮示例运行结果
5.3常用控件
5.3.2编辑框
编辑框的属性和风格图 5.24 编辑框的属性对话框
5.3常用控件
编辑框的基本操作
(1)口令设置默认的口令字符是,*”,应用程序可以用成员函数
CEdit::SetPasswordChar 来定义自己的口令字符,其函数原型如下:
void SetPasswordChar( TCHAR ch );
(2)选择文本用鼠标来选择文本的操作方法,在要选择的文本的一端按下鼠标左键并拖动鼠标,到另一端释放鼠标键。
用键盘来选择文本的方法,在按光标方向移动键的同时,按住 Shift键。
应用程序中可以通过编程选择文本,需要通过调用成员函数 CEdit::SetSel
来实现。与该函数相对应的还有 CEdit::GetSel和 CEdit::ReplaceSel,分别用来获取编辑框中前选择的开始和结束的位置以及替换被选择的文本。
(3)设置编辑框的页面边距设置编辑框的页面边距可以使文本在编辑框显示更具满意效果,应用程序可通过调用成员函数 CEdit::SetMargins来实现,函数原型:
void SetMargins( UINT nLeft,UINT nRight );
(4)剪帖板操作编辑框自动支持文本的复制、粘贴、剪切的键盘操作,对应的快捷健为
Ctrl+C,Ctrl+V和 Ctrl+X。若应用程序调用 CEdit::Undo函数时,还可撤消当前的操作,再调用一次该函数,则恢复刚才的操作。
5.3常用控件
(5)获取多行编辑框文本一种是使用 DDX/DDV,将编辑框控件所关联的变量类型选定为 CString后,
则不管多行编辑框的文本有多少都可用此变量来保存。这种方法不能单独获得多行编辑框中的某一行文本。
另一种方法是使用编辑框 CEdit类的相关成员函数来获取文本。例如,下面的代码将显示编辑框中第二行的文本内容:
char str[100];
if (m_Edit.GetLineCount()>=2) // 判断多行编辑框的文本是否有两行以上
{ int nChars;
nChars = m_Edit.LineLength(m_Edit.LineIndex(1)); // 获取第二行文本的字符个数
// 0表示第一行,1表示第二行,依次类推。 LineIndex用于将文本行转换成
// 能被 LineLength识别的索引
m_Edit.GetLine(1,str,nChars); // 获取第二行文本
str[nChars] = '\0';
MessageBox(str);
}
5.3常用控件
编辑框的通知消息
[例 Ex_Ctrls2] 使用静态文本、组框、编辑框以及按钮等控件,设计界面。
用户在,成绩 1”,,成绩 2”和,成绩 3”编辑框中输入成绩后,单击 [计算平均分 ]按钮,将显示出这三个成绩的平均分。
(1)打开前面的 Ex_CommCtrls。
(2)向应用程序中添加一个对话框资源,打开属性对话框将其标题改为,使用编辑框,,ID号改为 IDD_EDIT。
(3) 用编辑器为对话框添加如下表所示的一些控件。
(4)双击对话框模板或按 Ctrl+W快捷键,为对话框资源 IDD_EDIT创建一个对话框类 CEditDlg。
5.3常用控件
(5)打开 ClassWizard的 Member Variables标签,在 Class name中选择
CEditDlg,选中所需的控件 ID号,双击鼠标或单击 Add Variables按钮。依次为控件增加成员变量。
(6)切换到 ClassWizard的 Messsage Maps标签页,为 CEditDlg增加
WM_INITDIALOG的消息映射,并添加下列代码:
BOOL CEditDlg::OnInitDialog()
{ CDialog::OnInitDialog();
m_strAve = "0.00";
UpdateData(FALSE);// 将成员变量数据传给控件,并在控件中显示
return TRUE;
}
5.3常用控件
(7)用 ClassWziard为按钮 IDC_BUTTON1添加 BN_CLICKED的消息映射,并增加下列代码:
void CEditDlg::OnButton1()
{ UpdateData(); // 将控件显示的数据传给成员变量
double ave = (double)(m_nScore1+m_nScore2+m_nScore3)/3.0;
m_strAve.Format("%6.2f",ave);
UpdateData(FALSE); // 将成员变量数据传给控件并显示
}
(8)定位到 CEx_CommCtrlsDlg::OnButton1函数处,修改代码如下:
if (nID == IDC_RADIO1) {
CEditDlg dlg;
dlg.DoModal();
}
(9)在 Ex_CommCtrlsDlg.cpp文件的开始处,增加包含 CEditDlg的头文件。
#include,EditDlg.h”
(10)编译运行并测试。
作业
1.P375:1,3,6,8,10
2.P412:实验 9
5.3常用控件
5.3.3列表框
列表框的风格图 5.25 列表框的属性对话框
5.3常用控件
列表框的基本操作
(1)添加列表项列表框创建时是一个空的列表,需要添加或插入一些列表项。 CListBox类成员函数 AddString 和 InsertString用来向列表框增加列表项,原型:
int AddString( LPCTSTR lpszItem );
int InsertString( int nIndex,LPCTSTR lpszItem );
CListBox的 SetItemData和 SetItemDataPtr能使数据和某个列表项关联起来。
int SetItemData( int nIndex,DWORD dwItemData );
int SetItemDataPtr( int nIndex,void* pData );
(2)删除列表项
CListBox类成员函数 DeleteString和 ResetContent分别用来删除指定的列表项和清除列表框所有项目。它们的函数原型如下:
int DeleteString( UINT nIndex ); // nIndex指定要删除的列表项的索引
void ResetContent( );
若在添加列表项时使用 SetItemDataPtr函数,不要忘记在进行删除操作时及时将关联数据所占的内存空间释放出来。
5.3常用控件
(3)查找列表项
CListBox类成员函数 FindString 和 FindStringExact分别用来在列表框中查找所匹配的列表项,其中 FindStringExact的查找精度最高。
int FindString( int nStartAfter,LPCTSTR lpszItem ) const;
int FindStringExact( int nIndexStart,LPCTSTR lpszFind ) const;
lpszFind和 lpszItem指定要查找的列表项文本,nStartAfter和 nIndexStart指定查找的开始位置,若为 -1,则从头至尾查找。查到后,这两个函数都将返回所匹配列表项的索引,否则返回 LB_ERR。
(4)列表框的单项选择当选中列表框中某个列表项,可以使用 CListBox::GetCurSel来获取这个结果,
与该函数相对应的 CListBox::SetCurSel 函数是用来设定某个列表项呈选中状态 (高亮显示 )。
int GetCurSel( ) const; // 返回当前选择项的索引
int SetCurSel( int nSelect );
nSelect指定要设置的列表项索引,错误时这两个函数都将返回 LB_ERR。
若要获取某个列表项的字符串,可使用下列函数:
int GetText( int nIndex,LPTSTR lpszBuffer ) const;
void GetText( int nIndex,CString& rString ) const;
nIndex指定列表项索引,lpszBuffer 和 rString是用来存放列表项文本。
5.3常用控件
(5)列表框的多项选择在列表框的 Style属性对话框中选中多选 (Multiple)或扩展多选 (Extended)类型后,就可以在列表框中进行多项选择。要想获得选中的多个选项,通过需要用 ClassWizrd映射 LBN_SELCHANGE消息,添加类似代码:
void CListBoxDlg::OnSelchangeList1()
{ int nCount = m_list.GetSelCount(); // 获取用户选中的项数
if (nCount != LB_ERR)
{ int *buffer = new int[nCount]; // 开辟缓冲区
m_list.GetSelItems(nCount,buffer);
CString allStr,str;
allStr.Empty(); // 字符串清空
for (int i=0; i<nCount; i++)
{ m_list.GetText(buffer[i],str);
allStr = allStr +,[” + str +,]”;
}
delete []buffer; // 释放内存
// MessageBox(allStr); // 处理获得的文本
}
}
5.3常用控件
列表框的通知消息
[例 Ex_Ctrls3] 将一个 SCORE结构 (含有三门成绩的数据成员 )数据和列表框中每一个学生姓名列表关联起来。用户单击 [添加记录 ]按钮时,学生成绩记录中的,姓名,被添加在列表框中,该学生的成绩与该列表项关联。单击
[删除记录 ]时,列表框中当前选择项被删除,相关联的数据所占的内容空间被释放。任何时候选中列表框中某个学生,相应的记录数据都被显示出来。
(1)打开前面创建的基于对话框应用程序程序项目 Ex_CommCtrls。
(2)向应用程序中添加一个对话框资源 IDD_LISTBOX,标题定为,使用列表框,,用 ClassWizard为此对话框类定义为 CListBoxDlg。
(3)删除原来的 Cancel按钮,用编辑器为对话框添加如下表所示的控件。
5.3常用控件
(4)打开 ClassWizard的 Member Variables页面,在 Class name中选择 CListBoxDlg,选中所需的控件 ID号,双击鼠标或单击 Add Variables按钮。
(5)切换到 ClassWizard的 Messsage Maps标签页,为按钮 IDC_DATA_ADD添加
BN_CLICKED的消息映射,增加代码:
void CListBoxDlg::OnDataAdd()
{ UpdateData(TRUE);
if (m_strName.IsEmpty()) // 判断 m_strName是否为空
{ MessageBox("姓名不能为空! ");
return; }
m_strName.TrimLeft(); // 裁剪 m_strName左边的空格
m_strName.TrimRight(); // 裁剪 m_strName右边的空格
if ((m_List.FindString(-1,m_strName)) != LB_ERR)
{ MessageBox("列表框中已有相同姓名,不能添加! ");
return; }
int nIndex = m_List.AddString(m_strName); // 向列表框添加学生姓名
// 将该学生成绩与新增的列表项关联起来
SCORE data;
data.score1 = m_nScore1;
data.score2 = m_nScore2;
data.score3 = m_nScore3;
m_List.SetItemDataPtr(nIndex,new SCORE(data));
}
5.3常用控件
(6)用 ClassWizard为按钮 IDC_DATA_DEL添加 BN_CLICKED的消息映射,增加代码:
void CListBoxDlg::OnDataDel()
{ int nIndex = m_List.GetCurSel(); // 获得当前选择项的索引
if (nIndex != LB_ERR)
{ m_List.DeleteString(nIndex); // 删除当前选择项
m_strName.Empty();
m_nScore1 = m_nScore2 = m_nScore3 = 0;
UpdateData(FALSE);
}
else MessageBox("当前没有选择项或列表框操作失败! ");
}
(7)用 ClassWizard为按钮 IDC_LIST1添加 LBN_SELCHANGE的消息映射,增加代码:
void CListBoxDlg::OnSelchangeList1()
{ int nIndex = m_List.GetCurSel();
if (nIndex != LB_ERR)
{ m_List.GetText(nIndex,m_strName);
SCORE *data=(SCORE *)m_List.GetItemDataPtr(nIndex);
m_nScore1 = data->score1;
m_nScore2 = data->score2;
m_nScore3 = data->score3;
UpdateData(FALSE);
}
}
5.3常用控件
(8)用 ClassWizard为对话框添加 WM_DESTROY的消息映射,增加代码:
void CListBoxDlg::OnDestroy() // 此消息是当对话框关闭时发送的
{ for (int nIndex = m_List.GetCount()-1; nIndex>=0; nIndex--)
{// 删除所有与列表项相关联的 SCORE结构数据,并释放内存
delete (SCORE *)m_List.GetItemDataPtr(nIndex);
}
CDialog::OnDestroy(); // 关闭对话框
}
对话框被清除时发送 WM_DESTROY消息。用户在此消息的映射函数中添加一些对象删除代码,以便在对话框清除前有效地释放内存空间。
5.3常用控件
(9)打开 ListBoxDlg.h源文件,在类 CListBoxDlg定义的 public处添加下列代码:
public:
struct SCORE
{ int score1;
int score2;
int score3;
};
(10) 定位到 CEx_CommCtrlsDlg::OnButton1函数处,修改代码如下:
if (nID == IDC_RADIO2)
{ CListBoxDlg dlg;
dlg.DoModal();
}
(11)在 Ex_CommCtrlsDlg.cpp文件的开始处,增加包含 CListBoxDlg的头文件。
#include,ListBoxDlg.h”
(12) 编译运行并测试。
5.3常用控件
5.3.4组合框
组合框的风格及类型图 5.27 组合框的属性对话框
5.3常用控件
组合框常见操作组合框的操作大致分为两类,一类是对组合框中的列表框进行操作,另一类是对组合框中的编辑框进行操作。这些操作都可以调用 CComboBox成员函数来实现。
组合框的通知消息绘图时还需要下列一些技巧:
需要更新或重新绘制窗口的外观时,应用程序就会发送 WM_PAINT消息。用
ClassWizard在对话框中映射 WM_PAINT消息的目的是执行绘图代码。
防止用系统默认的颜色向对话框进行重复绘制,须调用 UpdateWindow函数。
UpdateWindow是 CWnd的无参数的成员函数,目的是绕过系统的消息列队,直接发送或停止发送 WM_PAINT消息。窗口没有需要更新的区域时,就停止发送。绘制完图形时,没有 WM_PAINT消息的发送,系统不会用默认的颜色对窗口进行重复绘制。
如果对话框中的任何部分变为无效时,对话框的 OnPaint函数都会自动调用。可以通过调用 Invalidate函数来通知系统此时的窗口状态已变为无效,强制系统调用
WM_PAINT消息函数 OnPaint重新绘制。
5.3常用控件
[例 Ex_Ctrls4] 根据用户从组合框中选择的填充样式,在对话框中绘制一个矩形区域,如图。
(1)打 开前面创建的基于对话框应用程序程序项目 Ex_CommCtrls。
(2)向应用程序中添加一个对话框资源 IDD_COMBO,标题定为,使用组合框,,用 ClassWizard为此对话框类定义为 CComboDlg。
(3) 删除原来的 Cancel按钮,用编辑器为对话框添加控件。
图 5.28 组合框示例运行结果 图 5.29 组合框控件布局
5.3常用控件
(4)打开 ClassWizard的 Member Variables标签,为组合框 IDC_PATTERN增加成员变量 m_Pattern,其类型为 Control类的 CComboBox 。
(5)为 CComboDlg类添加一个 int类型的成员变量 m_nDrawPattern。
(6)切换到 ClassWizard的 Messsage Maps标签页,为组合框 IDC_PATTERN
添加 CBN_SELCHANGE(组合框中的当前选项发生改变 )的消息映射,并增加下列代码:
void CComboDlg::OnSelchangePattern()
{ int nIndex = m_Pattern.GetCurSel();// 获得当前选项的索引
if (nIndex != CB_ERR)
{ m_nDrawPattern = m_Pattern.GetItemData(nIndex);
// 获得与当前选项相关联的数据
Invalidate(); // 强制系统调用 OnPaint函数重新绘制
}
}
5.3常用控件
(7)用 ClassWizard为对话框添加 WM_PAINT的消息映射,并增加下列代码:
void CComboDlg::OnPaint()
{ CPaintDC dc(this); // device context for painting(绘图所必须的设备环境 )
CWnd* pWnd = GetDlgItem(IDC_DRAW);// 获得控件 IDC_DRAW的窗口指针
pWnd->UpdateWindow(); // 避免系统自动重绘
CDC* pDC = pWnd->GetDC(); // 获得所需要的绘图设备环境
CBrush drawBrush; // 定义一个画刷
drawBrush.CreateHatchBrush(m_nDrawPattern,RGB(0,0,0));// 创建画刷
CBrush* pOldBrush = pDC->SelectObject(&drawBrush);
// 将画刷选入当前设备环境中
CRect rcClient; // 定义一个 CRect变量
pWnd->GetClientRect(rcClient); // 获得窗口客户区大小
pDC->Rectangle(rcClient); // 用当前画刷绘制一个矩形区域
pDC->SelectObject(pOldBrush); // 恢复设备环境原来的画刷设置
}
5.3常用控件
(8)用 ClassWizard为对话框添加 WM_INITDIALOG的消息映射,增加代码:
BOOL CComboDlg::OnInitDialog()
{ CDialog::OnInitDialog();
CString str[6] = {"水平线 ","竖直线 ","向下斜线 ","向上斜线 ","十字线
","交叉线 "};
int nIndex;
for (int i=0; i<6; i++)
{
nIndex = m_Pattern.AddString(str[i]);
m_Pattern.SetItemData(nIndex,i);
}
m_Pattern.SetCurSel(0);
m_nDrawPattern = 0;
return TRUE;
}
5.3常用控件
(9)定位到 CEx_CommCtrlsDlg::OnButton1函数处,修改代码如下:
if (nID == IDC_RADIO3)
{
CComboDlg dlg;
dlg.DoModal();
}
(10)在 Ex_CommCtrlsDlg.cpp文件的开始处,增加包含 CComboDlg的头文件。
#include,ComboDlg.h”
(11)编译运行并测试。
5.3常用控件
5.3.5滚动条和进展条
滚动条
(1)滚动条的基本操作
在 MFC的 CScrollBar类中,函数 SetScrollRange是用来设置滚动条的滚动范围的,其原型如下:
SetScrollRange( int nMinPos,int nMaxPos,BOOL bRedraw = TRUE );
在 CScrollBar类中,设置滚动块位置操作是由 SetScrollPos函数来完成的,其原型如下:
int SetScrollPos( int nPos,BOOL bRedraw = TRUE );
与 SetScrollRange 和 SetScrollPos相对应的两个函数是分别用来获取滚动条的当前范围以及当前滚动位置:
void GetScrollRange( LPINT lpMinPos,LPINT lpMaxPos ) ;
int GetScrollPos();
需要说明的是:在 CScrollBar类的成员函数中,还可以用 SetScrollInfo和
GetScrollInfo来代替上面提到的四个函数。与前面的函数相比,使用
SetScrollInfo函数还能使滚动块的大小随内容的多少而改变。
图 5.30 滚动条外观滚动箭头按钮滚动条 滚动块
5.3常用控件
(2) WM_HSCROLL或 WM_VSCROLL消息滚动条进行操作时,会向父窗口发送 WM_HSCROLL或 WM_VSCROLL消息。
通过 ClassWziard在其对话框中进行映射,产生相应的消息映射函数
OnHScroll和 OnVScroll,函数原型:
afx_msg void OnHScroll( UINT nSBCode,UINT nPos,CScrollBar* pScrollBar );
afx_msg void OnVScroll( UINT nSBCode,UINT nPos,CScrollBar* pScrollBar );
SB_LINELEFT SB_LINERIGHT
SB_PAGELEFT SB_PAGERIGHT
图 5.31 滚动条通知代码与位置的关系
SB_LINEUP
SB_PAGEUP
SB_THUMBTRACK和
SB_THUMBPOSITION
SB_PAGEDOWN
SB_LINEDOWN
5.3常用控件
进展条
(1)进展条的风格打开进展条的属性对话框。 Border指定进展条是否有边框,Vertical指定进展是水平还是垂直的。 Smooth表示平滑地填充进展条。
(2)进展条的基本操作基本操作:设置范围、当前位置、增量等。通过相关的 CProgressCtrl类成员函数实现。
int SetPos( int nPos );
int GetPos();
这两个函数分别用来设置和获取进展条的当前位置。
void SetRange( short nLower,short nUpper );
void SetRange32(int nLower,int nUpper );
void GetRange( int & nLower,int& nUpper );
分别用来设置和获取进展条范围的上限和下限值。
int SetStep( int nStep );
该函数用来设置进展条的步长并返回原来的步长。
int StepIt();
该函数将当前位置向前移动一个步长并重画进展条以反映新的位置。
5.3常用控件
5.3.6旋转按钮控件和滑动条
旋转按钮控件
(1)旋转按钮控件常用的风格图 5.35 旋转按钮控件属性对话框
5.3常用控件
(2)旋转按钮控件的基本操作成员函数 SetBase是用来设置其基数的,函数的原型如下:
int SetBase( int nBase );
成员函数 SetPos和 SetRange设置旋转按钮控件的当前位置和范围,它们的函数原型如下:
int SetPos( int nPos );
void SetRange( int nLower,int nUpper );
成员函数 SetAccel和 GetAccel用来设置和获取旋转按钮控件的加速度。其中函数 SetAccel的原型如下:
BOOL SetAccel( int nAccel,UDACCEL* pAccel );
参数 nAccel表示由 pAccel指定的 UDACCEL结构的数目。 pAccel指向一个
UDACCEL结构数组的指针,该数组包含了加速信息,其结构如下:
typedef struct {
UINT nSec; // 位置改变前所等待的秒数。
UINT nInc; // 位置增量。
}UDACCEL,FAR *LPUDACCEL;
(3)旋转按钮控件的通知消息旋转按钮控件的通知消息只有一个,UDN_DELTAPOS,它是当控件的当前数值将要改变时向其父窗口发送的。
5.3常用控件
滑动条
(1)滑动条的风格图 5.36 带刻度线的滑动条滑动块刻度线图 5.37 滑动条属性对话框
5.3常用控件
(2)滑动条的基本操作
成员函数 SetPos和 SetRange用来设置滑动条的位置和范围,原型如下:
void SetPos( int nPos );
void SetRange( int nMin,int nMax,BOOL bRedraw = FALSE );
成员函数 SetTic用来设置滑动条控件中的一个刻度线的位置。函数成功调用后返回非零值;否则返回 0。函数原型如下:
BOOL SetTic( int nTic );
成员函数 SetTicFreq设置显示在滑动条中的刻度线的疏密程度。原型如下:
void SetTicFreq( int nFreq );
成员函数 ClearTics用来从滑动条控件中删除当前的刻度线。函数原型如下:
void ClearTics( BOOL bRedraw = FALSE );
成员函数 SetSelection用来设置一个滑动条控件中当前选择的开始和结束位置。其函数原型如下:
void SetSelection( int nMin,int nMax );
(3)滑动条的通知消息消息代码都来自于 WM_HSCROLL或 WM_VSCROLL消息。
5.3常用控件
[例 Ex_Ctrls5]用滚动条、滑动条和旋转按钮控件分别来调整 RGB的三个颜色分量,根据指定的颜色填充一个矩形区域。
(1)打开前面创建的基于对话框应用程序程序项目 Ex_CommCtrls。
(2)向应用程序中添加一个对话框资源 IDD_SCROLL,标题定为,使用滚动条、
旋转按钮控件和滑动条,,用 ClassWizard为此对话框类定义为 CScrollDlg。
(3)删除原来的 Cancel按钮,用编辑器为对话框添加如下表所示的一些控件。
5.3常用控件
(4)打开 ClassWizard的 Member Variables标签,在 Class name中选择
CScrollDlg,选中所需的控件 ID号,双击鼠标或单击 Add Variables按钮。依次为下列控件增加成员变量。
(5)切换到 ClassWizard的 Messsage Maps标签页,为编辑框 IDC_EDIT1、
IDC_EDIT2和 IDC_EDIT3添加 EN_CHANGE的消息映射,使用它们的消息处理函数名都设为 OnChangeEdit,并增加下列代码:
void CScrollDlg::OnChangeEdit()
{ if (!m_bEditOK) return;
UpdateData();
m_Scroll.SetScrollPos(m_RValue);
m_Slider.SetPos(m_GValue);
Draw();
}
5.3常用控件
(6)用 ClassWizard为对话框添加 WM_PAINT的消息映射,增加代码:
void CScrollDlg::OnPaint()
{ CPaintDC dc(this); // device context for painting
CWnd* pWnd=GetDlgItem(IDC_DRAW);
pWnd->UpdateWindow();
Draw();
}
(7)用 ClassWizard为对话框添加 WM_INITDIALOG的消息映射,增加代码:
BOOL CScrollDlg::OnInitDialog()
{ CDialog::OnInitDialog();
// 设置滚动条和滑动条的范围和当前位置
m_Scroll.SetScrollRange(0,255);
m_Scroll.SetScrollPos(m_RValue);
m_Slider.SetRange(0,255);
m_Slider.SetPos(m_GValue);
// 设置旋转按钮的范围
m_Spin.SetRange(0,255);
UpdateData(FALSE); // 将数据传给控件
m_bEditOK = TRUE;
return TRUE;
}
5.3常用控件
(8)用 ClassWizard为对话框添加 WM_HSCROLL的消息映射,增加代码:
void CScrollDlg::OnHScroll(UINT nSBCode,UINT nPos,CScrollBar* pScrollBar)
{ int nID = pScrollBar->GetDlgCtrlID();
if (nID == IDC_SLIDER1) // 是滑动条产生水平滚动消息
{ m_GValue = m_Slider.GetPos();// 获得滑动条当前的位置 }
if (nID == IDC_SCROLLBAR1) // 是滚动条条产生水平滚动消息
{ switch(nSBCode)
{ case SB_LINELEFT:m_RValue--; break;
case SB_LINERIGHT:m_RValue++; break;
case SB_PAGELEFT,m_RValue -= 10; break;
case SB_PAGERIGHT:m_RValue += 10; break;
case SB_THUMBTRACK:m_RValue = nPos;break;
}
if (m_RValue<0) m_RValue = 0;
if (m_RValue>255) m_RValue = 255;
m_Scroll.SetScrollPos(m_RValue);
}
UpdateData(FALSE);
Draw();
CDialog::OnHScroll(nSBCode,nPos,pScrollBar);
}
5.3常用控件
(9)将项目工作区切换到 ClassView页面,用鼠标右击,CScrollDlg”项,在弹出的快捷菜单中选中,Add Member Function”,将要增加的函数名设为
Draw,函数类型为 void,并添加下列代码:
void CScrollDlg::Draw()
{ CWnd* pWnd = GetDlgItem(IDC_DRAW);
CDC* pDC = pWnd->GetDC(); // 获得窗口当前的设备环境指针
CBrush drawBrush; // 定义画刷变量
drawBrush.CreateSolidBrush(RGB(m_RValue,m_GValue,m_BValue));
// 创建一个填充色画刷。
// 颜色分量转换成一个 32位的 RGB颜色值
CBrush* pOldBrush = pDC->SelectObject(&drawBrush);
CRect rcClient;
pWnd->GetClientRect(rcClient);
pDC->Rectangle(rcClient);
pDC->SelectObject(pOldBrush);
}
5.3常用控件
(10)为 CScrollDlg类添加一个 BOOL型成员变量 m_bEditOK,并在其构造函数中将其初值设为 FALSE。
(11)定位到 CEx_CommCtrlsDlg::OnButton1函数处,修改代码如下:
if (nID == IDC_RADIO4)
{ CScrollDlg dlg;
dlg.DoModal();
}
(12)在 Ex_CommCtrlsDlg.cpp文件的开始处,增加包含 CScrollDlg的头文件。
#include,ScrollDlg.h”
(13)编译运行并测试。
在同时使用编辑框和旋转按钮控件时,有时会出现运行错误。为了解决这个问题,本例使用一个办法,即使用一个 BOOL型成员变量 m_bEditOK作为控制条件,使得所有初始化代码 (包括设置旋转控件范围 )执行后,才允许编辑框工作。
由于滚动条和滑动条等许多控件都能产生 WM_HSCROLL或 WM_VSCROLL消息,因此当它们是处在同一方向 (水平或垂直 )时,就需要添加相应代码判断消息是谁产生的。
由于滚动条中间的滚动块在默认时是不会停止在用户操作的位置处的,因此需要调用 SetScrollPos函数来进行相应位置的设定。
5.3常用控件
5.3.7图像列表和标签控件
图像列表控件
(1)图像列表的创建由于 Create函数的重载很多,故这里给出最常用的一个原型:
BOOL Create( int cx,int cy,UINT nFlags,int nInitial,int nGrow );
(2)图像列表的基本操作常见的图像列表的基本操作有:增加、删除和绘制等,成员函数:
int Add( CBitmap* pbmImage,CBitmap* pbmMask );
int Add( CBitmap* pbmImage,COLORREF crMask );
int Add( HICON hIcon );
BOOL Remove( int nImage );
该函数用来从图像列表中删除一个由 nImage指定的图像,
BOOL Draw( CDC* pdc,int nImage,POINT pt,UINT nStyle );
该函数用来在由 pt指定的位置处绘制一个图像。
HICON ExtractIcon( int nImage );
该函数用来将 nImage指定的图像扩展为图标。
COLORREF SetBkColor( COLORREF cr );
该函数用来设置图像列表的背景色,
5.3常用控件
标签控件
(1)标签控件的风格图 5.39 标签控件属性对话框
5.3常用控件
(2)标签控件的基本操作
GetItemRect是用来获取标签的边界大小,原型如下:
CSize SetItemSize( CSize size );
void SetPadding( CSize size );
int SetMinTabWidth( int cx );
BOOL GetItemRect( int nItem,LPRECT lpRect ) const;
成员函数 InsertItem,DeleteItem表示在一个标签控件中插入、删除某一标签项,
DeleteAllItems删除所有的项。原型如下:
BOOL InsertItem( int nItem,LPCTSTR lpszItem );
BOOL InsertItem( int nItem,LPCTSTR lpszItem,int nImage);
BOOL DeleteItem( int nItem );
BOOL DeleteAllItems( );
标签控件中使用图像列表时,必须调用 CTabCtrl::SetImageList函数来指定一个已创建的图像列表。函数原型如下:
CImageList * SetImageList( CImageList * pImageList );
成员函数 SetCurSel和 GetCurSel用来设置和获取当前选择的标签项,原型如下:
int SetCurSel( int nItem );
int GetCurSel( ) const;
成员函数 DeselectAll用来重新设置一个标签控件中的项,清除任何被按下的项,函数
HighlightItem是使某一个标签项处于高亮状态。原型如下:
void DeselectAll( BOOL fExcludeFocus );
BOOL HighlightItem( int idItem,BOOL fHighlight = TRUE );
(3)标签控件的通知消息
5.3常用控件
[例 Ex_Ctrls6] 使用无模式对话框来构造某个标签页面,一开始将所有的标签页面创建好,然后根据所选择的当前标签选项决定哪个页面需要显示,哪个页面需要隐藏和禁用。
(1)用 MFC AppWizard(exe)创建一个基于对话框的应用程序项目 Ex_TabCtrl。
(2)打开属性对话框将对话框标题改为,使用标签控件,。
(3) 添加一个默认标签控件 IDC_TAB1,调整其大小和布局。
(4)按 Ctrl+W,打开 ClassWizard对话框,切换到 Member Variables页面,在
Class name中选择 CEx_TabCtrlDlg,选中标签控件 ID号 IDC_TAB1,双击鼠标或单击 Add Variables按钮,为其添加一个 CTabCtrl类型的成员变量 m_Tab。
(5)添加三个对话框资源 IDD_DIALOG1,IDD_DIALOG2和 IDD_DIALOG3,并用 ClassWizard依次为此三个对话框类定义为 CTab1Dlg,CTab2Dlg和 CTab3Dlg。
5.3常用控件
(6)将上述三个对话框的属性设为 Child Style和 None Border(其他默认 ),且将对话框尽量缩小,如图。
图 5.41 设置对话框属性
5.3常用控件
(7) 为三个对话框添加如下表所示的一些控件。
5.3常用控件
(8)在 ClassView中的 CEx_TabCtrlDlg类名处右击鼠键,从弹出的快捷菜单中选择 Add Member Variables,添加下列数据成员:
public:
CTab1Dlg *m_pTab1Dlg;
CTab2Dlg *m_pTab2Dlg;
CTab3Dlg *m_pTab3Dlg;
CImageList m_ImageList;
(9)打开 Ex_TabCtrlDlg.h文件,在 class CEx_TabCtrlDlg前添加下列头文件:
#include "Tab1Dlg.h"
#include "Tab2Dlg.h"
#include "Tab3Dlg.h"
5.3常用控件
(10)在 ClassView中的 CEx_TabCtrlDlg类名处右击鼠键,选择 Add Member Function,添加成员函数 SetDlgState和 DoTab,并增加下列代码:
void CEx_TabCtrlDlg::SetDlgState(CWnd *pWnd,BOOL bShow)
{ pWnd->EnableWindow(bShow);
if (bShow)
{ pWnd->ShowWindow(SW_SHOW);
pWnd->CenterWindow(); // 居中显示
}
else pWnd->ShowWindow(SW_HIDE);
}
void CEx_TabCtrlDlg::DoTab(int nTab)
{ if (nTab>2) nTab = 2; // 确定 nTab值不能超过范围
if (nTab<0) nTab = 0;
BOOL bTab[3];
bTab[0] = bTab[1] = bTab[2] = FALSE;
bTab[nTab] = TRUE;
// 切换对话框的显示和隐藏
SetDlgState(m_pTab1Dlg,bTab[0]);
SetDlgState(m_pTab2Dlg,bTab[1]);
SetDlgState(m_pTab3Dlg,bTab[2]);
}
5.3常用控件
(11)用 ClassWizard为 IDC_TAB1映射 TCN_SELCHANGE消息,添加代码:
void CEx_TabCtrlDlg::OnSelchangeTab1(NMHDR* pNMHDR,LRESULT*
pResult)
{ int nSelect = m_Tab.GetCurSel();
if (nSelect >= 0)
DoTab(nSelect);
*pResult = 0;
}
(12)按下 Ctrl+R快捷键,单击 Import按钮,从外部磁盘中调入三个图标文件,并取默认的图标 ID号 IDI_ICON1,IDI_ICON2和 IDI_ICON3。
5.3常用控件
(13)在 CEx_TabCtrlDlg::OnInitDialog中添加下列代码:
BOOL CEx_TabCtrlDlg::OnInitDialog()
{ CDialog::OnInitDialog();
……
m_pTab1Dlg = new CTab1Dlg(); // 为无模式对话框分配空间
m_pTab2Dlg = new CTab2Dlg();
m_pTab3Dlg = new CTab3Dlg();
m_pTab1Dlg->Create(IDD_DIALOG1,&m_Tab);
m_pTab2Dlg->Create(IDD_DIALOG2,&m_Tab);
m_pTab3Dlg->Create(IDD_DIALOG3,&m_Tab);
m_ImageList.Create(16,16,ILC_COLOR|ILC_MASK,3,0); // 创建图像列表
m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON1));
m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON2));
m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON3));
m_Tab.SetImageList(&m_ImageList); // 设置 TAB控件所使用的图像列表
m_Tab.InsertItem(0,"基本信息 ",0);
m_Tab.InsertItem(1,"成绩 ",1);
m_Tab.InsertItem(2,"备注 ",2);
m_Tab.SetMinTabWidth(80); // 设置标签项的最小宽度
m_Tab.SetPadding(CSize(12,3)); // 设置标签项和图标周围的间隔
m_Tab.SetCurSel(0);
DoTab(0);
return TRUE;
}
5.3常用控件
(14)用 ClassWizard为 CEx_TabCtrlDlg类添加 WM_DESTROY的消息映射,
CEx_TabCtrlDlg对话框退出时,删除分配给无模式对话框的内存。代码:
void CEx_TabCtrlDlg::OnDestroy()
{ CDialog::OnDestroy();
if (m_pTab1Dlg) delete m_pTab1Dlg;
if (m_pTab2Dlg) delete m_pTab2Dlg;
if (m_pTab3Dlg) delete m_pTab3Dlg;
}
(15)用 ClassWizard为 CTab1lDlg类添加 WM_INITDIALOG消息的映射,增加下列代码:
BOOL CTab1Dlg::OnInitDialog()
{ CDialog::OnInitDialog();
CheckRadioButton(IDC_RADIO_MAN_1,IDC_RADIO_WOMAN_1,IDC
_RADIO_MAN_1);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION,OCX Property Pages should return FALSE
}
(16) 编译并运行。
5.3常用控件需要说明的是:
标签页面的切换可能还不止一种方法。例如,可以先将各个页面的控件与标签控件一起事先全部地添加到对话框模板中,然后再根据标签控件的当前选项确定控件的显示和隐藏,从而达到切换的效果。
在标签页面控件操作过程中,当按 Enter键或 Esc键,该页面的对话框就会退出,标签页面变成了一个空白,影响交互效果。解决这个问题的一个办法是在各页面的对话框中屏蔽掉 Enter键和 Esc键的按键消息,它是通过添加 PreTranslateMessage函数的重载来实现的,如下面的代码:
BOOL CTab1Dlg::PreTranslateMessage(MSG* pMsg)
{ if (pMsg->message == WM_KEYDOWN)
{ if (pMsg->wParam == VK_RETURN) return TRUE;
if (pMsg->wParam == VK_ESCAPE) return TRUE; }
return CDialog::PreTranslateMessage(pMsg);
}
5.4通用对话框和消息对话框
5.4.1通用对话框
Windows提供了一组标准用户界面对话框,它们都有相应的 MFC库中的类来支持。所有这些通用对话框类都是从一个公共的基类 CCommonDialog派生而来。表列出了这些通用对话框。
5.4通用对话框和消息对话框
5.4.2消息对话框是最简单的一类对话框,只是用来显示信息的。 MFC类库中提供相应的函数实现这样的功能,只要在程序任何地方调用它们。函数原型:
int AfxMessageBox( LPCTSTR lpszText,UINT nType = MB_OK,UINT
nIDHelp = 0 );
int MessageBox( LPCTSTR lpszText,LPCTSTR lpszCaption = NULL,UINT
nType = MB_OK );
作业
1.P375:12
2.P420:实验 10