现在流行的VC书上基本都有简单的绘图程序,但是大都是先点一个点,再点一个点,这样要画的图形就出来了。这中间没有任何的演示过程,不到最后不知道自己画的是什么。本章想要显示给大家绘图程序应该显示绘制的过程,鼠标移动时绘制的是什么图形要实时显示出来。我先做一个平常书上的画图程序给大家看。
1,首先建一个名为“bookGraphic”的单文档应用程序。在ResourcesView下的菜单IDR_MAINFRAME中添加几个菜单,如下:
子菜单:画图
菜单项:直线 IDM_DRAW_LINE
矩形 IDM_DRAW_RECT
此系统只绘制直线和矩形,看看效果而已。
2,现在添加消息响应,因为要绘制图形,而绘制图形要在视区中显示,所以把消息响应到View类中,此系统是CBookGraphicView类。利用ClassWizard添加消息响应。响应的消息中应该标识选中了哪个功能。因为这两个功能是不能同时存在的,所以可以用一个变量来分辨,如m_nDrawType。我们为了比较容易阅读程序,这里定义一个枚举,如下:
int m_nDrawType;
enum DRAWTYPE
{
DRAW_NONE = 0, // 不绘制图形
DRAW_LINE = 1, // 绘制直线
DRAW_RECT = 2, // 绘制矩形
};
这样就避免了用1,2来表示选择的是直线还是矩形。
3,绘制直线和矩形都是需要两点来确定的,为了保存第一个点---起始点,所以在CBookGraphicView类中要定义一个CPoint类的对象,CPoint m_ptOrign。因为起始点和终止点都是在鼠标弹起的消息中进行的,所以要区分当时处于哪个状态,是取起始点还是确定绘制。需要定义一个变量来区分:int m_nStep;
到现在需要的变量已经定义好了,需要在CBookGraphicView类中初始化:
CBookGraphicView::CBookGraphicView()
{
// TODO: add construction code here
m_ptOrign = 0;
m_nDrawType = DRAW_NONE; // 这个是必须的,因为系统刚开始时是没有选择绘制的图形的。我没有设置默认O(∩_∩)O~
m_nStep = 0; // 0---表示没有开始步骤,1---代表绘制了第一步,2---代表绘制了第二步,3---代表绘制了第三步,此系统只有两步就完成绘制。
}
4,现在对上面的两个消息响应函数进行处理,很简单,只是指定选择绘制的是什么图形和让绘制的步骤归0即可。
void CBookGraphicView::OnDrawLine()
{
// TODO: Add your command handler code here
m_nDrawType = DRAW_LINE;
m_nStep = 0;
}
void CBookGraphicView::OnDrawRect()
{
// TODO: Add your command handler code here
m_nDrawType = DRAW_RECT;
m_nStep = 0;
}
5,在CBookGraphicView类中响应OnLButtonUp消息做绘图过程:
void CBookGraphicView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
ASSERT(m_nDrawType >= DRAW_NONE);
if (m_nDrawType < DRAW_NONE)
{
CView::OnLButtonUp(nFlags, point);
return;
}
if (DRAW_NONE == m_nDrawType)
{// 没有选择要绘制的图形,所以直接退出函数
CView::OnLButtonUp(nFlags, point);
return;
}
if (0 == m_nStep)
{
m_ptOrign = point;
++m_nStep; // 标记已经过了第一步
}
else if (1 == m_nStep)
{
CClientDC dc(this);
switch (m_nDrawType)
{
case DRAW_NONE:
break;
case DRAW_LINE:
dc.MoveTo(m_ptOrign);
dc.LineTo(point);
m_nStep = 0;
break;
case DRAW_RECT:
dc.SelectStockObject(NULL_BRUSH); // dc置空画刷
dc.Rectangle(CRect(m_ptOrign, point));
m_nStep = 0;
break;
default:break;
}
}
CView::OnLButtonUp(nFlags, point);
}
这样超简单的绘图程序就完成了。。。。。。。
现在要制作新的系统了,注意看…….
首先新建一个名为myGraphic的单文档应用程序,按照上面得步骤做到第3步。我们要实现在绘制过程中图形是出现的,而且是跟这鼠标一起走的,这里要定义一个记录在鼠标移动过程中的点,CPoint m_prPreMoving;在构造函数中置零。第4不也同上…….
现在看绘图过程,其实实现上面的效果很简单只是第一次擦除上次画的图形,第二次绘制新的图形。只是改了一下绘图的模式,具体代码如下:
void CMyGraphicView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
ASSERT(m_nDrawType >= DRAW_NONE);
if (m_nDrawType < DRAW_NONE)
{
CView::OnLButtonUp(nFlags, point);
return;
}
if (0 == m_nStep)
{
m_ptOrign = point;
m_ptPreMoving = point;
m_nStep = 1;
}
else if (1 == m_nStep)
{
CClientDC dc(this);
int nOldMode = dc.SetROP2(R2_NOTXORPEN);// 去系统的反色
switch (m_nDrawType)
{
case DRAW_NONE:
break;
case DRAW_LINE:
// 擦除图形
dc.MoveTo(m_ptOrign);
dc.LineTo(m_ptPreMoving);
// 绘制新的图形
dc.MoveTo(m_ptOrign);
dc.LineTo(point);
break;
case DRAW_RECT:
dc.SelectStockObject(NULL_BRUSH);
dc.Rectangle(CRect(m_ptOrign, m_ptPreMoving));
dc.Rectangle(CRect(m_ptOrign, point));
break;
default:
break;
}
m_nStep = 0;
dc.SetROP2(nOldMode);
}
CView::OnLButtonUp(nFlags, point);
}
void CMyGraphicView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if (m_nDrawType <= 0 || 0 == m_nStep)
{
CView::OnMouseMove(nFlags, point);
return;
}
if (1 == m_nStep)
{
CClientDC dc(this);
int nOldMode = dc.SetROP2(R2_NOTXORPEN);
switch (m_nDrawType)
{
case DRAW_NONE:
break;
case DRAW_LINE:
// 擦除图形
dc.MoveTo(m_ptOrign);
dc.LineTo(m_ptPreMoving);
// 绘制新的图形
dc.MoveTo(m_ptOrign);
dc.LineTo(point);
break;
case DRAW_RECT:
// 擦除图形
dc.Rectangle(CRect(m_ptOrign, m_ptPreMoving));
// 绘制新的图形
dc.Rectangle(CRect(m_ptOrign, point));
break;
default:
break;
}
m_ptPreMoving = point;
dc.SetROP2(R2_NOTXORPEN);
}
CView::OnMouseMove(nFlags, point);
}
到这里可以看到绘制的效果了,和上面的不一样吧,O(∩_∩)O~。主要是使用了CClient类的SetROP2函数改变了绘制的模式,但是绘制完成后要把dc的绘制模式还原。这里只是简单的绘制图形,还未实现重绘,未使用类的继承、多态,等下次有时间吧。过不了几天的。。。。。。。
写完时,听到了刘德华的《冰雨》,很好听的一首歌。