动手学MFC之七——进军单文档

有时候代码的位置远比它们本身更重要。

之前几节我们一直在对话框里面玩,不上档次啊,今天我们就来单文档里面看看。

建立一个单文档项目同样是新建MFC,只不过在选择类型的时候选单文档。


一路next或者直接finish就行啦,其实next后面是有玄机的,但是我们第一次接触,就暂时避开这些吧。全编译运行,出来界面了吧?


哈哈,我们一行代码都没写,就得到了一个窗口了。它具有一些菜单和工具栏,同样还支持最大化最小化等等,是不是很棒呢?

下面我们要增加一个自己的菜单,选择resource选项卡,打开Menu,双击IDR_MAINFRAME。


进入菜单编辑界面后,我们就看到之前显示在程序中的菜单了,哦,原来真身在这啊!


我们将原来的这些菜单都删掉,我们要建造自己的王国。选中菜单,按下键盘上的delete键就能删除菜单了,我们在主菜单项中写上“我的菜单”,注意,这个菜单是弹出的,注意它在Pop-up这里打上了钩,说明它点中后不会响应啥,只会弹出它的子菜单项。


         然后我们为子菜单添加一个菜单1,ID写成IDM_MENU1。这个菜单是有ID的,说明它可以被点击。


         好了,运行一下吧,是不是看到菜单的变化了呢?但是菜单1是灰色的,刚刚不是说可以响应点击吗?别急,我们还没有为它添加响应函数呢。调出类向导,在Class name中切换到CSingleDocView(SingleDoc是我的工程名),注意,这里也可以切换到其他的类,但是由于我们之后的代码都在CSingleDocView类中,所以我们把菜单的响应函数也放在这个类里面。Objects ID选中IDM_MENU1,Messages选中COMMAND,Add Function,Edit Code,这一套动作是不是行云流水了呢?

         在响应函数中我们就加一句话,MessageBox("点击菜单1");,看看能不能弹出菜单。


         全编译运行吧,是不是成功了?

         但是我们发现下面有一行工具栏比较讨厌,我们也要改造它,在resource中点开Toolbar,双击IDR_MAINFRAME,哈哈,我们又找到它的真身了。


同样,我们把这些有图标的都删掉,怎么删,按delete不管用,这个我可是摸索了好一阵才知道了,直接把要删的图标用鼠标左键拖到工具栏外面就行了,是不是很方便呢?好了,我们画一个黄色的图标示意一下吧(画图不用我教吧,最右边有画图工具的,和windows画图很像的),注意,在上面敲回车键,将其ID改为IDM_MENU1,运行看看效果吧。


         是不是工具栏也变了呢?而且我们点击工具栏上的按钮,也弹出了消息框,和我们点击菜单的时候一样,为什么呢?我们没有为工具栏按钮绑定消息响应函数啊。啊哈,原因是我们在给工具栏按钮添加ID的时候添加的是IDM_MENU1,它不就是菜单的ID么,由于这层关系,所以。。。(我就不说废话了),这里补充一下,一般我们是不为工具栏按钮单独赋予功能的,工具栏只是菜单的一个快捷方式,所以工具栏的ID一般都和某一个菜单ID对应起来。

         但是我们的程序白白的,好空洞啊,下面我们来画个图吧,切换到FileView,找到SingleDocView.cpp,点开,找到里面的一个OnDraw函数,这是系统画图是调用的函数。


         什么,不相信,还骗你不成,一句话就可以验明真假。我们在里面加上pDC->Rectangle(10,10,200,200);


         运行一下吧。


         哈哈,一个黑框框出现了,刚刚那句代码就是画矩形用的(rectangle是矩形的意思,英语四六级过了吧?),里面的参数代表左上角坐标和右下角坐标。PS:在MFC中,坐标原点在左上角,向右是x正方向,向下是y正方向,那么现在问,矩形的边长是多少,当然是190啦。既然说到画图,我们就说几个常用的画图函数,刚刚我们看了pDC->Rectangle(),等等,你问pDC是什么东西,这不是一两句话就能讲清楚的,你先把它想象成一个画图助手吧,画图助手可以帮助你画很多东西,比如直线,pDC->MoveTo(10,10); pDC->LineTo(200,200);,这是画一条起点在(10,10)终点在(200,200)的线,噢,就是刚刚那个矩形的一个对角线,还可以画椭圆,椭圆的英语是什么,Ellipse,pDC->Ellipse(210,210,400,400);是画一个左上角在(210,210),右下角在(400,400)的矩形的内切椭圆(初中几何学过的吧?)。

还有一个函数不得不提一下,就是写字,pDC->TextOut(210,150,"叶落香");,这句话是在(210,150)这个点输出本尊大名。好了,全编译运行下看看吧。


         你的程序是不是也输出了同样的结果呢?

         之前有位热心网友提了一个问题,说怎么编一个倒计时器,这里借此机会稍微实现一下,也巩固一下以前的知识。

         我们先在View类中定义三个变量,表示时、分、秒。


         注意,这三个变量是View类的成员变量,加在CSingleDocView中,其定义在CSingleDocView.h文件里,因为这里是面向对象编程,所以我们尽量少定义全局变量,多使用类,发挥面向对象的强大威力。

         然后我们在构造函数中初始化它们,这次是在CSingleDocView.cpp文件啦。


         然后我们将pDC->TextOut(210,150,"叶落香");这句话注释掉,修改为

CString str;

         str.Format("%02d:%02d:%02d",m_hour,m_minute,m_second);

         pDC->TextOut(210,150,str);

         相信这个大家应该能看懂,什么,字符串格式化忘了,谭浩强的数再拿来看十遍。运行下看看效果吧。

         是不是在原来显示名字的地方显示了00:00:00呢?

         下面,我们要加一个对话框,让用户输入时、分、秒,废话不多说,上界面


         其关联成员变量的信息如下:


         注意,我为设置了变量为UINT类型,并且设定了范围(注意下面的MinimumValue和Maximum Value),其中,时设为0~23,分设为0~59,秒设为0~59,这个是根据需求来设定的哈。我为这个对话框关联了类CDlgTime。然后,我们在增加一个菜单,叫做倒计时,在里面添加子项,设置,开始,停止,分配ID为IDM_SET、IDM_START、IDM_STOP,分别添加关联函数。


         在OnSet中调出对话框,并接受设定值,这都是上节的内容啦。

CDlgTime dlgTime;

         if(IDOK == dlgTime.DoModal())

         {

                   m_hour = dlgTime.m_hour;

                   m_minute = dlgTime.m_minute;

                   m_second = dlgTime.m_second;

         }

         别忘了#include "DlgTime.h",好了,玩一把吧,设定参数,咦,怎么数据没变呢,还是显示00:00:00,这是因为我们少加了一句话,Invalidate();,这句话告诉MFC,给我重新调用下OnDraw函数。之前是因为系统在初始化窗口是需要绘制窗口,所以调用了OnDraw函数,那时候我们的时分秒都是0,所以显示的是00:00:00,而当我们改变了时分秒的时候,系统并不知道要重新绘制窗口,所以我们需要用Invalidate();去通知系统重绘窗口。Invalidate的意思是使无效,这里的意思是使窗口处于无效状态,MFC系统检测到窗口处于无效状态,就回去重绘窗口。


         试试吧,这次是不是有变化了?

下面,我们在OnStart和OnStop中加入代码,开启和关闭定时器


         接下来就是定时器里面的逻辑了,也是很简单的

m_second--;
	if(m_second < 0)
	{
		m_second = 59;
		m_minute--;
		if(m_minute < 0)
		{
			m_minute = 59;
			m_hour--;
			if(m_hour < 0)
			{
				// 时间到
				m_hour = 0;
				m_minute = 0;
				m_second = 0;
				KillTimer(1);
				MessageBox("时间到");
			}
		}
	}
	Invalidate();


         试试吧,是不是成功了呢?当然,这里的定时器当时间变为0之后,还要过1s才能提示时间到,如果你的业务需求是马上提示,只需要改下OnTimer里面的逻辑就行。

         到了这里,你可以为菜单添加几个工具栏按钮,对应这三个菜单。

         但是程序还是不完美,因为我们在没有开始倒计时的时候,怎么能允许点击停止菜单呢?我们在开始倒计时后,怎么还能再点击开始菜单和设置菜单呢?所以我们还要对菜单进行控制。

         调出类向导,我们看到IDM_SET对应的事件中还有一个UPDATE_COMMAND_UI。


         这个方法就可以控制菜单啦,这个方法的参数pCmdUI有一个Enable方法,在里面设置True和False可以控制菜单。好了,说了这么多,来实践一把。我们增加一个成员变量m_isTimerStart,表示定时器是否开启,初始化为False。然后在每一句SetTimer后面加上m_isTimerStart= true;,在每一句KillTimer后面加上m_isTimerStart = false;

         然后在三个菜单的UPDATE_COMMAND_UI消息的响应函数中添加代码如下:


         再来试试吧,是不是更完美了呢?

         又到了总结时间,这次我们学习了:

1、  单文档菜单的初步使用;

2、  单文档工具栏的初步使用

3、  单文档画图

4、  窗口重绘

5、  菜单可用禁用控制

6、  实现了一个倒计时功能,复习了之前几节课的知识

这节的例子在http://download.csdn.net/detail/yeluoxiang/7082365,欢迎大家下载,也欢迎大家和我讨论。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值