您的位置:首页 > 大数据 > 人工智能

Little Painter Step by Step-Day 3

2008-12-25 04:12 253 查看
第三天:(目标:讨论Paint的机制,避免丢失每次画图的结果)
昨天的程序中,我们用两种方式来进行画图,一种是在MouseUp时通过创建Canvas的Graphics对象作图,一种是在Canvas的Paint事件中作图。其实这里面有个问题,如果我们没有写MouseMove和Paint中的代码,当完成了一条直线的作图后,我们发现如果将ApplicationForm最小化,然后还原,直线就没有了~~不过一旦在Paint中加了昨天的代码,我们会发现这条直线就一直存在,但是当画下一条直线时,上一条直线也消失了~~
为什么Canvas能绘图?
对于每个Windows的窗口(我们程序里使用的m_Canvas也可以看成一个Windows的窗口)它都会在消息循环里去响应Paint的消息,当它的一部分或者全部绘图区失效时,就会发出一个重绘的请求。失效会发生在如当窗口的一部分或全部被另一个窗口挡住,或者发生resize事件,又或者被最小化然后还原等等条件下,当窗口失效后,Windows会去重绘失效的那部分,最基本的情况,就是用窗口的背景色去刷新失效的部分,然后将其置为有效。
有了这个理解,我们就应该能明白为什么会有昨天的问题了。对于MouseUp里绘图的情况,当窗口最小化然后还原,我们没有在Paint事件中做任何处理,这样当系统重绘消息发出后,整个窗体就被刷白了,上次绘图的结果就没有被保存
对于第二种情况,基于同样的原理,画第二条线时,第一条线的信息并没有被保存下来,接着系统以背景色刷新,然后执行画线(第二条)命令,这样就只有一条线能被显示在Canvas上。
所以,我们需要做的是,保存所有的画图信息,并在Paint时间被触发时,重绘保存的图形
我们需要一个添加一个类,这个类能保存绘图时所需的全部信息,命名为DrawInformation。
class DrawInformation
{
public DrawInformation(Point startPoint, Point endPoint, DrawType currentDrawType)
{
m_StartPoint = startPoint;
m_EndPoint = endPoint;
m_CurrentDrawType = currentDrawType;
}

public Point StartPoint
{
get { return m_StartPoint; }
}

public Point EndPoint
{
get { return m_EndPoint; }
}

public DrawType CurrentDrawType
{
get { return m_CurrentDrawType; }
}

private Point m_StartPoint;
private Point m_EndPoint;
private DrawType m_CurrentDrawType;
}
对于整个程序,我们需要添加一个List<DrawInformation>,当每次mouseup时,创建一个DrawInfomation对象,并添加到该list中,当Paint事件触发后,我们遍历每个DrawInformation对象,根据不同的DrawType重绘已经画过的图形。更改后的代码如下:
private void m_Canvas_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
m_StartPoint = e.Location;
}
}

private void m_Canvas_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
m_EndPoint = e.Location;

DrawInformation info = new DrawInformation(m_StartPoint, m_EndPoint, m_CurrentDrawType);
m_DrawInfoList.Add(info);
m_Canvas.Invalidate();
}
}

private void m_Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
m_EndPoint = e.Location;
m_Canvas.Invalidate();
}
}

private void m_Canvas_Paint(object sender, PaintEventArgs e)
{
// Draw the current preview
switch (m_CurrentDrawType)
{
case DrawType.Line:
e.Graphics.DrawLine(Pens.Black, m_StartPoint, m_EndPoint);
break;
case DrawType.Circle:
Int32 width = Math.Abs(m_EndPoint.X - m_StartPoint.X);
Int32 height = Math.Abs(m_EndPoint.Y - m_StartPoint.Y);
Int32 diameter = width <= height ? width : height;
e.Graphics.DrawEllipse(Pens.Black,
new Rectangle(m_StartPoint, new Size(diameter, diameter)));
break;
default:
break;
}

// Draw the exist items
foreach (DrawInformation info in m_DrawInfoList)
{
switch (info.CurrentDrawType)
{
case DrawType.Line:
e.Graphics.DrawLine(Pens.Black, info.StartPoint, info.EndPoint);
break;
case DrawType.Circle:
Int32 width = Math.Abs(info.EndPoint.X - info.StartPoint.X);
Int32 height = Math.Abs(info.EndPoint.Y - info.StartPoint.Y);
Int32 diameter = width <= height ? width : height;
e.Graphics.DrawEllipse(Pens.Black,
new Rectangle(info.StartPoint, new Size(diameter, diameter)));
break;
default:
break;
}
}
}

private Point m_StartPoint;
private Point m_EndPoint;
private DrawType m_CurrentDrawType;
private List<DrawInformation> m_DrawInfoList = new List<DrawInformation>();
这样,所有的图形都被不会因为重绘而消失了,但是现在我们的仅能画简单的线和圆,明天我们会尝试设置更多的参数,绘制各种各样的线和圆,并把所绘的图形保存为图片。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: