对话框分为模态(Modal)对话框和非模态(Modeless)对话框两种。模态对话框是指当其显示时,程序会暂停执行,直到关闭这个模态对话框后,才能继续执行程序中其他任务。非模态对话框显示时,允许转而执行程序中其他任务,而不用关闭这个对话框。对话框也是一种资源,可以在资源视图中新建一个对话框来实现。与对话框相关的是CDialog类,当我们使用类向导时,编译器自动检测出我们添加了一个资源,提示我们是否需要为他创建一个类,然后编译器会自动将我们的资源,以及基类选择好,我们只需要填写类名就可以了。编译器为这个类编写了两个函数:1.构造函数2.DoDataExchange,用来完成数据的交换和校验。
首先,新建一个对话框工程项目MFCApplication,然后资源视图/Dialog/插入Dialog/在新插入的Dialog对话框上添加类,接着在MFCApplication对应的对话框中添加一个按钮“Start Modal”用来启动新插入的Dialog对话框,并在Dialog对话框添加消息响应函数:建立一个DialogDlg对像,调用DoModal函数来实现模态对话框:
void CMFCApplicationDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
DialogDlg dlg;
dlg.DoModal();
}
注意,还得自己包含#include "Dialog.h",因为这句代码类向导并没有帮助添加。
void CMFCApplicationDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
DialogDlg dlg;
dlg.Create(IDD_DIALOG, this);
dlg.ShowWindow(SW_SHOW);
}
可是程序编译后依然没有显示,这是为什么呢?因为这里的dlg是一个局部变量,程序执行完以后,就析构了。那为什么前面的模态对话框就可以呢?因为模态对话框创建之后,程序就停在了这里,所以他的生命周期并没有结束。那么怎么解决呢?
1.把这个对话框变量定义为全局变量。
2.定义一个指针,指向堆上的数据:
void CMFCApplicationDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
DialogDlg* pDlg = new DialogDlg;
pDlg->Create(IDD_DIALOG, this);
pDlg->ShowWindow(SW_SHOW);
}
虽然这样做可以实现功能,但是并不好,因为pDlg会在程序结束时被释放,所以我们以后就拿不到这个指针了,自然也就无法释放它,会造成内存泄露。这个问题可以通过将指针定义为类的成员变量来解决。
还有一点区别在于:对于模态对话框,点击“确定”后,对话框是被“销毁了”;而对于非模态对话框,则是“隐藏了”,你需要重写虚函数OnOK,并在其中调用DestroyWindow ,基类的OnOK只是调用了EndDialog来隐藏对话框。
程序运行结果:
void CMFCApplicationDlg::OnBnClickedBtnAdd()
{
// TODO: 在此添加控件通知处理程序代码
m_btn.Create(_T("TEST"), BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
CRect(0, 0, 100, 100), this, 123);
}
运行程序,点击ADD按钮,的确会显示一个新的“TEST”按钮,但是当再次点击时,就会报错,是因为当我们点击时,会调用OnBnClickedBtnAdd通过Create函数创建一个按钮;但是如果再次点击,那么还会调用Create函数将按钮与m_btn关联,可是m_btn已经和第一次创建的按钮相关联了,所以会出错。为此,可以通过增加一个成员变量m_bIsCreate来记录窗口是否已经创建,如果创建,那么就会销毁窗口,而在下一次点击时,就又可以创建了:
void CMFCApplicationDlg::OnBnClickedBtnAdd()
{
// TODO: 在此添加控件通知处理程序代码
//static BOOL bIsCreated = FALSE;
if (m_bIsCreate == FALSE)
{
m_btn.Create(_T("TEST"), BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
CRect(0, 0, 100, 100), this, 123);
m_bIsCreate = TRUE;
}
else
{
m_btn.DestroyWindow();
m_bIsCreate = FALSE;
}
}
void CMFCApplicationDlg::OnBnClickedBtnAdd()
{
// TODO: 在此添加控件通知处理程序代码
if (!m_btn.m_hWnd)
{
m_btn.Create(_T("TEST"), BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
CRect(0, 0, 100, 100), this, 123);
//m_bIsCreate = TRUE;
}
else
{
m_btn.DestroyWindow();
//m_bIsCreate = FALSE;
}
}
void CMFCApplicationDlg::OnStnClickedNumber1()
{
// TODO: 在此添加控件通知处理程序代码
CString str;
if (GetDlgItem(IDC_NUMBER1)->GetWindowText(str), str == _T("Number1:"))
{
GetDlgItem(IDC_NUMBER1)->SetWindowText(_T("数值1:"));
}
else
{
GetDlgItem(IDC_NUMBER1)->SetWindowText(_T("Number1:"));
}
}
void CMFCApplicationDlg::OnBnClickedBtnAdd()
{
// TODO: 在此添加控件通知处理程序代码
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_s(num3, ch3, 10);
GetDlgItem(IDC_EDIT3)->SetWindowText(ch3);
}
方法二:跟方法一类似,但使用
GetDlgItemText和SetDlgItemText完成了方法一中需要通过两步才能完成的工作。
void CMFCApplicationDlg::OnBnClickedBtnAdd()
{
int num1, num2, num3;
char ch1[10], ch2[10], ch3[10];
GetDlgItemText(IDC_EDIT1,ch1,10);
GetDlgItemText(IDC_EDIT2, ch2, 10);
num1 = atoi(ch1);
num2 = atoi(ch2);
num3 = num1 + num2;
_itoa_s(num3, ch3, 10);
SetDlgItemText(IDC_EDIT3, ch3);
}
方法三:通过使用GetDlgItemInt函数直接通过控件ID获取空间的文本,并且将它转化为int类型,再使用SetDlgItemInt函数完成显示。
void CMFCApplicationDlg::OnBnClickedBtnAdd()
{
int num1 = GetDlgItemInt(IDC_EDIT1);
int num2 = GetDlgItemInt(IDC_EDIT2);
int num3 = num1 + num2;
SetDlgItemInt(IDC_EDIT3,num3);
}
方法四:
int m_num1;
int m_num2;
int m_num3;
源文件的构造函数中:
CMFCApplicationDlg::CMFCApplicationDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CMFCApplicationDlg::IDD, pParent)
, m_num1(0)
, m_num2(0)
, m_num3(0)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_bIsCreate = FALSE;
}
在源文件的DoDataExchange中:
void CMFCApplicationDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, m_num1);
DDX_Text(pDX, IDC_EDIT2, m_num2);
DDX_Text(pDX, IDC_EDIT3, m_num3);
}
DDX_TEXT函数用来将ID指定的控件与特定的类成员变量相关联。既然编辑框控件已经与类成员变量相关联了,那么就可以直接利用这些相关联的变量来编程实现上述所需功能了。如果真是这样子简单,那么我们只要在OnBnClickedBtnAdd函数中添加如下一行代码即可了:
void CMFCApplicationDlg::OnBnClickedBtnAdd()
{
m_num3 = m_num1 + m_num2;
}
运行程序后发现,在前两个编辑框中输入两个数值后,单击“ADD”按钮第三个编辑框中并没有出现所期待的结果。可以发现:不管输入多少,执行到m_num3 = m_num1 + m_num2时,m_num1和m_num2的值总为0。DoDataExchange函数不是直接调用的,而是通过UpdataData函数调用的。而UpdateData函数有一个参数:当参数为true时(默认),是从对话框获取数据,当参数为false时,是向对框写数据。于是只是将程序改为如下就可以了:
void CMFCApplicationDlg::OnBnClickedBtnAdd()
{
UpdateData();
m_num3 = m_num1 + m_num2;
UpdateData(FALSE);
}
因为我们把编辑框控件与一个int型的变量相关联了,所以如果我们在编辑框中输入一个非数值型的字符,然后点击“ADD”按钮,程序会弹出一个对话框,提示:“请键入一个整数”。
void CMFCApplicationDlg::OnBnClickedBtnAdd()
{
// TODO: 在此添加控件通知处理程序代码
int num1, num2, num3;
char ch1[10], ch2[10], ch3[10];
m_edit1.GetWindowTextA(ch1,10);
m_edit2.GetWindowTextA(ch2, 10);
num1 = atoi(ch1);
num2 = atoi(ch2);
num3 = num1 + num2;
_itoa(num3,ch3,10);
m_edit3.SetWindowTextA(ch3);
}
void CMFCApplicationDlg::OnBnClickedBtnAdd()
{
// TODO: 在此添加控件通知处理程序代码
int num1, num2, num3;
char ch1[10], ch2[10], ch3[10];
::SendMessage(m_edit1.m_hWnd, WM_GETTEXT, 10, (LPARAM)ch1);
::SendMessage(m_edit2.m_hWnd, WM_GETTEXT, 10, (LPARAM)ch2);
num1 = atoi(ch1);
num2 = atoi(ch2);
num3 = num1 + num2;
_itoa(num3,ch3,10);
m_edit3.SendMessage(WM_SETTEXT,0,(LPARAM)ch3);
}
注意:
void CMFCApplicationDlg::OnBnClickedBtnAdd()
{
// TODO: 在此添加控件通知处理程序代码
int num1, num2, num3;
char ch1[10], ch2[10], ch3[10];
SendDlgItemMessage(IDC_EDIT1, WM_GETTEXT, 10, (LPARAM)ch1);
SendDlgItemMessage(IDC_EDIT2, WM_GETTEXT, 10, (LPARAM)ch2);
num1 = atoi(ch1);
num2 = atoi(ch2);
num3 = num1 + num2;
_itoa(num3,ch3,10);
SendDlgItemMessage(IDC_EDIT3,WM_SETTEXT, 0, (LPARAM)ch3);
}
使用成员函数,就省去了获取编辑框的工作。
SendDlgItemMessage(IDC_EDIT3,EM_SETSEL, 1, 2);
m_edit3.SetFocus();