用VC++做计算器.docx
《用VC++做计算器.docx》由会员分享,可在线阅读,更多相关《用VC++做计算器.docx(33页珍藏版)》请在冰豆网上搜索。
用VC++做计算器
用VC++做计算器
在这一章,要实现一个简单计算器。
其类似于Windows附件中自带的计算器。
实际
效果如图3-1所示,这个计算器不仅实现了简单的四则运算功能,还实现了高级的科学
计算功能,而且具有简洁大方的图文外观。
该计算器具有一个菜单栏,一个编辑框及若
干按键。
编辑框可以用任何指定的字体和颜色显示文本。
按钮控件具有对鼠标敏感的功
能,当鼠标处于不同的位置和状态时,按钮控件会显示不同的颜色,并且所有按钮控件
的客户区域为椭圆或圆形。
其实际效果如图3-1所示:
图3-1计算器示例效果图
●为对话框添加菜单。
●制定高级按钮控件,该按钮具有不规则的形状,并可以根据用户鼠标的位置和点
击状态的不同,显示不同的颜色。
●制定高级编辑控件,该编辑控件可以指定文本文字的字体和颜色。
●实现对话框的扩展功能。
3.1窗体设计
该计算器是基于对话框的应用程序,利用MFCAppWizard生成应用计算器应用程
序框架,具体步骤如下:
(1)执行VC程序,选择FILE|New命令,弹出New对话框,单击Projects选项卡,
选择MFCAppWizard(exe)选项,然后在ProjectName文本框中输入Calculator。
Location
文本框是指项目的本地路径,这里读者可以自行设定。
保持Platform里的Win32复选框
不变。
如图3-2所示。
(2)单击OK按钮,弹出MFCAppWizard-Step1对话框。
选择DialogBased单选
按钮。
如图3-3所示。
VisualC++简明教程
图3-2New对话框
图3-3MFCAppWizard-Step1对话框
(3)单击Next按钮,弹出MFCAppWizard-Step2of6对话框。
如图3-4所示。
(4)单击Next按钮,弹出MFCAppWizard-Step3of6对话框,如图3-5所示。
图3-4MFCAppWizard-Step2对话框
图3-5MFCAppWizard-Step3对话框
(5)单击Next按钮,弹出MFCAppWizard-Step4of6对话框。
如图3-6所示。
点击Finish按钮,创建框架。
图3-6MFCAppWizard-Step4对话框
3.2编辑资源
因为在利用MFCAppWizard生成计算器工程时,选择的应用程序类型是对话框应
用程序,所以工程刚建立时,就已经具有如图3-7所示的对话框资源。
图3-7初始状态的对话框资源
接下来就在它的基础上,编辑和添加其它的资源。
3.2.1编辑对话框及控件资源
利用VisualC++提供的资源编辑器对对话框资源进行编辑。
删除对话框上默认的
OK和Cancel按钮。
添加一个Edit控件,其控件ID为IDC_DSPEDIT。
添加若干按扭控
件,其ID如表3-1所示。
表3-1按扭控件资源清单
按钮名称
按钮ID
用途
0
BTN_0
BTN_1
BTN_2
BTN_3
BTN_4
BTN_5
BTN_6
BTN_7
BTN_8
BTN_9
按键0
按键1
按键2
按键3
按键4
按键5
按键6
按键7
按键8
按键9
小数点
求值
1
2
3
4
5
6
7
8
9
.
BTN_10
BTN_11
BTN_12
BTN_13
BTN_14
BTN_15
BTN_16
BTN_17
BTN_18
BTN_19
=
+
加号
-
减号
*
乘号
/
除号
CE
sqrt
1/x
sin
清屏
开方
倒数
正弦
VisualC++简明教程
cos
tan
x^2
x^3
x^y
exp
ln
BTN_20
BTN_21
BTN_22
BTN_23
BTN_24
BTN_25
BTN_26
BTN_27
作弦
正切
平方
立方
以x为底的y次幂
以e为底的幂
以e为底的对数
对数
log
并且添加三个静态框,将编辑控件、普通计算、高级计算分别分组。
其效果如图3-8
所示:
图3-8编辑对话框资源
3.2.2编辑菜单资源
下面为计算器添加一个菜单资源。
在VisualC++中的Workspace工具条中,选中
ResourceView选项卡。
在其中的Menu项上单击鼠标右键,在弹出的快捷菜单中选择
InsertMenu命令。
如图3-9所示。
图3-9添加菜单资源
这样就为计算器添加了一个菜单资源,将其ID更改为IDR_MENU。
利用资源编辑
器对菜单进行编辑。
编辑后的菜单如图3-10所示。
图3-10编辑菜单资源
3.3实现高级按钮控件类
利用ClassWizard添加一个新类。
如图3-11所示:
图3-11添加CAdvButton类
添加新类名称为CAdvButton,其父类为CButton类。
我们就在这个类中实现高级的
按钮控件。
3.3.1添加成员变量和成员函数
要实现的高级按钮控件需要对鼠标的移动和点击作出相应的颜色变化。
首先在
CAdvButton的头文件里加入几种预定义颜色,其代码如下:
#defineDesiableColorRGB(192,192,192)
//灰色,按钮不可用
//红色,按钮拥有焦点
//绿色,按钮被按下
//蓝色,默认
#defineFocusColor
#defineSelectColor
#defineDefaultColor
#defineTextColor
RGB(255,0,0)
RGB(0,255,0)
RGB(0,0,255)
RGB(128,128,128)
//浅灰色,文本颜色
如果读者需要将按钮设定为其它颜色,那么只需改动上面的预定义即可。
接下来,添加成员变量:
public:
CRect
CRgn
m_ClientRect;
//用来保存按钮的客户的矩形区域
m_ClientRgn;//用来保存按钮的客户区域,非矩形
BOOL
m_IsTimerOn;
//标志计时器是否已经打开
VisualC++简明教程
UINT
m_State;
//按钮所处状态
//当前鼠标位置
CPoint
m_Point;
利用ClassWizard添加下列消息映射和响应函数:
//消息响应函数
protected:
//{{AFX_MSG(CAdvButton)
afx_msgintOnCreate(LPCREATESTRUCTlpCreateStruct);
afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);//
//
afx_msgvoidOnLButtonUp(UINTnFlags,CPointpoint);
afx_msgvoidOnMouseMove(UINTnFlags,CPointpoint);
//
//
afx_msgvoidOnTimer(UINTnIDEvent);
//}}AFX_MSG
//处理ON_WM_TIMER消息
//消息映射
//{{AFX_MSG_MAP(CAdvButton)
ON_WM_CREATE()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_TIMER()
//}}AFX_MSG_MAP
WM_CREATE消息当创建窗口时被触发,其响应函数为OnCreate。
WM_LBUTTONDOWN消息当用户鼠标左键按下时被触发,其响应函数为
OnLButtonDown。
WM_LBUTTONUP消息当用户鼠标左键抬起时被触发,其响应函数
为OnLButtonUp。
WM_MOUSEMOVE消息当用户鼠标移动时被触发,其响应函数为
OnMouseMove。
WM_TIMER消息当计时器到达时被触发,其响应函数为OnTimer。
再利用ClassWizard覆盖父类中的两个关键的虚函数:
//{{AFX_VIRTUAL(CAdvButton)
public:
virtualvoidDrawItem(LPDRAWITEMSTRUCTlpDrawItemStruct);
protected:
virtualvoidPreSubclassWindow();
//}}AFX_VIRTUAL
其中对于所有的对于按钮的绘制工作都是在DrawItem函数中完成的。
3.3.2添加创建按钮控件代码
按钮的创建分两步完成。
首先,调用构造函数对按钮对象进行初始化;其次,调用
Create函数创建按钮。
在构造函数中,对所有成员变量进行初始化。
实现代码如下:
//构造函数
CAdvButton:
:
CAdvButton()
{
//初始化m_ClientRect
m_ClientRect.left
m_ClientRect.top
=0;
=0;
m_ClientRect.right=0;
m_ClientRect.bottom=0;
m_ClientRgn.DeleteObject();
//删除区域对象
m_ClientRgn.CreateEllipticRgnIndirect(&m_ClientRect);
//创建椭圆区域
m_State=0;
m_Point.x=m_Point.y=0;
m_IsTimerOn=FALSE;
}
重载父类中的Create虚函数。
实现代码如下:
//重载父类Create函数
BOOLCAdvButton:
:
Create(LPCTSTRlpszCaption,DWORDdwStyle,constRECT&rect,
CWnd*pParentWnd,UINTnID)
{
returnCButton:
:
Create(lpszCaption,dwStyle,rect,pParentWnd,nID);
}
3.3.3设置按钮形状、外观、颜色、标题
要创建用户自绘制按钮,必须将按钮的风格设为BS_OWNERDRAW。
因为只有设
置了这一属性,那么当按钮控件的可见部分需要重绘时,Windows才会调用
CAdvButton:
:
DrawItem函数,用户定义的对按钮的绘制工作才会有效。
否则,DrowItem
函数将不会被调用。
PreSubclassWindow函数在窗口被创建之前就被调用,因此,在PreSubclassWindow
函数中,将按钮的风格设为BS_OWNERDRAW。
实现代码如下:
voidCAdvButton:
:
PreSubclassWindow()
{
//修改按钮控件风格
ModifyStyle(0,BS_OWNERDRAW|BS_PUSHBUTTON);
CButton:
:
PreSubclassWindow();
}
如果要使得按钮能对鼠标的移动与点击作出不同的变化,那么按钮就需要时刻知道
鼠标的位置与动作。
所以,就必须在鼠标的点击、弹起及移动消息的响应函数里填加相
应的代码,以获取鼠标的位置与动作。
在鼠标左键按下时,得到按钮窗口客户区域的屏幕坐标位置和鼠标的屏幕坐标位
置。
当鼠标坐标位置落于窗口客户区域内,且当前按扭控件处于非选中状态时,将按钮
状态标帜设为选中状态,即将m_State设为2。
接着,调用Invalidate函数,使客户区无
效,框架会自动调用DrawItem函数,重绘客户区。
其实现代码如下:
VisualC++简明教程
//当鼠标在按钮的客户区内按下时,改变按钮状态
voidCAdvButton:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CRectrect;
GetWindowRect(&rect);
GetCursorPos(&m_Point);
//得到按钮客户区域的屏幕坐标位置
//得到鼠标的屏幕坐标位置
if((rect.PtInRect(m_Point))&&(m_State!
=2))
{
m_State=2;
Invalidate();
//
//重绘客户区
}
CButton:
:
OnLButtonDown(nFlags,point);
}
在鼠标左键抬起时,得到按钮窗口客户区域的屏幕坐标位置和鼠标的屏幕坐标位
置。
当鼠标坐标位置落于窗口客户区域内,且当前按扭控件处于选中状态时,将按钮状
态标帜设为非选中状态,即将m_State设为1。
接着,调用Invalidate函数,使客户区无
效,框架会自动调用DrawItem函数,重绘客户区。
其实现代码如下:
//当鼠标在按钮的客户区内弹起时,改变按钮状态
voidCAdvButton:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CRectrect;
GetWindowRect(&rect);
GetCursorPos(&m_Point);
//得到按钮客户区域的屏幕坐标位置
//得到鼠标的屏幕坐标位置
if((rect.PtInRect(m_Point))&&(m_State!
=1))
{
m_State=1;
Invalidate();
//
//重绘客户区
}
CButton:
:
OnLButtonUp(nFlags,point);
}
在用户移动鼠标时,如果计时器没有启动,则启动计时器,并将计时器启动标帜
m_IsTimerOn设为TRUE。
其实现代码如下:
//当鼠标在按钮的客户区内移动时,启动计时器
voidCAdvButton:
:
OnMouseMove(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
if(!
m_IsTimerOn)
{
//如果计时器没有启动
SetTimer(1000,100,NULL);//启动计时器
m_IsTimerOn=TRUE;//
}
CButton:
:
OnMouseMove(nFlags,point);
}
当计时器消息当达时,其响应函数OnTimer将被调用。
在OnTimer函数中,首先获
得按钮窗口的客户区域的屏幕坐标位置和鼠标的屏幕坐标位置。
当鼠标位置落于按扭控件客户区域时,则说明鼠标是在按钮的客户区内移动。
如果
按扭控件处于非焦点和非选中状态,则将按扭控件状态设为获得焦点状态。
调用
Invalidate函数,使窗口无效。
框架自动调用DrawItem函数重绘按钮客户区。
当鼠标位置没有落于按扭控件客户区域时,则说明鼠标已经移出了按钮的客户区。
如果按钮没有处于默认状态,则将按钮设为默认状态。
调用Invalidate函数使按钮客户
区无效。
框架自动调用DrawItem函数,重绘按钮客户区。
并且如果鼠标已经移出了按钮的客户区,则消毁计时器,并将计时器的开启标帜
m_IsTimerOn设为FALSE。
OnTimer函数的实现代码如下:
//计时器消息的响应函数
voidCAdvButton:
:
OnTimer(UINTnIDEvent)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CRectrect;
GetWindowRect(&rect);
GetCursorPos(&m_Point);
//得到按钮客户区域的屏幕坐标位置
//得到鼠标的屏幕坐标位置
if(rect.PtInRect(m_Point))
{
//如果鼠标在按钮的客户区内
if((m_State!
=1)&&(m_State!
=2)){
m_State=1;
Invalidate();
//
}
}
else{
//如果鼠标已经不在按钮的客户区内了
if(m_State!
=0){
m_State=0;
Invalidate();
}
//重绘客户区
KillTimer(nIDEvent);//销毁计时器
m_IsTimerOn=FALSE;
VisualC++简明教程
}
CButton:
:
OnTimer(nIDEvent);
}
下面来实现客户区的绘置函数DrawItem。
DrawItem函数是一个虚函数,它是在按
钮控件上进行绘制操作的关键函数。
当按扭的风格具有OWNERDRAW属性时,如果按
钮的可见区域需要重绘时,框架会自动调用DrawItem函数。
其参数lpDrawItemStruct
包含了在按钮客户区域绘图所需的所有必要信息。
在DrawItem函数中,首先得到窗口的的有效矩形区域,在此矩形区域内创建椭圆。
调用SetWindowRgn函数,设置窗口的有效区域为椭圆。
从参数lpDrawItemStruct结构中得到按钮控件客户区域的设备环境变量指针。
根据
按钮当前状态,创建不同的画笔。
调用设备环境类的成员函数,设置背景模式为透明,
选择画笔,在按钮客户区内绘制椭圆及显示文本。
其实现代码如下:
//这按钮控件客户区的绘置函数,也是实现所有高级控件的关键
voidCAdvButton:
:
DrawItem(LPDRAWITEMSTRUCTlpDrawItemStruct)
{
GetClientRect(&m_ClientRect);
m_ClientRgn.DeleteObject();
//得到窗口的的有效矩形区域
//
m_ClientRgn.CreateEllipticRgnIndirect(&m_ClientRect);
//在矩形区域内创建椭圆
//设置窗口的有效区域为椭圆
SetWindowRgn(m_ClientRgn,FALSE);
CDC*pDC=CDC:
:
FromHandle(lpDrawItemStruct->hDC);//得到按钮控件客户区域的设备
环境变量指针
CPen*pPen=NULL;
switch(m_State)
//根据按钮不同的状态,创建不同的画笔
{
case0:
pPen=newCPen(PS_SOLID,1,DefaultColor);
break;
case1:
pPen=newCPen(PS_SOLID,1,FocusColor);
break;
case2:
pPen=newCPen(PS_SOLID,1,SelectColor);
break;
case3:
pPen=newCPen(PS_SOLID,1,DesiableColor);
break;
}
pDC->SetBkMode(TRANSPARENT);//设置背景模式为透明
pPen=pDC->SelectObject(pPen);
pDC->Ellipse(&m_ClientRect);
//
//在按钮客户区内绘制椭圆
pPen=pDC->SelectObject(pPen);
if(pPen)deletepPen;
//
LPTSTRpCaption=newchar[MAXCAPTIONLEN];
//
intiLen=GetWindowText(pCaption,MAXCAPTIONLEN);
pDC->SetTextColor(TextColor);
//指定文本颜色
//绘制文本,作为按钮标题
pDC->DrawText(pCaption,iLen,&m_ClientRect,DT_SINGLELINE|
DT_CENTER|DT_VCENTER);
}
通过上面的代码,按钮就已经具有了对鼠标不同的位置和动作改变不同的颜色。
并
且,按钮的客户区域已经是一个椭圆,而不再是一个矩形。
正是下面的代码将按钮的客
户区域设定为椭圆形:
GetClientRect(&m_ClientRect);
m_ClientRgn.DeleteObject();
//通到窗口的的有效矩形区域
//
m_ClientRgn.CreateEllipticRgnIndirect(&m_ClientRect);
//在矩形区域内创建椭圆
//设置窗口的有效区域为椭圆
SetWindowRgn(m_ClientRgn,FALSE);
至此,一个完整的高级按钮类就全部完成了。
3.4实现高级编辑控件类
利用ClassWizard添加一个新类。
如图3-12所示:
图3-12添加CAdvEdit类
添加的新类命名为CAdvEdit,其父类为CEdit。
下面就在此类的基础上,实现高级
编辑控件。
3.4.1添加成员变量和成员函数
为CAdvEdit类添加一个字符串类型的成员变量m_Caption,用来记录编辑框中的文
本内容。
其代码如下:
//CAdvEdit.h头文件
VisualC++简明教程
public:
CStringm_Caption;//编辑框文本
利用AppWizard添加消息函数OnPaint。
此函数是WM_PAINT消息的响应函数,
当编辑框可见客户区需要重绘时,此消息会被触发,框架会自动调用OnPaint函数。
并且利用AppWizard添加两个public类型的成员函数,分别用来绘制编辑控件客户
区和设置编辑控件的显示文本。
实现代码如下:
public:
voidOnDraw();//绘制编辑控件客户区
voidOnDisplay(LPCTSTRlpszStr);
protected:
//设置编辑控件显示文本
//{{AFX_MSG(CAdvEdit)
afx_msgvoidOnPaint();
//}}AFX_MSG
//WM_ON_PAINT消息的响应函数
3.4.2添加编辑控件代码
在OnDisplay函数中设置编辑框的显示文本。
OnDisplay函数的参数lpszStr为字符
串类型,它包含了要设置的显示文本的内容。
在OnDisplay函数中将参数lpszStr的值符
给成员函数m_Caption,再调用OnDraw函数将其显示出来。
实现代码如下:
//设置编辑控件文本
voidCAdvEdit:
:
OnDisplay(LPCTSTRlpszStr)
{
m_Caption=lps