1.实际上对话框就是一个窗口,也可以将它看成是一个大容器,可以放置各种控件
2.对话框的创建和显示
(1)在MFC中,所有的控件类都是由CWnd派生来的,因此,控件实际上也是窗口
(2)对话框的种类:模态对话框和非模态对话框
(3)创建对话框资源
(4)在MFC中,对资源的操作通常都是通过一个与资源相关的类来完成的,创建一个与对话框资源相关联的类
(5)CTestDlg的DoDataExchange函数用来完成对话框数据的交换和校验
(6)在程序中显示对话框窗口
1.模态对话框的创建:CDialog类的成员函数DoModal,该函数的作用是创建并显示一个模态对话框,其返回值将作为CDialog类的另一成员函数EndDialog的参数,后者的功能是关闭模态对话框。
CTestDlg dlg; //必须包含头文件TestDlg.h
dlg.DoModal();
2.非模态对话框的创建:CDialog类的成员函数Create()
(1) 函数声明:
1.BOOL Create(LPCTSTR lpszTemplateName,CWnd* pParentWnd = NULL);
2.BOOL Create(UINT nIDTemplate,CWnd* pParentWnd = NULL);
//Create函数的第一个参数可以是对话框资源的ID,或者也可以是对话框模板的名称
//第二个参数指定了对话框的父窗口,若为NULL,对话框的父窗口就是主应用程序窗口。
(2)当利用Create函数创建非模态对话框后,还需要调用ShowWindow函数将这个对话框显示出来
dlg.Create(IDD_DIALOG1,this);
dlg.ShowWindow(SW_SHOW);(dlg要设置为视类成员变量或在堆上分配内存)
(3) 对非模态对话框来说,要重写基类的OnOk函数和OnCancel函数,并在重写的函数中调用DestroyWindow函数,销毁对话框
3.动态创建按钮
(1)添加按钮ADD,通过ClassWizard添加消息响应函数
(2)在CTestDlg中添加成员变量 CButton m_btn,
(3)在ADD的响应函数中动态创建按钮NEW
m_btn.Create("new",BS_DEFPUSHBUTTON|WS_VISIBLE|WS_CHILD,CRect(0,0,100,100),this,123);//如果在创建按钮时没有指定WS_VISIBLE风格,一定要调用这个按钮的ShowWindow函数,将该按钮控件显示出来。
(4)点击ADD会创建按钮NEW,再次点击ADD会报错,因为m_btn已经与一个按钮窗口关联,再次创建窗口并试图与m_btn关联会出现非法操作,解决办法是:判断m_btn是否已经与一个按钮关联,若是,销毁先前按钮,关联新的按钮。
if(m_bIsCreated == false)
{
m_btn.Create("new",BS_DEFPUSHBUTTON|WS_VISIBLE|WS_CHILD,CRect(0,0,\
100,100),this,123);
m_bIsCreated = true;
}
else
{
m_btn.DestroyWindow();
m_bIsCreated = false;
}
(5)上面问题的另一中解决办法:判断m_btn的窗口句柄是否为空,若为空,则没有关联按钮窗口;if(!m_btn.m_hWnd){}else{}
4.控件的访问
(1)静态文本控件
1.添加控件
2.调整控件位置(Layout菜单)
3.修改控件ID(IDC_NUMBER1)、Caption (Number1)
4.为控件添加BN_CLICKED消息响应函数
5.获得静态文本控件对象:CWnd成员函数GetDlgItem()
函数原型:CWnd* GetDlgItem(int nID)const;//这个函数返回一个由参数nID指定的控件或子窗口的指针
6.获取静态文本控件上显示的文本:CWnd类的成员函数GetWindowText()
7.设置控件的文本:CWnd类的成员函数:SetWindowText()
CString str;
if(GetDlgItem(IDC_NUMBER1)->GetWindowText(str),str=="Number1:")
{
GetDlgItem(IDC_NUMBER1)->SetWindowText("数值1:");
}
else
{
GetDlgItem(IDC_NUMBER1)->SetWindowText("Number1:");
}
8.静态文本控件在默认状态下是不发送通告信息的,打开静态文本控件的属性——Styles选项卡——选中Notify这个选项
(2)编辑框控件
1.获得编辑框中的内容:GetWindowText()函数
设置编辑框中的内容:SetWindowText()函数
int num1,num2,num3;
char ch1[10],ch2[10],ch3[10];
GetDlgItem(IDC_EDIT1)->GetWindowText(ch1,10);
GetDlgItem(IDC_EDIT2)->GetWindowText(ch2,10);
num1 = atoi(ch1);
num2 = atoi(ch2);
num3 = num1 + num2;
itoa(num3,ch3,10);
GetDlgItem(IDC_EDIT3)->SetWindowText(ch3);
2.另一种实现方法:CWnd成员函数GetDlgItemText(这个函数返回对话框中指定ID的控件上的文本(相当于GetDlgItem和GetWindowText的组合))和SetDlgItemText()
GetDlgItemText(IDC_EDIT1,ch1,10);
GetDlgItemText(IDC_EDIT2,ch2,10);
SetDlgItemText(IDC_EDIT3,ch3);
3.第三种实现方法:CWnd的成员函数GetDlgItemInt()和SetDlgItemInt()
//功能:GetDlgItemInt()返回指定控件的文本,并转换为一个整型数值
函数原型:UINT GetDlgItemInt(int nID,BOOL* lpTrans =NULL,BOOL bSigned =TRUE)const;
//1.控件ID 2.接受转换标识(错误警告) 3.指定被检索的值是否有符号
函数原型:UINT SetDlgItemInt(int nID,UINT nValue,BOOL bSigned =TRUE);
//1.控件ID 2.产生控件上文本的整型数值 3.指定被检索的值是否有符号
4.第四种实现方法:将三个编辑框分别与对话框类的三个成员变量相关联,然后通过这些成员变量来检索和设置编辑框的文本,这时最简单的访问控件的方式。
ClassWizard—Member Variables—Class name中选CTestDlg—选中控件—add Variable
(1)在DoDataExchange函数内部实现了对话框控件与类成员变量的关联(自动)
(2)在程序代码中从来不直接调用 DoDataExchange函数,而是通过CWnd类的成员函数UpdateDate来调用,通过调用后者来初始化对话框控件或从对话框获取数据。
函数原型:BOOL UpdateData(BOOL bSaveAndValidata = TRUE);
//参数值为TRUE说明函数正在获取对话框的数据,FALSE说明函数正在初始化对话框控件
UpdateData(true);
m_value3 = m_value1 + m_value2;
UpdateData(false);
(3)在关联控件和类成员变量时不仅可以设置变量类型,还可以设置取值范围
MFC提供了多个以DDV_为前缀的数据校验函数。(DDX对话框数据交换 DDV对话框数据校验)
5.第五种实现方式:把编辑框控件再与一个变量相关联,与上面不同的是,此次关联的是一个控件变量,即代表控件本身
(1)ClassWizard打开增加成员变量对话框,这次变量的类别不选Value,选Control,变量类型自动成为CEdit(派生于CWnd)
(2)利用控件变量调用GetWindowText和SetWindowText函数
m_edit1.GetWindowText(ch1,10);
6.第六种实现方式:通过获取或设置窗口文本的消息,获取或设置窗口文本
(1)获取窗口文本的消息是WM_GETTEXT,发送该消息后,系统将把指定窗口的文本复制到调用者提供的一个缓冲中,在这个消息的两个附加参数中,wParam指定将复制的字符数,lParam就是调用者提供的用来保存窗口文本的缓存地址
(2)设置窗口文本的消息是WM_SETTEXT,这个消息的wParam参数没有使用,值为0,lParam指定了用来设置窗口文本的字符串地址
(3)利用SDK的SendMessage函数实现(先获得按钮窗口对象成员变量—句柄)
int num1,num2,num3;
char ch1[10],ch2[10],ch3[10];
::SendMessage(GetDlgItem(IDC_EDIT1)->m_hWnd,WM_GETTEXT,10,(LPARAM)ch1);
::SendMessage(GetDlgItem(IDC_EDIT2)->m_hWnd,WM_GETTEXT,10,(LPARAM)ch2);
num1 = atoi(ch1);
num2 = atoi(ch2);
num3 = num1 + num2;
itoa(num3,ch3,10);
::SendMessage(GetDlgItem(IDC_EDIT3)->m_hWnd,WM_SETTEXT,0,(LPARAM)ch3);
7.第七种方法:也是通过发送消息来完成对控件的访问,但是直接给对话框的子控件发送消息,使用函数SendDlgItemMessage()(不是全局函数,是类成员函数)
函数原型:LRESULT SendDlgItemMessage(int nID,UINT message,WPARAM wParam = 0,LPARAM lParam = 0);
//第一个参数指定将接受当前发送的这条消息的对话框控件,后三个参数和SendMessage
//相同,实际上,这个函数功能相当于把SendMessage函数和GetDlgItem函数组合起来
SendDlgItemMessage(IDC_EDIT1,WM_GETTEXT,10,(LPARAM)ch1);
(1) EM_GETSET消息,获取编辑框中复选内容(EM_开头的都是编辑框消息)
(2) SetFocus函数将焦点转移到所选的控件上
5.对话框伸缩功能的实现
(1)添加一个按钮 收缩<<
(2)添加消息响应函数
(3)添加分割条(图片画线实现,选择Styles选项卡中的Sunken,下陷效果)
(4)添加代码
CString str;
if(GetDlgItem(IDC_BUTTON1)->GetWindowText(str),str=="收缩<<")
{
GetDlgItem(IDC_BUTTON1)->SetWindowText("展开>>");
}
else
{
GetDlgItem(IDC_BUTTON1)->SetWindowText("收缩<<");
}
static CRect rectLarge;//静态变量,坐标都初始化为零
static CRect rectSmall;
if(rectLarge.IsRectNull())
{
CRect rectSeparator;
GetWindowRect(&rectLarge);
GetDlgItem(IDC_SEPERATOR)->GetWindowRect(&rectSeparator);
rectSmall.left = rectLarge.left;
rectSmall.top = rectLarge.top;
rectSmall.right = rectLarge.right;
rectSmall.bottom = rectSeparator.bottom;
}
if(str == "收缩<<")
{
SetWindowPos(NULL,0,0,rectSmall.Width(),rectSmall.Height(),SWP_NOMOVE|SWP_NOZORDER);
}
else
{
SetWindowPos(NULL,0,0,rectLarge.Width(),rectLarge.Height(),SWP_NOMOVE|SWP_NOZORDER);
}
解释:(1)CRect类有两个成员函数可以用来判断一个矩形是否为空IsRectEmpty():检测矩形区域是否为空,为空返回非零值;IsRectNull():如果矩形的左上角和右下角的四个坐标值都为零,则返回一个非零值。
(2)GetWindowRect()获取对话框窗口或控件窗口尺寸(调用该函数得到一个矩形)
(3)SetWindowPos函数设置对话框的大小
函数原型:BOOL SetWindowPos(const CWnd* pWndInsertAfter,int x,int y,int cx,int cy,UINT nFlags) //该函数的作用是设置窗口的位置和大小
// pWndInsertAfter,标识一个CWnd对象(窗口的Z次序排序-窗口重叠),这个参数可以是//指向某个CWnd对象的指针也可以是wndBottom,wndtop等
//x,y,窗口左上角坐标 cx,cy窗口的宽度和高度
//nFlags设定窗口的尺寸和定位(各种预定义值的组合)
6.输入焦点的传递
(1)对话框默认按钮(styles选项卡 Default button)如事先不选择任何按钮,在对话框中按下回车键,默认按钮的消息响应函数会来处理这一事件
(2)实现在第一个编辑框中按下回车键后,输入焦点转移到第二个编辑框的功能:可以捕获键盘按键消息,在消息响应函数中把焦点移动到下一编辑框控件
两种实现方式:
1.为编辑框控件生成一个相关联的类,然后利用这个类来捕获键盘按键消息
2.修改编辑框控件的窗口过程函数(窗口过程是在定义窗口类时设置的,当窗口
创建之后怎样去修改?SetWindowLong()函数可以实现
函数原型:LONG SetWindowLong(HWND hWnd,int nIndex,LONG dwNewLong);
//该函数的作用是改变指定窗口的属性
// hWnd 想要改变其属性的窗口句柄
// nIndex 要设置的属性值的偏移地址,若取值SWL_WNDPROC:设置一个新的窗口过程
// dwNewLong指定设置的新值
//若调用成功,函数将返回原先为窗口指定的属性(32位整型)
(1)当对话框及其上的控件创建完成后,显示前,会发送一个消息WM_INITDIALOG
(2)添加消息响应函数,在其中调用SetWindowLong()改变控件窗口过程 prevProc=(WNDPROC)SetWindowLong(GetDlgItem(IDC_EDIT1)->m_hWnd,GWL_WNDPROC,
(LONG)NewEditProc);
(3)定义全局变量和全局函数
WNDPROC prevProc;
LRESULT CALLBACK NewEditProc(HWND hwnd,UINT uMsg,WPARAM wParam, LPARAM lParam)
{
if(uMsg == WM_CHAR && wParam == 0x0d)
{
::SetFocus(GetNextWindow(hwnd,GW_HWNDNEXT));
return 1;
}
else
{
return prevProc(hwnd,uMsg,wParam,lParam);
}
}
(4)设置焦点可以用SetFocus实现:HWND SetFocus(HWND hwnd);因为NewEditProc这个窗口过程是全局函数,所以不能调用CWnd的成员函数,只能用相应的SDK函数
(5)获得对话框中某个控件的下一个控件的句柄:GetNextWindow()函数
函数原型:HWND GetNextWindow(HWND hWnd,UINT wCmd);
//这个函数返回指定窗口的下一个窗口的句柄,参数中第一个是当前窗口句柄
//第二个参数是查找的方向 CW_HWNDNEXT:下一个 CW_HWNDPREV:上一个
//layout tab order菜单项可以设置各控件的Tab顺序
3. 另一中获得窗口句柄的方法: GetWindow()
函数声明:HWND GetWindow(HWND hWnd,UINT uCMD);//该函数返回与指定窗口有特定关系的窗口句柄 (Z次序)
4.第三种得到窗口句柄的方法:GetNextDlgTabItem(),该函数将返回指定控件前面或后面的一个具有WS_TABSTOP风格的按钮(属性)