在这一章,要实现一个简单计算器。其类似于 Windows附件中自带的计算器。实际 效果如图 3-1所示,这个计算器不仅实现了简单的四则运算功能,还实现了高级的科学 计算功能,而且具有简洁大方的图文外观。该计算器具有一个菜单栏,一个编辑框及若 干按键。编辑框可以用任何指定的字体和颜色显示文本。按钮控件具有对鼠标敏感的功 能,当鼠标处于不同的位置和状态时,按钮控件会显示不同的颜色,并且所有按钮控件 的客户区域为椭圆或圆形。
其实际效果如图 3-1所示:
图 3-1计算器示例效果图
●为对话框添加菜单。
●制定高级按钮控件,该按钮具有不规则的形状,并可以根据用户鼠标的位置和点 击状态的不同,显示不同的颜色。 ●制定高级编辑控件,该编辑控件可以指定文本文字的字体和颜色。 ●实现对话框的扩展功能。
3.1窗体设计
该计算器是基于对话框的应用程序,利用 MFC AppWizard生成应用计算器应用程 序框架,具体步骤如下:
(1)执行 VC程序,选择 FILE|New命令,弹出 New对话框,单击 Projects选项卡, 选择 MFC AppWizard(exe)选项,然后在 Project Name文本框中输入 Calculator。Location 文本框是指项目的本地路径,这里读者可以自行设定。保持 Platform里的 Win32复选框 不变。如图 3-2所示。
(2)单击 OK按钮,弹出 MFC AppWizard-Step1对话框。选择 Dialog Based单选 按钮。如图 3-3所示。
Visual C ++简明教程
图3-2 New对话框 图 3-3 MFC AppWizard-Step1对话框
(3)单击 Next按钮,弹出 MFC AppWizard-Step2 of 6对话框。如图 3-4所示。 (4)单击 Next按钮,弹出 MFC AppWizard-Step3 of 6对话框,如图 3-5所示。
图 3-4 MFC AppWizard-Step2对话框 图 3-5 MFC AppWizard-Step3对话框
(5)单击 Next按钮,弹出 MFC AppWizard-Step4 of 6对话框。如图 3-6所示。 点击 Finish按钮,创建框架。
图 3-6 MFC AppWizard-Step4对话框
3.2编辑资源
因为在利用 MFC AppWizard生成计算器工程时,选择的应用程序类型是对话框应 用程序,所以工程刚建立时,就已经具有如图 3-7所示的对话框资源。
图 3-7初始状态的对话框资源
接下来就在它的基础上,编辑和添加其它的资源。
3.2.1编辑对话框及控件资源
利用 Visual C++提供的资源编辑器对对话框资源进行编辑。删除对话框上默认的 OK和 Cancel按钮。添加一个 Edit控件,其控件 ID为 IDC_DSPEDIT。添加若干按扭控 件,其 ID如表 3-1所示。
表 3-1按扭控件资源清单
按钮名称 0 1 2 3 4 5 6 7 8 9 . = + - * / CE sqrt 1/x sin
按钮 ID
BTN_0 BTN_1 BTN_2 BTN_3 BTN_4 BTN_5 BTN_6 BTN_7 BTN_8 BTN_9 BTN_10 BTN_11 BTN_12 BTN_13 BTN_14 BTN_15 BTN_16 BTN_17 BTN_18 BTN_19
按键 0 按键 1 按键 2 按键 3 按键 4 按键 5 按键 6 按键 7 按键 8 按键 9 小数点 求值 加号 减号 乘号 除号 清屏 开方 倒数 正弦
用途
Visual C ++简明教程
cos tan x^2 x^3 x^y exp ln log
BTN_20 BTN_21 BTN_22 BTN_23 BTN_24 BTN_25 BTN_26 BTN_27
作弦 正切 平方 立方
以 x为底的 y次幂 以 e为底的幂 以 e为底的对数 对数
并且添加三个静态框,将编辑控件、普通计算、高级计算分别分组。其效果如图 3-8 所示:
图 3-8编辑对话框资源
3.2.2编辑菜单资源
下面为计算器添加一个菜单资源。在 Visual C++中的 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的头文件里加入几种预定义颜色,其代码如下:
#define DesiableColor RGB(192,192,192) #define FocusColor #define SelectColor #define TextColor
RGB(255,0,0) RGB(0,255,0) RGB(128,128,128)
//灰色,按钮不可用 //红色,按钮拥有焦点 //绿色,按钮被按下 //蓝色,默认 //浅灰色,文本颜色
#define DefaultColor RGB(0,0,255)
如果读者需要将按钮设定为其它颜色,那么只需改动上面的预定义即可。 接下来,添加成员变量:
public: CRect CRgn BOOL
m_ClientRect; //用来保存按钮的客户的矩形区域 m_ClientRgn ; //用来保存按钮的客户区域,非矩形 m_IsTimerOn; //标志计时器是否已经打开
Visual C ++简明教程
UINT CPoint
m_State; m_Point;
//按钮所处状态 //当前鼠标位置
利用 ClassWizard添加下列消息映射和响应函数:
//消息响应函数 protected:
//{{AFX_MSG(CAdvButton)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); // afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnTimer(UINT nIDEvent); //}}AFX_MSG //消息映射
//{{AFX_MSG_MAP(CAdvButton) ON_WM_CREATE() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_WM_TIMER() //}}AFX_MSG_MAP
// //
//
//处理 ON_WM_TIMER消息
WM_CREATE消息当创建窗口时被触发,其响应函数为 OnCreate。 WM_LBUTTONDOWN消息当用户鼠标左键按下时被触发,其响应函数为
OnLButtonDown。WM_ LBUTTONUP消息当用户鼠标左键抬起时被触发,其响应函数 为 OnLButtonUp。WM_MOUSEMOVE消息当用户鼠标移动时被触发,其响应函数为 OnMouseMove。WM_TIMER消息当计时器到达时被触发,其响应函数为 OnTimer。
再利用 ClassWizard覆盖父类中的两个关键的虚函数:
//{{AFX_VIRTUAL(CAdvButton) public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); protected:
virtual void PreSubclassWindow(); //}}AFX_VIRTUAL
其中对于所有的对于按钮的绘制工作都是在 DrawItem函数中完成的。
3.3.2添加创建按钮控件代码
按钮的创建分两步完成。首先,调用构造函数对按钮对象进行初始化;其次,调用 Create函数创建按钮。
在构造函数中,对所有成员变量进行初始化。实现代码如下:
//构造函数
CAdvButton::CAdvButton() {
//初始化 m_ClientRect m_ClientRect.left = 0; m_ClientRect.top = 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函数
BOOL CAdvButton::Create(LPCTSTR lpszCaption,DWORD dwStyle,const RECT& rect,
CWnd * pParentWnd,UINT nID) {
return CButton::Create(lpszCaption, dwStyle, rect, pParentWnd, nID); }
3.3.3设置按钮形状、外观、颜色、标题
要创建用户自绘制按钮,必须将按钮的风格设为 BS_OWNERDRAW。因为只有设 置了这一属性,那么当按钮控件的可见部分需要重绘时, Windows才会调用 CAdvButton::DrawItem函数,用户定义的对按钮的绘制工作才会有效。否则, DrowItem 函数将不会被调用。
PreSubclassWindow函数在窗口被创建之前就被调用,因此,在 PreSubclassWindow 函数中,将按钮的风格设为 BS_OWNERDRAW。实现代码如下:
void CAdvButton::PreSubclassWindow() {
//修改按钮控件风格
ModifyStyle(0, BS_OWNERDRAW|BS_PUSHBUTTON); CButton::PreSubclassWindow(); }
如果要使得按钮能对鼠标的移动与点击作出不同的变化,那么按钮就需要时刻知道 鼠标的位置与动作。所以,就必须在鼠标的点击、弹起及移动消息的响应函数里填加相 应的代码,以获取鼠标的位置与动作。
在鼠标左键按下时,得到按钮窗口客户区域的屏幕坐标位置和鼠标的屏幕坐标位 置。当鼠标坐标位置落于窗口客户区域内,且当前按扭控件处于非选中状态时,将按钮 状态标帜设为选中状态,即将 m_State设为 2。接着,调用 Invalidate函数,使客户区无 效,框架会自动调用 DrawItem函数,重绘客户区。其实现代码如下:
Visual C ++简明教程
//当鼠标在按钮的客户区内按下时,改变按钮状态
void CAdvButton::OnLButtonDown(UINT nFlags, CPoint point) {
// TODO: Add your message handler code here and/or call default CRect rect;
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函数,重绘客户区。其实现代码如下:
//当鼠标在按钮的客户区内弹起时,改变按钮状态 void CAdvButton::OnLButtonUp(UINT nFlags, CPoint point) {
// TODO: Add your message handler code here and/or call default CRect rect;
GetWindowRect(&rect); //得到按钮客户区域的屏幕坐标位置 GetCursorPos(&m_Point); //得到鼠标的屏幕坐标位置 if((rect.PtInRect(m_Point))&&(m_State != 1)) {
m_State = 1; Invalidate(); }
CButton::OnLButtonUp(nFlags, point); }
//
//重绘客户区
在用户移动鼠标时,如果计时器没有启动,则启动计时器,并将计时器启动标帜 m_IsTimerOn设为 TRUE。其实现代码如下:
//当鼠标在按钮的客户区内移动时,启动计时器
void CAdvButton::OnMouseMove(UINT nFlags, CPoint point) {
// TODO: Add your message handler code here and/or call default
if(!m_IsTimerOn) {
//如果计时器没有启动
SetTimer(1000,100,NULL); //启动计时器 m_IsTimerOn = TRUE; // }
CButton::OnMouseMove(nFlags, point); }
当计时器消息当达时,其响应函数 OnTimer将被调用。在 OnTimer函数中,首先获 得按钮窗口的客户区域的屏幕坐标位置和鼠标的屏幕坐标位置。
当鼠标位置落于按扭控件客户区域时,则说明鼠标是在按钮的客户区内移动。如果 按扭控件处于非焦点和非选中状态,则将按扭控件状态设为获得焦点状态。调用 Invalidate函数,使窗口无效。框架自动调用 DrawItem函数重绘按钮客户区。
当鼠标位置没有落于按扭控件客户区域时,则说明鼠标已经移出了按钮的客户区。 如果按钮没有处于默认状态,则将按钮设为默认状态。调用 Invalidate函数使按钮客户 区无效。框架自动调用 DrawItem函数,重绘按钮客户区。
并且如果鼠标已经移出了按钮的客户区,则消毁计时器,并将计时器的开启标帜 m_IsTimerOn设为 FALSE。
OnTimer函数的实现代码如下:
//计时器消息的响应函数
void CAdvButton::OnTimer(UINT nIDEvent) {
// TODO: Add your message handler code here and/or call default CRect rect;
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;
//重绘客户区 //
Visual C ++简明教程
}
CButton::OnTimer(nIDEvent); }
下面来实现客户区的绘置函数 DrawItem。DrawItem函数是一个虚函数,它是在按 钮控件上进行绘制操作的关键函数。当按扭的风格具有 OWNERDRAW属性时,如果按 钮的可见区域需要重绘时,框架会自动调用 DrawItem函数。其参数 lpDrawItemStruct 包含了在按钮客户区域绘图所需的所有必要信息。
在 DrawItem函数中,首先得到窗口的的有效矩形区域,在此矩形区域内创建椭圆。 调用 SetWindowRgn函数,设置窗口的有效区域为椭圆。
从参数 lpDrawItemStruct结构中得到按钮控件客户区域的设备环境变量指针。根据 按钮当前状态,创建不同的画笔。调用设备环境类的成员函数,设置背景模式为透明, 选择画笔,在按钮客户区内绘制椭圆及显示文本。其实现代码如下:
//这按钮控件客户区的绘置函数,也是实现所有高级控件的关键 void CAdvButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) {
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) {
case 0:
pPen = new CPen(PS_SOLID,1,DefaultColor);
break; case 1:
pPen = new CPen(PS_SOLID,1,FocusColor); break; case 2:
pPen = new CPen(PS_SOLID,1,SelectColor); break; case 3:
pPen = new CPen(PS_SOLID,1,DesiableColor); break;
}
pDC->SetBkMode(TRANSPARENT); //设置背景模式为透明 pPen = pDC->SelectObject(pPen); pDC->Ellipse(&m_ClientRect);
//
//在按钮客户区内绘制椭圆
//根据按钮不同的状态,创建不同的画笔
//在矩形区域内创建椭圆
pPen = pDC->SelectObject(pPen); if(pPen) delete pPen;
//
LPTSTR pCaption = new char[MAXCAPTIONLEN]; pDC->SetTextColor(TextColor); //绘制文本,作为按钮标题
//指定文本颜色
//
int iLen = GetWindowText(pCaption,MAXCAPTIONLEN);
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头文件
Visual C ++简明教程
public:
CString m_Caption; //编辑框文本
利用 AppWizard添加消息函数 OnPaint。此函数是 WM_PAINT消息的响应函数, 当编辑框可见客户区需要重绘时,此消息会被触发,框架会自动调用 OnPaint函数。
并且利用 AppWizard添加两个 public类型的成员函数,分别用来绘制编辑控件客户 区和设置编辑控件的显示文本。
实现代码如下:
public:
void OnDraw(); //绘制编辑控件客户区 void OnDisplay(LPCTSTR lpszStr); protected:
//{{AFX_MSG(CAdvEdit) afx_msg void OnPaint(); //}}AFX_MSG
//WM_ON_PAINT消息的响应函数
//设置编辑控件显示文本
3.4.2添加编辑控件代码
在 OnDisplay函数中设置编辑框的显示文本。 OnDisplay函数的参数 lpszStr为字符 串类型,它包含了要设置的显示文本的内容。在 OnDisplay函数中将参数 lpszStr的值符 给成员函数 m_Caption,再调用 OnDraw函数将其显示出来。实现代码如下:
//设置编辑控件文本
void CAdvEdit::OnDisplay(LPCTSTR lpszStr) {
m_Caption = lpszStr; OnDraw(); }
在 OnPaint函数中调用自定义函数 OnDraw。实现代码如下:
//WM_ PAINT消息的响应函数 void CAdvEdit::OnPaint() {
CPaintDC dc(this); // device context for painting OnDraw(); }
在 OnDraw函数中,在编辑控件客户区域内绘制文本。首先,得到编辑控件客户区 的矩形区域;其次,得到编辑控件客户区的设备环境变量;接着,用指定的画刷填充客 户区,并且用指定的颜色绘制显示文本。
实现代码如下:
//绘制编辑控件客户区 void CAdvEdit::OnDraw() {
CRect rect;
GetClientRect(&rect); //得到客户区矩形区域 CDC* pDC = GetDC();
//得到编辑控件设备环境变量
pDC->SetBkMode(TRANSPARENT); //设置背模式为透明
CBrush * pBrush = new CBrush(RGB(255,255,255)); //创建白色画刷 pDC->FillRect(&rect,pBrush);
//用画刷填充客户区
pDC->SetTextColor(RGB(92,92,92)); //设置文本颜色 //绘制文本,用指定的颜色和字体
pDC->DrawText(m_Caption,rect,DT_SINGLELINE|DT_VCENTER|DT_RIGHT); }
3.5对话框界面设计
在实现在 CAdvButton和 CAdvEdit之后,现在来实现主对话框界面功能。
由于主对话框上控件按钮较多,而且要实现动态扩展功能和菜单功能,所以要添加 的成员变量和成员函数较多。因此,不在此全部列出。下面仅对其中重要的成员变量和 函数加以说明。
主要成员变量:
//CCalculatorDlg.h头文件 CButton
m_DspStatic;
//显示计算结果的编辑框 //对话框菜单按钮 //标志对话框是否已扩展
CAdvEdit m_DspEdit; CMenu * m_Menu; BOOL m_IsExtend;
主要成员函数:
//CCalculatorDlg.h头文件
//{{AFX_VIRTUAL(CCalculatorDlg) protected:
virtual void DoDataExchange(CDataExchange* pDX); //数据交换函数 //}}AFX_VIRTUAL virtual BOOL OnInitDialog();
//虚函数,可覆盖用来进行用户初始化操作
virtual void OnOK(); //虚函数,覆盖用来屏蔽 Enter操作 //{{AFX_MSG(CCalculatorDlg)
//响应消息 ON_WM_CTLCOLOR,用以修改对话框及其控件颜色
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); afx_msg void OnPaint(); //}}AFX_MSG
//响应消息 WM_ON_PAINT
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); //响应消息 WM_ON_CREATE
除以上的主要成员外,还需要对每个按钮控件定义一个 CAdvButton的对象与之相 关联,并为对每个按钮控件建立一个成员函数来响应其 EN_CLICKED消息。由于函数 较多,不在此列举,请读者查看光盘中的示例代码。
Visual C ++简明教程
3.5.1加载菜单资源
在 3.2.2节中,已经为工程新建了一个菜单资源 IDR_MENU。现将其添加到计算器 对话框上。利用 CMenu类的 LoadMenu函数,将菜单资源加载到内存中。再调用 SetMenu 函数,将菜单添加到对话框上。实现代码如下:
//初始化对话框函数
BOOL CCalculatorDlg::OnInitDialog() {
CDialog::OnInitDialog(); //其它的初始化代码 m_Menu = new CMenu;
//
//调用父类的初始化代码
m_Menu->LoadMenu(IDR_MENU); //加载菜单资源模板
//将菜单添加到对话框 SetMenu(m_Menu);
return TRUE; // return TRUE unless you set the focus to a control }
3.5.2关联控件与对象
在 CCalculatorDlg类的声明中,已经为编辑框、静态框及每一个按钮声明了相应类
型的对象与之对应。但这些控件与对象的关联工作是在 DoDataExchange函数中利用 DDX_Control宏来完成的。宏 DDX_Control需要三个参数,即 CDataExchange类型的指 针,控件 ID,相应类型的对象。实现代码如下:
//数据交换函数
void CCalculatorDlg::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CCalculatorDlg)
DDX_Control(pDX, IDC_DSPSTATIC, m_DspStatic); //静态框 DDX_Control(pDX, IDC_DSPEDIT, m_DspEdit); //将按钮控件与 CAdvButton对象相关联 DDX_Control(pDX, BTN_0, m_AdvButton0); DDX_Control(pDX, BTN_1, m_AdvButton1); DDX_Control(pDX, BTN_2, m_AdvButton2); DDX_Control(pDX, BTN_3, m_AdvButton3); DDX_Control(pDX, BTN_4, m_AdvButton4); DDX_Control(pDX, BTN_5, m_AdvButton5); DDX_Control(pDX, BTN_6, m_AdvButton6); DDX_Control(pDX, BTN_7, m_AdvButton7); DDX_Control(pDX, BTN_8, m_AdvButton8); DDX_Control(pDX, BTN_9, m_AdvButton9); DDX_Control(pDX, BTN_10, m_AdvButtonPoint); DDX_Control(pDX, BTN_11, m_AdvButtonEqu); DDX_Control(pDX, BTN_12, m_AdvButtonAdd);
//编辑框
DDX_Control(pDX, BTN_13, m_AdvButtonSub); DDX_Control(pDX, BTN_14, m_AdvButtonMul); DDX_Control(pDX, BTN_15, m_AdvButtonDiv); DDX_Control(pDX, BTN_16, m_AdvButtonClear); DDX_Control(pDX, BTN_17, m_AdvButtonSqrt); DDX_Control(pDX, BTN_18, m_AdvButtonReverse); DDX_Control(pDX, BTN_19, m_AdvButtonSin); DDX_Control(pDX, BTN_20, m_AdvButtonCos); DDX_Control(pDX, BTN_21, m_AdvButtonTan); DDX_Control(pDX, BTN_22, m_AdvButtonSqu); DDX_Control(pDX, BTN_23, m_AdvButtonCub); DDX_Control(pDX, BTN_24, m_AdvButtonPow); DDX_Control(pDX, BTN_25, m_AdvButtonExp); DDX_Control(pDX, BTN_26, m_AdvButtonLn); DDX_Control(pDX, BTN_27, m_AdvButtonLog); //}}AFX_DATA_MAP }
3.4.3实现对话框扩展功能
首先,在 CCalculatorDlg::OnCreate函数中,设定对话框的初始大小与位置。OnCreate 是 WM_ON_CREATE消息的响应函数,该函数在对话框创建时被触发。此时,窗口还 没有完全被创建好,因此,不可以在此初始化一些完全基于窗口的操作。可以在这个对 话框中进行窗口风格修改,位置设置等操作。其参数 lpCreateStruct中包含了创建窗口所 需的所必需信息。在此函数中修改对话框大小后,对话框就会以指定的大小显示,而不 是以对话框板中建立的大小显示。实现代码如下:
int CCalculatorDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) {
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1; CRect rect;
GetWindowRect(&rect);
//得到对话框的窗口区域矩形
//指定窗口大小与位置;宽为 232像素,高度不变
SetWindowPos(&wndTop,0,0,232,rect.Height(),SWP_NOMOVE|SWP_NOZORDER); // TODO: Add your specialized creation code here return 0; }
其次,添加菜单项 ID_EXTEND的响应函数 OnExtend。在 OnExtend函数中,首先 判断当前对话框状态,即是否已经被扩展。
如果对话框已被扩展,则收缩对话框。首先得到对话框的当前位置,将其指定为新 的宽度,但高度维持不变。再将其中的编辑控件和编辑控件外的静态框收缩到合理的位 置。最后将菜单项 ID_EXTEND的显示文本设置为“扩展”,将表示对话框是否扩展的
Visual C ++简明教程
标帜变量 m_IsExtend设置为 FALSE。
如果对话框为非扩展,则扩展对话框。首先得到对话框的当前位置,将其指定为新 的宽度,但高度维持不变。再将其中的编辑控件和编辑控件外的静态框收缩到合理的位 置。最后将菜单项 ID_EXTEND的显示文本设置为“收缩”,将表示对话框是否扩展的 标帜变量 m_IsExtend设置为 TRUE。
实现代码如下:
//菜单命令 ID_EXTEND的响应函数 void CCalculatorDlg::OnExtend() {
CRect rect;
if(m_IsExtend) //如果当前对话框已被扩展 {
GetWindowRect(&rect);
//得到对话框的窗口区域矩形
//设置对话框窗口位置与大小;宽为 232像素,高度不变
SetWindowPos(&wndTop,0,0,232,rect.Height(),SWP_NOMOVE|SWP_NOZORDER); //得到编辑框的窗口区域矩形 m_DspEdit.GetWindowRect(&rect);
//设置编辑框窗口位置与大小;宽为 182像素,高度不变
m_DspEdit.SetWindowPos(NULL,rect.left,rect.top,182,rect.Height(),
SWP_NOMOVE|SWP_NOZORDER); //得到静态框的窗口区域矩形 m_DspStatic.GetWindowRect(&rect); //设置静态框窗口位置与大小
m_DspStatic.SetWindowPos(NULL,rect.left,rect.top,202,rect.Height(),
SWP_NOMOVE|SWP_NOZORDER); //更改菜单项显示文本
m_Menu ->ModifyMenu(ID_EXTEND,MF_BYCOMMAND|MF_STRING,ID_EXTEND,
\"扩展\"); m_IsExtend = FALSE; } else {
GetWindowRect(&rect);
//得到对话框的窗口区域矩形
//设置对话框窗口位置与大小;宽为 409像素,高度不变
SetWindowPos(&wndTop,0,0,409,rect.Height(),SWP_NOMOVE|SWP_NOZORDER); //得到编辑框的窗口区域矩形 m_DspEdit.GetWindowRect(&rect);
//设置编辑框窗口位置与大小;宽为 361像素,高度不变
m_DspEdit.SetWindowPos(NULL,rect.left,rect.top,361,rect.Height(),
SWP_NOMOVE|SWP_NOZORDER);
//得到静态框的窗口区域矩形 m_DspStatic.GetWindowRect(&rect); //设置静态框窗口位置与大小
m_DspStatic.SetWindowPos(NULL,rect.left,rect.top,381,rect.Height(),
SWP_NOMOVE|SWP_NOZORDER); //更改菜单项显示文本
m_Menu ->ModifyMenu(ID_EXTEND,MF_BYCOMMAND|MF_STRING,ID_EXTEND,
\"标准\"); m_IsExtend = TRUE; } }
3.5.4屏蔽 Enter键
读者可能会发现,直到现在为止,虽然计算器的界已经完成。但是,它还有一个缺 陷:当 Enter键按下时,对话框就会突然关掉。这是因为对话框默认具有焦点的控件是 OK键,所以,当 Enter键按下时,框架会自动执行当前拥有焦点的控件的响应函数, 所以,对话框自然就关闭了。
要屏蔽这一功能,只要执行下面的代码就可以了。
void CCalculatorDlg::OnOK() {
// TODO: Add extra validation here //CDialog::OnOK(); }
//屏蔽掉此句代码
读者只需重新建一个函数,响应 IDOK按扭的 EN_CLICKED命令就可以了。
3.6数值计算功能的实现
通过以上的所有步骤,就建立了一个简洁大方的计算器交互界面。下面就来进行具 体功能的实现。
首先添加成员变量。该计算器中所有的运算都是二元运算,即需要两个操作数,一 个二元运算操作符。所以必须声明两个浮点数,分别用来表示初始操作数和结果操作数 同时,必须声明两个字符串类型的变量,分别用来显示初始操作数和结果操作数。还需 要一个整型变量用来记录当前运算符,以及一个整型变量用来记录当前小数点按钮是否 被点击过。实现代码如下:
//CCalculatorDlg.h头文件 private:
CString m_StrBegin; //记录初始操作数,字符串 char m_buffer[100]; //记录结果操作数,字符串 double m_begin;
//记录初始操作数,浮点
Visual C ++简明教程
double m_end; int m_bit;
//记录结果操作数,浮点 //记录运算符
int m_IsCheckPoint; //标识是否按下了小数点符号
当数字键 0-9被点击时,则将当前所按键追加到初始操作数末尾,并将初始操作数 显示出来。以数字键 0被点击为例,实现代码如下:
//以按键 0的响应为例,其余 1-9的响应完全类似 void CCalculatorDlg::AdvButton0() {
m_StrBegin = m_StrBegin+\"0\";
if (!m_IsCheckPoint) //如果小数点按下了
m_DspEdit.OnDisplay(m_StrBegin+\".\"); else //如果小数点没有按下
m_DspEdit.OnDisplay(m_StrBegin); }
当小数点键被点击时,首先判断小数点键是否已经被点击过,以及当前初始操作数 字符串是否为空。如果小数点键没有被点击过,而且当前初始操作数字符串不为空,则 将小数点追加到初始操作数末尾,并且修改小数点标帜 m_IsCheckPoint为 TRUE。实现 代码如下:
void CCalculatorDlg::AdvButtonPoint() { {
m_StrBegin = m_StrBegin+\".\"; m_DspEdit.OnDisplay(m_StrBegin); m_IsCheckPoint = true; } }
//显示文本
//按下.键时的处理函数
if (!m_IsCheckPoint && m_StrBegin != \"\") //如果小数点没有按下,且字符串不为空
//改变标识
当清除键 CE被点击时,则对所有的成员变量进行初始化。清除小数点标帜,将保 存初始操作数和结果操作数的字符串清空,将保存初始操作数和结果操作数的浮点数清 0,将当前操作符清 0。实现代码如下:
void CCalculatorDlg::AdvButtonClear() {
m_IsCheckPoint = false; m_StrBegin = \"\"; m_begin = 0.0; //清 0 m_end = 0.0; //清 0
m_bit = 0; //当前操作符为无效操作 m_DspEdit.OnDisplay(\"0.\"); }
//消除小数点按下标记
当任何一个运算符键被点击时,首先根据当前运算符计算运算结果,再修改记录当 前运算符的变量的值。以加号键被按下为例,实现代码如下:
//以加号为例,其余的操作符也采用类似操作 void CCalculatorDlg::AdvButtonAdd() {
Result(); //计算运算结果
m_bit = 1; //设置当前运算类型; 1代表加法运算 }
计算器的核心运算函数—— Result。在 Result中,首先将记录当前操作数的字符串 中保存的字符串转化为浮点数;其次根据当前操作符的类型,选择适当的运算操作;再 将记录结果操作数的浮点变量中的值转化为字符串,并显示在结果编辑框中。实现代码 如下:
void CCalculatorDlg::Result() //核心运算函数 {
//清除小数点标记
//当输入数据转为浮点数 m_begin = atof(m_StrBegin); switch(m_bit) {
case 1:
//处理+号 m_end += m_begin;
break;
case 2: //处理-号
m_end -= m_begin;
break; case 3:
//处理*号,即乘法 m_end *= m_begin; break; case 4:
//处理/号,即除法
m_DspEdit.OnDisplay(\"除数不能为零! \"); break; }
m_end /= m_begin; break;
case 5: //处理 sqrt号,即开方
if (m_end < 0) {
m_DspEdit.OnDisplay(\"函数输入无效! \"); break; }
m_end = sqrt(m_end); break;
case 6: //处理 1/x号,即求倒数
if (m_end == 0) {
m_DspEdit.OnDisplay(\"分母输入无效! \"); if (m_begin==0) {
m_IsCheckPoint = false;
Visual C ++简明教程
break; }
m_end = 1/m_end; case 7: //处理=号 //空操作 break;
//处理 sin号 case 8:
m_end = sin(m_end); break; case 9:
//处理 cos号 m_end = cos(m_end); break;
case 10: //处理 tan号
m_end = tan(m_end); break;
case 11: //处理 x^2号,即平方
m_end = m_end*m_end; break;
case 12: //处理 x^3号,即立方
m_end = m_end*m_end*m_end; break;
case 13: //处理 x^y号,即求 x的 y次方
m_end = pow(m_end,m_begin); break;
case 14: //处理 Exp号,即求 e的 x次方
m_end = exp(m_end); break;
case 15: //处理 ln号
if (m_end<=0) {
m_DspEdit.OnDisplay(\"函数输入无效! \"); break; }
m_end = log(m_end); break;
case 16: //处理 log号
if (m_end<=0) {
m_DspEdit.OnDisplay(\"函数输入无效! \"); return; }
m_end = log10(m_end); break; default:
//
m_end = m_begin; break;
}
m_begin = 0.0; //清 0 m_bit = 0; // m_StrBegin = \"\";//
int i = sprintf(m_buffer,\"%10.12f\将结果转换为字符串 m_DspEdit.OnDisplay(m_buffer); }
//显示结果
3.7本章小结
本章以一个计算器的实现为基础,向读者介绍一基于对话框的应用程序的编程方法 以及对话框常用控件的高级编程。虽然本章主要只讨论了按扭控件和编辑控件,但是其 它控件的编程都与其类似,故不再作讨论。
通过对本章的学习,读者应该了解以下几方面知识: ●对话框应用程序的编程模式 ● CDialog类及模式对话框的编程 ●为对话框添加菜单资源 ●按钮控件的应用 ●改变按钮的客户区形状 ●在按钮客户区内作图 ●编辑控件的应用
●在编辑控件客户区内绘制文本 ●对话框的扩展
●对话框及对话框控件的高级编程
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- 7swz.com 版权所有 赣ICP备2024042798号-8
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务