Windows系统中最常用最简单的一类对话框——消息对话框。
MFC提供了两个函数可以直接生成指定风格的消息对话框,而不需要我们在每次使用的时候都要去创建对话框资源和生成对话框类等。
这两个函数就是CWnd类的成员函数MessageBox()和全局函数AfxMessageBox()。
参数说明:
lpszText:需要显示的消息字符串。
lpszCaption:消息对话框的标题字符串。默认值为NULL。取值为NULL时使用默认标题。
nType:消息对话框的风格和属性。默认为MB_OK风格,即只有“确定”按钮。
nType的取值可以是下面两个表中任取一个值,也可以是各取一个值的任意组合。即可以指定一个对话框类型,也可以指定一个对话框图标,还可以两者都设定。
参数说明:
lpszText:同CWnd::MessageBox()函数
nType:CWnd::MessageBox()函数
nIDHelp:此消息的帮助的上下文ID。默认值为0,取0时表示要使用应用程序的默认帮助上下文。
在调用了上面两个函数后,都可以弹出模态消息对话框。
消息对话框关闭后,我们也都可以得到它们的返回值。
两者的返回值就是用户在消息对话框上单击的按钮的ID,可以是以下值。
从整数计算器的界面中可以看出,该程序主要是应用按钮和文本编辑框控件,重点是如何正确处理各个按钮的响应函数,使每一个数字按钮或运算符按钮单击后都能显示正确的结果。
【编程步骤】
建立“基于对话框”的MFC工程Int_Calculator。
删除主对话框中自动生成的默认控件。
添加如图所示的按钮控件和编辑框控件。布局如图所示,各控件ID如下表所示。
为所有的按钮添加单击响应函数。
为IDC_VALUE文本编辑框添加int类型的关联变量m_nValue。
在Int_CalculatorDlg.h文件中添加如下变量:
int m_nOperand1; //操作数1
int m_nOperand2; //操作数2
int m_nOperator; //运算符标识
BOOL m_bOperator; //是否已经按了操作符
在Int_CalculatorDlg.cpp文件中的CInt_CalculatorDlg类构造函数中添加如下代码:
m_nOperand1 = 0;
m_nOperand2 = 0;
m_nOperator = -1;
m_bOperator = FALSE;
编写操作数按钮函数。
在整数计算器中,操作数需要通过数字按钮录入,那么如何将数字按钮的单击转换为实际的数值呢?
以数字“0”按钮为例讲述数字按钮的响应过程。
void CInt_CalculatorDlg::OnClickedB0()
{
m_nValue = m_nValue*10 + 0;
UpdateData(FALSE);
}
将m_nValue乘10加上0,当m_nValue值为0时,可以避免出现连续多个无意义的0,当m_nValue值不为0时,又可以得到正确的结果。最后调用UpdateData(FALSE)函数进行数据交换,更新界面显示内容。
其他数字按钮的响应函数与数字“0”按钮类似,仅列出数字“1”按钮的响应函数。
void CInt_CalculatorDlg::OnClickedB1()
{
m_nValue = m_nValue*10 + 1;
UpdateData(FALSE);
}
编写运算符按钮响应函数。
当单击运算符按钮时,除需要设置m_nOperator的数值和m_bOperator外,还应该将用户录入的数值保存起来,并将m_nValue置0,为录入下一个操作数做准备。
以“+”按钮为例,其响应函数为:
void CInt_CalculatorDlg::OnClickedBadd()
{
m_nOperator = 1; //置1表示加法,2表示减法,3表示乘法,4表示除法
m_bOperator = TRUE;
m_nOperand1 = m_nValue;
m_nValue = 0;
}
注意,在此不需要调用UpdateData(FALSE)函数,因为当按运算符时文本编辑框中仍然显示第一个操作数。
编写“=”按钮响应函数。
当单击“=”按钮时,首先需要判断是否单击过运算符,然后根据运算符标识进行相应的计算,并显示结果。
void CInt_CalculatorDlg::OnClickedBequal()
{
if(m_bOperator == FALSE) //判断是否单击过运算符
{
AfxMessageBox(_T("输入错误,请单击运算符"));
return;
}
m_nOperand2 = m_nValue; //获得第二个操作数
switch(m_nOperator) //根据运算符表示计算
{
case 1: m_nValue = m_nOperand1 + m_nOperand2; break;
case 2: m_nValue = m_nOperand1 - m_nOperand2; break;
case 3: m_nValue = m_nOperand1 * m_nOperand2; break;
case 4:
if(m_nOperand2 == 0)//判断除数是否为0
{
AfxMessageBox(_T("被除数不能为零,请重新计算!"));
OnBnClickedBc(); //清空所有标识,即“C”按钮响应函数
}
else
m_nValue = m_nOperand1 / m_nOperand2;
break;
}
UpdateData(FALSE);//显示计算结果
m_nValue = 0;//为下一次运算作准备
}
在后面加一句m_nOperand1 = m_nValue;还可以实现连续计算的功能
[update 1]经验证这样上面划了删除线的方法不行,需要大面积改动之前的代码,原本的代码设计并不能很好的实现连续运算
[update 2]上面的函数有bug:比如点击12+12然后点=,之后再点=上面会变成12
原因是中间计算结果没有清除 ,需要修改为:
m_nValue = 0;
m_nOperand1 = 0;
m_nOperand2 = 0;
m_nOperator = -1;
m_bOperator = FALSE;
编写“C”按钮响应函数。
在整数计算器中,还有一个按钮功能未完成,即“C”,其功能是清除所有信息,包括保存在m_nOperand1和m_nOperand2中的数值。
void CInt_CalculatorDlg::OnClickedBc()
{
// TODO: 在此添加控件通知处理程序代码
m_nValue = 0;
m_nOperator = -1;//置运算符标识
m_bOperator = FALSE;//置标识位
m_nOperand1 = 0;//清空数据
m_nOperand2 = 0;
UpdateData(FALSE);//更新显示
}
最后编译、链接、运行。
整数计算器采用十进制整数进行运算,除此之外整数还有十六进制、八进制和二进制表示方式,Windows系统的计算器就具有该功能。
本节将参照其功能,实现十进制与八进制之间的相互转换,并从中学习单选按钮和复选框控件的使用方法。
【分析】在实现功能之前,首先需要考虑整数的不同进制如何转换?
对于一个整数,无论是十进制还是八进制都只是在显示方式上有所区分,其本质仍然是同一个数值。也就是说一个整数变量的数值可以以八进制或者十进制显示,但是其使用的存储变量只能是十进制的整型变量。
单选按钮由一个圆圈和文本标签组合而成,当它被选中时,圆圈中就标上一个黑点。
单选按钮通常是分组使用,同一组的单选按钮具有互斥性,即某一单选按钮被选中会清除同组内其他单选按钮的选中状态。
通过勾选某一单选按钮Radio Button Properties对话框中General选项卡的Group选项,标识某一组单选按钮的开始。
1.打开Int_Calculator工程,添加2个单选按钮,如图所示,其ID值分别为
IDC_RADIODEC和IDC_RADIOOCT。
2. 选中IDC_RADIODEC控件Properties中置Group选项为“True”。
3.为IDC_RADIODEC添加关联变量m_nChoice,并且在Cint_CalculatorDlg类的构造函数中已经将其初始化为0,表示10进制为默认选项。
自动生成的代码
4. 打开ClassWizard的“命令”选项卡,为IDC_RADIODEC和IDC_RADIOOCT添加BN_CLICKED消息,生成OnRadiodec()和OnRadiooct()函数,并添加如下代码 :
void CIntegerCalculatorDlg::OnBnClickedRadioOct()
{
CButton *p8 = ((CButton*)GetDlgItem(IDC_B8));
//通过ID得到按钮控件对象的指针
p8->EnableWindow(FALSE); //使按钮不可用
CButton *p9 = ((CButton*)GetDlgItem(IDC_B9));
p9->EnableWindow(FALSE);
transform(); //进制转换
}
其中GetDlgItem()函数的功能是根据控件ID获取对话框中控件的句柄,其函数声明为:
CWnd* GetDlgItem(int nID) const;
其中nID为控件的ID值。
而EnableWindow()函数是CWnd类的成员函数,功能是使窗口允许或禁止,其函数声明为:
BOOL EnableWindow( BOOL bEnable = TRUE );
其中bEnable为TRUE,则窗口被允许,为FALSE,则窗口将被禁止。
void Int_CalculatorDlg::OnBnClickedRadioDec()
{
CButton *p8 = ((CButton*)GetDlgItem(IDC_B8));
//通过ID得到按钮控件对象的指针
p8->EnableWindow(TRUE); //使按钮可用
CButton *p9 = ((CButton*)GetDlgItem(IDC_B9));
p9->EnableWindow(TRUE);
transform(); //进制转换
}
单击该单选按钮,即计算器按照10进制显示计算中需要使用的按钮,同时计算结果也以10进制数显示。
数制转换这件事就交给transform()函数来解决。
6.编写transform()函数
在Int_CalculatorDlg.h文件中添加函数声明void transform();,在IntegerCalculatorDlg.cpp文件中添加如下代码。
void Int_CalculatorDlg::transform()
{
UpdateData(TRUE); //获得数据
if(m_nChoice== 0) //10进制单选按钮被选中
m_nValue = octToDec(m_nValue); //将8进制转换为10进制
else //8进制单选按钮被选中
{
char s8[30];
itoa(m_nValue,s8,8); //将10进制转换为8进制
m_nValue = atoi(s8);
}
UpdateData(FALSE); //更新界面,显示转换后结果
}
其中octToDec()函数为自定义函数,功能是将八进制数值转换为十进制数值,函数代码如下:
int Int_CalculatorDlg::octToDec(int value)
{
int result=0; //结果变量
int num = 0; //次幂变量
while (value != 0)
{
int low = value%10; //取个位数
int mul = 1;
for(int i=0;i<num;i++) //该位数为8的num次幂
mul *= 8;
result = result + low*mul; //累加结果
num++;
value = value/10; //去掉个位数
}
return result; //返回计算结果
}
7 修改计算过程,在OnBequal()函数做如下修改:
void Int_CalculatorDlg ::OnBequal()
{
……
m_nOperand2 = m_nValue;
if(m_nChoice == 1) //如果是8进制
{
m_nOperand1 = octToDec(m_nOperand1); //将运算数转换为10进制
m_nOperand2 = octToDec(m_nOperand2);
}
switch(m_nOperator) {
……
}
if(m_nChoice == 1) //如果是8进制
{
char s8[30];
itoa(m_nValue,s8,8); //将计算结果以8进制显示
m_nValue = atoi(s8);
}
……
}
8 编译、链接、运行。
为了实现进制功能的开启与关闭,采用复选框控件作为切换控件。
标准的复选框在文本标签旁边有一个方框,当该选项被选中时,方框内出现一个“√”号,当该项未被选中时,方框内空白。
1 添加复选框控件IDC_CHECK_FLAG。
2 打开ClassWizard的Message Maps选项卡,为IDC_CHECK_FLAG添加BN_CLICKED消息,生成OnClickedCheckFlag()函数。
3 在OnClickedCheckFlag ()函数中添加如下代码:
void Cinte_CalculatorDlg::OnClickedCheckFlag()
{
CButton *pChoice = ((CButton*)GetDlgItem(IDC_CHECKCHOICE));
//如果复选框选中
if(BST_CHECKED==pChoice->GetCheck())
{
CButton *pDec =
((CButton*)GetDlgItem(IDC_RADIODEC));
pDec->EnableWindow(TRUE);
CButton *pOct =
((CButton*)GetDlgItem(IDC_RADIOOCT));
pOct->EnableWindow(TRUE);
}
else
{
CButton *pDec =
((CButton*)GetDlgItem(IDC_RADIODEC));
pDec->EnableWindow(FALSE);
CButton *pOct =
((CButton*)GetDlgItem(IDC_RADIOOCT));
pOct->EnableWindow(FALSE);
}
}
GetCheck()函数的功能是获得复选框的选中状态,其函数声明为:
int GetCheck() const;
其返回值为
0:按钮处于未选中状态。
1:按钮处于选中状态。
2:按钮状态不定(仅当按钮风格为BS_3STATE或BS_AUTO3STATE时)如果按钮是其它风格,则返回0。
为了代码清晰,系统为其做了宏定义:
#define BST_UNCHECKED 0x0000
#define BST_CHECKED 0x0001
#define BST_INDETERMINATE 0x0002
4 为了使对话框在初始运行时保持正常状态,需在OnInitDialog()函数中添加如下代码:
BOOL Cint_CalculatorDlg::OnInitDialog()
{
……
SetIcon(m_hIcon, FALSE); // Set small icon
CButton *pDec = ((CButton*)GetDlgItem(IDC_RADIODEC));
pDec->EnableWindow(FALSE);
CButton *pOct = ((CButton*)GetDlgItem(IDC_RADIOOCT));
pOct->EnableWindow(FALSE);
……
}
5 编译、链接、运行。