现在的位置: 首页 > 综合 > 正文

初学MFC

2014年03月25日 ⁄ 综合 ⁄ 共 2886字 ⁄ 字号 评论关闭


最近的C++课程老师要求我们学习MFC,虽然我也觉得这是即将被微软抛弃的东西

但是既然既然老师布置下来了,就好好学吧,反正这都是基础,以后肯定要学新的,先入门吧。

我用的是vs03,

首先是弄清楚视图和文档的概念:

 在MFC"文档/视图"架构中,CView类是所有视图类的基类,它提供了用户自定义视图类的公共接口。在"文档/视图"架构中,文档负责管理和维护数据;而视图类则负责如下工作:

  (1) 从文档类中将文档中的数据取出后显示给用户;

  (2) 接受用户对文档中数据的编辑和修改;

  (3) 将修改的结果反馈给文档类,由文档类将修改后的内容保存到磁盘文件中。

而文档负责了数据真正在永久介质中的存储和读取工作,视图呈现只是将文档中的数据以某种形式向用户呈现,因此一个文档可对应多个视图。


我们是从一个利用视图类与鼠标键盘交互的例子开始的。

1.利用MFC生成向导,选择单文档模式,生成程序框架

从解决方案中可以看到产生了一些文件

我在很多程序刚开始都见过stdafx.h这个头文件,今天算是彻底把它弄明白了,afx曾经是微软一个专门的技术开发团队,而stdafx.h则是这个团队为了定义一些环境配置、参数设置等专门定义的,有了这个头文件,我们才能调用AfxGetApp()等这些api函数。打开stdafx.h可以看到它帮我们包含进来一些关键的库:

另外一些文件例如doc文件对应的是文档类

view对应视图类。

利用类视图,对view类添加成员,这种利用向导的方式在MFC比较常用,因为比较不会乱,MFC是一个框架,我们在被人定好的框架里折腾罢了,你不需要知道框架的具体细节,多利用向导就行了。


添加这么几个变量,并且在构造函数中初始化,记住还是在view类中:

BOOL  m_bMouseDown;     //标识鼠标左键是否按下
HCURSOR  m_hCross;       //十字型鼠标句柄
HCURSOR  m_hArrow;      //标准型鼠标句柄
CPoint m_ptOld;                  //临时点
CPoint m_ptStart;                //画线的起始点

CDocViewView::CDocViewView()
{
	m_bMouseDown = false;
	m_hCross = AfxGetApp()->LoadStandardCursor(IDC_CROSS);
	m_hArrow = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
}


AfxGetApp( )这个函数可以得到当前应用进程的指针,是CWinApp*类型的,通过这个指针可以访问到这个进程中的对象。

上图两句话是从当前应用进程中,就是我们创建的实例。LoadStandardCursor的注释为:// Loads a stock cursor resource; for for IDC_* values.简言之,就是载入windows标准的光标对象,标准对象有很多,具体请看另外一篇文章。

在view类的属性中,选择消息,添加OnLButtonDown函数,并且加入以下代码。

void CDocViewView:: OnLButtonDown (UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	m_bMouseDown = true;        // 鼠标左键按下
	m_ptStart = point;                 // 画线的起点
	m_ptOld = point;                   // 临时点
	SetCapture();                         // 将鼠标消息发送到视窗口
	CRect rect;
	GetClientRect(&rect);          // 得到客户窗口的大小
	ClientToScreen(&rect);        // 将当前窗口坐标转换成屏幕坐标
	ClipCursor(&rect);               // 把鼠标限定在其参数指定的矩形区域内
	SetCursor(m_hCross);	// 设置鼠标形状为十字形
	CView::OnLButtonDown(nFlags, point);
}


setcapture(),该函数在属于当前线程的指定窗口里设置鼠标捕获。一旦窗口捕获了鼠标,所有鼠标输入都针对该窗口,无论光标是否在窗口的边界内。同一时刻只能有一个窗口捕获鼠标。如果鼠标光标在另一个线程创建的窗口上,只有当鼠标键按下时系统才将鼠标输入指向指定的窗口。


ClipCursor()

该函数把鼠标限制在屏幕上的一个矩形区域内,如果调用SetCursor或用鼠标设置的一个随后的鼠标位置在该矩形区域的外面,则系统自动调整该位置以保持鼠标在矩形区域之内


同样利用消息创建OnMouseMove和OnLButtonUp






void CMyDrawView::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if( m_bMouseDown )
	{
		CClientDC dc(this);
		dc.SetROP2( R2_NOT );
		dc.MoveTo( m_ptStart );	//这两行代码擦除从起点(鼠标按下点)到
		dc.LineTo( m_ptOld );	//上次鼠标移动到的位置之间的临时线
		dc.MoveTo( m_ptStart );	//这两行代码从起点到鼠标当前位置画线
		dc.LineTo( point );		// 
		m_ptOld = point; //鼠标当前位置在下一次鼠标移动事件看来就是"旧位置"
	}
	CView::OnMouseMove(nFlags, point);
}

  CClientDC:(客户区设备上下文)用于客户区的输出,与特定窗口关联,可以让开发者访问目标窗口中客户区,其构造函数中包含了GetDC,析构函数中包含了ReleaseDC。
Windows API SetROP2(int nDrawMode)主要用于设定当前前景色的混合模式。R2_NOT就是取反的意思,即前景色为背景色的反色,经常用R2_NOT来画橡皮线,因为两次取反可以还原背景色。

LineTo

  用当前画笔画一条线,从当前位置连到一个指定的点。这个函数调用完毕,当前位置变成x,y


void CMyDrawView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	if( m_bMouseDown )
	{
		m_bMouseDown = false;
		ReleaseCapture();
		ClipCursor( NULL );
		CClientDC dc(this);
		dc.SetROP2( R2_NOT );
		dc.MoveTo( m_ptStart );       //这两行代码擦除从起点(鼠标按下点)到
		dc.LineTo( m_ptOld );          //上次鼠标移动到的位置之间的临时线   
		dc.SetROP2( R2_COPYPEN );
		dc.MoveTo( m_ptStart );      //这两行代码从起点到鼠标当前位置画线
		dc.LineTo( point );                //
	               SetCursor(m_hArrow);          //设置鼠标形状为标准箭头形
	}
	CView::OnLButtonUp(nFlags, point);
}

抱歉!评论已关闭.