windows程序设计(22):使用单文档架构编写程序(修改版)

上一次课我们剖析了MFC的单文档应用程序的框架,这一次课主要是使用这个框架。总的来说,是通过doc类存储、处理数据,而在view类显示数据。
先描述一下程序的功能:
有一个菜单可以选择颜色,默认为白色。然后窗口上会显示一个4*4的格子,默认颜色为白色,当鼠标点击在这个格子中时,格子会变成你之前选中的颜色。然后可以利用打开和保存菜单来实现打开和保存的功能。

首先为doc添加两个成员变量:

protected:
	COLORREF m_clrCurrentColor;
	COLORREF m_clrGrid[4][4];
和与之对应的get、set函数:

COLORREF CSquareDoc::GetCurrentColor()
{
	return m_clrCurrentColor;
}

COLORREF CSquareDoc::GetSquare(int i, int j)
{
	ASSERT(i >=0 && i <=3 && j >= 0 && j <=3);
	return m_clrGrid[i][j];
}

void CSquareDoc::SetSquare(int i, int j,COLORREF color)
{
	ASSERT(i >=0 && i <=3 && j >= 0 && j <=3);
	m_clrGrid[i][j] = color;
	//文档被修改
	SetModifiedFlag(TRUE);
	//更新VIEW,引起重绘
	UpdateAllViews(NULL);
}
文档\视类框架的特点就体现在在这里了,如果调用了SetSquare函数,那么会引起视类的重绘。
对于菜单中每个颜色的响应,也放在视类中:
void CSquareDoc::OnColorRed() 
{
	// TODO: Add your command handler code here
	m_clrCurrentColor = RGB(255,0,0);
}

void CSquareDoc::OnUpdateColorRed(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->SetRadio(m_clrCurrentColor == RGB(255,0,0));
}

一个函数是设置颜色的,第二个函数是用来标记菜单的单选选项的。
储存和打卡的操作也放在文档中,其实就是串行化函数:

void CSquareDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
		for(int i = 0; i < 4; ++i)
		{
			for(int j = 0; j< 4; ++j)
			{
				ar<<m_clrGrid[i][j];
			}
		}
		ar<<m_clrCurrentColor;
	}
	else
	{
		// TODO: add loading code here
		for(int i = 0; i < 4; ++i)
		{
			for(int j = 0; j< 4; ++j)
			{
				ar>>m_clrGrid[i][j];
			}
		}
		ar>>m_clrCurrentColor;
	}
}

这个问题在另一篇博客http://blog.csdn.net/thefutureisour/article/details/8185205中仔细的讨论过,这里只说一下我们的是如何使用的。主要是是使用CArchive类的对象,利用他重载的>>和<<操作符就能实现。当然,此时你<<的对象必须是内置类型。我们这里保存了每个格子的颜色和当前的颜色。如果是自定义类型,就有一点麻烦了,大家看之前的博客就行了。

文档类的内容就这么多,下面看看视类,视类的主要作用就是画画,还有响应鼠标消息:

void CSquareView::OnDraw(CDC* pDC)
{
	CSquareDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here

	//MM_LOMETRIC模式下y轴朝上,原点为左上角
	pDC->SetMapMode(MM_LOMETRIC);
	//填充颜色
	for(int i = 0; i < 4;++i)
	{
		for(int j = 0; j < 4;++j)
		{
			COLORREF color = pDoc->GetSquare(i, j);
			CBrush brush(color);
			int x1 = 200+ i * 200;
			int y1 = -200- j * 200;
			int x2 = x1 + 200;
			int y2 = y1 - 200;
			CRect rect(x1,y1,x2,y2);
			pDC->FillRect(rect,&brush);
		}
	}

	//画出格子

	for(int x = 200; x < 1200; x += 200)
	{
		pDC->MoveTo(x,-200);
		pDC->LineTo(x,-1000);
	}

	for(int y = -200; y >-1200;y -= 200)
	{
		pDC->MoveTo(200,y);
		pDC->LineTo(1000,y);
	}

}

void CSquareView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	CClientDC dc(this);
	dc.SetMapMode(MM_LOMETRIC);
	//传过来的设备坐标
	CPoint pos = point;
	//转化为逻辑坐标
	dc.DPtoLP(&pos);

	if(pos.x >= 200 && pos.x < 1200 && pos.y <= -200 && pos.y > -1200)
	{
		int i = (pos.x - 200) / 200;
		int j = (-pos.y - 200) / 200;
		CSquareDoc *pDC = GetDocument();
		//获取当前颜色
		COLORREF color = pDC->GetCurrentColor();
		//设置某个方块的颜色
		pDC->SetSquare(i, j, color);
	}
	CView::OnLButtonDown(nFlags, point);
}

我们发现,我们让鼠标点击引起m_clrGrid[4][4]的某个方块的改变,而方块的改变引起重绘,而重绘会调用

OnDraw。在这个函数中,我们会根据m_clrGrid[4][4]的值,把所有的方块都画一遍。这也就解决了当窗口最小化再最大化以后,颜色消失的问题。还有一点需要注意的是,这里先填了颜色,再画了网格。如果改变二者的顺序,填充的颜色会遮挡住网格的边界的。

最后简单的评价一个这个程序,首先,它的架构:在doc中处理数据,在view中显示数据,这一点是很好的,保证了用具界面与核心内容分离。但是,它也有不好的地方,当鼠标点击后,是通过刷屏,在刷屏时重新绘制整幅图像,但如果消息到来的次数很频繁,那么这样做会是得程序一闪一闪的,很不好看;所以如果考虑到这个问题,应该这么架构:

1.对于特定的消息,如果它们引起的画图是一样的,(比如键盘上方向键引起的缩放和鼠标滚轮引起的缩放),那么应该让他们调用同一个函数。

2.对于不同的画图,比如最小化以后再最大化引起的重绘,设计另外一套绘图。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值