MFC编写一个绘图程序
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MFC编写一个绘图程序相关的知识,希望对你有一定的参考价值。
要求:
1. 画三角形、四边形、圆形、五边形,在窗口中自由移动,碰到窗口边缘会自动弹回(入射角度和折射角度一致)
2.通过菜单、Toolbar命令可以无限增加三角形、四边形、圆形、五边形
4.通过鼠标可以点中三角形、四边形、圆形、五边形,点中的图形可以停下运动,再点中图形可以继续运动
5.对选中的图形,可以设置填充颜色,线条宽度
6.Toolbar的图形按钮有相应的ToolTip
7.画三角形、四边形、圆形、五边形采用采用图形和位图两种方式实现。位图实现不设置填充颜色,线条宽度
8.采用面向对象编程(MFC)
//PS_DASH菜单项处理函数
void CDrawTestView::OnPenDash()
// TODO: Add your command handler code here
m_PenStyle = PS_DASH;
this->SetMenuItemCheck(0,0,7,1);
//PS_DOT菜单项处理函数
void CDrawTestView::OnPenDot()
// TODO: Add your command handler code here
m_PenStyle = PS_DOT;
this->SetMenuItemCheck(0,0,7,2);
//PS_DASHDOT菜单项处理函数
void CDrawTestView::OnPenDashdot()
// TODO: Add your command handler code here
m_PenStyle = PS_DASHDOT;
this->SetMenuItemCheck(0,0,7,3);
//PS_DASHDOTDOT菜单项处理函数
void CDrawTestView::OnPenDashdotdot()
// TODO: Add your command handler code here
m_PenStyle = PS_DASHDOTDOT;
this->SetMenuItemCheck(0,0,7,4);
//PS_NULL菜单项处理函数
void CDrawTestView::OnPenNull()
// TODO: Add your command handler code here
m_PenStyle = PS_NULL;
this->SetMenuItemCheck(0,0,7,5);
//PS_INSIDEFRAME菜单项处理函数
void CDrawTestView::OnPenInsideframe()
// TODO: Add your command handler code here
m_PenStyle = PS_INSIDEFRAME;
this->SetMenuItemCheck(0,0,7,6);
//宽度1菜单项处理函数
void CDrawTestView::OnPen1()
// TODO: Add your command handler code here
m_PenWidth = 1;
this->SetMenuItemCheck(0,1,4,0);
//宽度3菜单项处理函数
void CDrawTestView::OnPen3()
// TODO: Add your command handler code here
m_PenWidth = 3;
this->SetMenuItemCheck(0,1,4,1);
//宽度5菜单项处理函数
void CDrawTestView::OnPen5()
// TODO: Add your command handler code here
m_PenWidth = 5;
this->SetMenuItemCheck(0,1,4,2);
//宽度7菜单项处理函数
void CDrawTestView::OnPen7()
// TODO: Add your command handler code here
m_PenWidth = 7;
this->SetMenuItemCheck(0,1,4,3);
//画笔颜色下黑色菜单项处理函数
void CDrawTestView::OnPenBlack()
// TODO: Add your command handler code here
m_PenColor = RGB(0,0,0);
this->SetMenuItemCheck(0,2,4,0);
//画笔颜色下红色菜单项处理函数
void CDrawTestView::OnPenRed()
// TODO: Add your command handler code here
m_PenColor = RGB(255,0,0);
this->SetMenuItemCheck(0,2,4,1);
//画笔颜色下绿色菜单项处理函数
void CDrawTestView::OnPenGreen()
// TODO: Add your command handler code here
m_PenColor = RGB(0,255,0);
this->SetMenuItemCheck(0,2,4,2);
//画笔颜色下蓝色菜单项处理函数
void CDrawTestView::OnPenBlue()
// TODO: Add your command handler code here
m_PenColor = RGB(0,0,255);
this->SetMenuItemCheck(0,2,4,3);
//None菜单项处理函数
void CDrawTestView::OnBrushNone()
// TODO: Add your command handler code here
m_BrushStyle = -1;
this->SetMenuItemCheck(1,0,7,0);
//HS_BDIAGONAL菜单项处理函数
void CDrawTestView::OnBrushBdiagonal()
// TODO: Add your command handler code here
m_BrushStyle = HS_BDIAGONAL;
this->SetMenuItemCheck(1,0,7,1);
//HS_CROSS菜单项处理函数
void CDrawTestView::OnBrushCross()
// TODO: Add your command handler code here
m_BrushStyle = HS_CROSS;
this->SetMenuItemCheck(1,0,7,2);
//HS_DIAGCROSS菜单项处理函数
void CDrawTestView::OnBrushDiagcross()
// TODO: Add your command handler code here
m_BrushStyle = HS_DIAGCROSS;
this->SetMenuItemCheck(1,0,7,3);
//HS_FDIAGONAL菜单项处理函数
void CDrawTestView::OnBrushFdiagonal()
// TODO: Add your command handler code here
m_BrushStyle = HS_FDIAGONAL;
this->SetMenuItemCheck(1,0,7,4);
//HS_HORIZONTAL菜单项处理函数
void CDrawTestView::OnBrushHorizontal()
// TODO: Add your command handler code here
m_BrushStyle = HS_HORIZONTAL;
this->SetMenuItemCheck(1,0,7,5);
//HS_VERITICAL菜单项处理函数
void CDrawTestView::OnBrushVertical()
// TODO: Add your command handler code here
m_BrushStyle = HS_VERTICAL;
this->SetMenuItemCheck(1,0,7,6);
//画刷颜色下白色菜单项处理函数
void CDrawTestView::OnBrushWhite()
// TODO: Add your command handler code here
m_BrushColor = RGB(255,255,255);
this->SetMenuItemCheck(1,1,4,0);
//画刷颜色下红色菜单项处理函数
void CDrawTestView::OnBrushRed()
// TODO: Add your command handler code here
m_BrushColor = RGB(255,0,0);
this->SetMenuItemCheck(1,1,4,1);
//画刷颜色下绿色菜单项处理函数
void CDrawTestView::OnBrushGreen()
// TODO: Add your command handler code here
m_BrushColor = RGB(0,255,0);
this->SetMenuItemCheck(1,1,4,2);
//画刷颜色下蓝色菜单项处理函数
void CDrawTestView::OnBrushBlue()
// TODO: Add your command handler code here
m_BrushColor = RGB(0,0,255);
this->SetMenuItemCheck(1,1,4,3);
我们在CDrawTestView类中再添加两个函数GetPen和GetBrush来获得自定义画笔和画刷指针,函数代码如下:
//获得自定义画笔指针
CPen* CDrawTestView::GetPen()
return new CPen(m_PenStyle,m_PenWidth,m_PenColor);
//获得自定义画刷指针
CBrush* CDrawTestView::GetBrush()
//判断是否是阴影线画刷
if (m_BrushStyle == -1)
//不是阴影线画刷
return new CBrush(m_BrushColor);
else
//是阴影线画刷
return new CBrush(m_BrushStyle,m_BrushColor);
编写这两个函数的好处在于:如果以后需要更改获得画笔或者画刷的方式(比如画笔改用第三个构造函数来构造),只需要修改这两个函数即可。如果在每个绘图函数菜单项的处理函数中写构造画笔和画刷的代码,一旦画笔和画刷的构造方式要发生改变,就必须逐个修改每个绘图函数菜单项的处理函数。
现在修改绘图函数菜单项的处理函数,调用GetPen和GetBrush函数获得画笔和画刷,然后选用画笔和画刷,并在函数的最后删除画笔和画刷。这是因为获得画笔和画刷的函数每次都是构造新的画笔和画刷,而它们将占用系统资源,所以在使用完毕后要进行删除。而LineTo等绘制线形图形的绘图函数不受画刷影响,所以在这些绘图函数的处理函数中不需要选用画刷。因为所有线形图形绘图函数菜单项的处理函数要添加的代码是相同的,同样所有区域图形绘图函数菜单项的处理函数要添加的代码也是相同的,所以这里只列出“LineTo”(绘制线形图形)菜单项和“Rectangle”(绘制区域图形)菜单项修改后的处理函数代码,读者只需按照相同方法修改其它处理函数即可。修改后的代码如下:
//LineTo菜单项处理函数
void CDrawTestView::OnDrawLineto()
// TODO: Add your command handler code here
CClientDC dc(this);
CPen* pen = this->GetPen();
dc.SelectObject(pen);
dc.MoveTo(300,300);
dc.LineTo(400,400);
pen->DeleteObject();
//Rectangle菜单项处理函数
void CDrawTestView::OnDrawRectangle()
// TODO: Add your command handler code here
CClientDC dc(this);
CPen* pen = this->GetPen();
CBrush* brush = this->GetBrush();
dc.SelectObject(pen);
dc.SelectObject(brush);
dc.Rectangle(450,100,650,250);
pen->DeleteObject();
brush->DeleteObject();
代码中粗体字部分是后添加的代码,修改原则是在获得设备环境对象之后,调用绘图函数之前,先获得画笔或画笔和画刷,然后让设备环境对象选用它们。最后在所有绘图函数执行完后,删除前面获得的画笔或画笔和画刷。
下面我们看一个例子,修改OnDraw函数,输入如下代码:
void CDrawTestView::OnDraw(CDC* pDC)
CDrawTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//构造要输出的文本字符串
CString s;
s = "DrawTest Function";
//构造文本要输出的矩形区域
CRect r;
r.left = 50;r.right =150;
r.top =10;r.bottom = 40;
//绘制矩形,以便确定输出的文本在矩形区域中的位置
pDC->Rectangle(r);
//水平,垂直方向都居中,单行显示,超出区域范围不剪切
pDC->DrawText(s,r,DT_VCENTER|DT_CENTER|DT_SINGLELINE|DT_NOCLIP);
//向下平移矩形区域
r.top = r.top + 50;r.bottom = r.bottom +50;
pDC->Rectangle(r);
//垂直方向居底,水平方向靠右,单行显示
pDC->DrawText(s,r,DT_BOTTOM|DT_RIGHT|DT_SINGLELINE);
//向下平移矩形区域
r.top = r.top + 50;r.bottom = r.bottom +50;
pDC->Rectangle(r);
//垂直方向居顶,水平方向靠左,超出矩形区域时,在单词之间换行
pDC->DrawText(s,r,DT_TOP|DT_LEFT|DT_WORDBREAK);
//向下平移矩形区域
r.top = r.top + 50;r.bottom = r.bottom +50;
pDC->Rectangle(r);
//垂直方向居中,水平方向靠左,单行显示,超出范围时用省略号取代字符串尾部字符
pDC->DrawText(s,r,
DT_VCENTER|DT_LEFT|DT_SINGLELINE|DT_END_ELLIPSIS);
在 MFC 中重绘时闪烁
【中文标题】在 MFC 中重绘时闪烁【英文标题】:Flickering while redrawing in MFC 【发布时间】:2010-09-20 11:51:31 【问题描述】:我正在使用 C++ 和 MFC 编写俄罗斯方块游戏。我有一个计时器和 OnTimer 处理程序。处理程序如下所示:
... do some game-only logic ...
this->RedrawWindow();
在 OnPaint 处理程序中,我绘制块、地图(带有位图背景)、分数等。对于绘图,我使用位图和 BitBlt 函数。一切都是从头开始绘制的,我重新绘制了整个窗口区域。整体性能正常,有时会闪烁,但没关系,但是当我将位图背景添加到地图时,重绘时闪烁变得难以忍受。我是否必须使用其他算法来绘制位图,或者每次触发 OnPaint 时我在进行所有重绘时可能是错误的?
如何消除闪烁?我只能使用 C++ 和 MFC,不幸的是,在开始这个项目之前我根本不知道后者。
那么,再说一遍:如何消除闪烁并提高重绘性能?
【问题讨论】:
也检查这个答案:***.com/questions/197948/… 【参考方案1】:尝试覆盖 CWnd::OnEraseBkgnd 以仅返回非零值。这告诉窗口您已经自己处理了擦除窗口背景。
【讨论】:
【参考方案2】:尝试双缓冲。 “双缓冲”是指写入内存 DC,然后将内存 DC BitBlt-ing 到屏幕的技术。
结合 Windows,此技术可用于处理 WM_PAINT 消息。您的 OnDraw 函数调用 BitBlt 将内存 DC 复制到屏幕 DC。内存 DC 与视图类中的成员变量相关联,并在没有其他消息正在处理时写入。
这里有一个link 可以提供一些帮助的代码。
【讨论】:
【参考方案3】:一种可能的解决方案是为所有绘图创建一个内存位图 (DC),然后在完成所有绘图后将其以 blit 方式显示在屏幕上。当您将所有屏幕实体一一绘制时,可能会出现闪烁。如果您使用内存中的位图,则不会有任何闪烁。这是伪代码:
Clear Memory Buffer
Blit the background bitmap on the Memory Buffer
For each entity that needs to be drawn
Draw entity on Memory Buffer
Blit the Memory Buffer to the screen DC
【讨论】:
【参考方案4】:您应该同时应用之前的两个答案。
如果您正在绘制整个窗口区域,则应覆盖 OnEraseBkgnd(如 sje397 建议的那样)以避免 Windows 将背景绘制为灰色。这就是导致闪烁的原因。
但您也最好应用双缓冲技术。这样,绘图将在内存中完成,一次复制到屏幕上。这也将提高您的表现。
祝你好运。
【讨论】:
以上是关于MFC编写一个绘图程序的主要内容,如果未能解决你的问题,请参考以下文章