我写了一个绘图的程序
发现,当只用像 直线、圆,矩形时 画面会闪烁具体情况是:当选择直线(以直线为例)时,拖动到自己想要的位置,过程中就会闪烁(就是选择直线,然后按住鼠标左键拖动画线,中途显示的时候)
因为在拖动的时候要显示出拖动的线,所以我不停的清除以前的再显示现在的线条。这就使得画面很闪。
我看了Windows自带的画图工具好像没有闪的情况,我想请教各位大侠,有什么好的方法吗????我用了双缓存绘图,还是没有用。我是先根据用户的拖动先显示轨迹(没有用双缓存),等用户确定了就用另一个Graphic绘制到Bitmap中。
发现,当只用像 直线、圆,矩形时 画面会闪烁具体情况是:当选择直线(以直线为例)时,拖动到自己想要的位置,过程中就会闪烁(就是选择直线,然后按住鼠标左键拖动画线,中途显示的时候)
因为在拖动的时候要显示出拖动的线,所以我不停的清除以前的再显示现在的线条。这就使得画面很闪。
我看了Windows自带的画图工具好像没有闪的情况,我想请教各位大侠,有什么好的方法吗????我用了双缓存绘图,还是没有用。我是先根据用户的拖动先显示轨迹(没有用双缓存),等用户确定了就用另一个Graphic绘制到Bitmap中。
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
SelectRect.Width = 0;
SelectRect.Height = 0;
SelectRect.X = e.X;
SelectRect.Y = e.Y; ps.X = e.X;
ps.Y = e.Y;
pe = ps; } private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// 第一个 DrawReversible 为消除原来的辅助线
// 第二个 DrawReversible 画新的辅助线
if (rbLine.Checked)
{
ControlPaint.DrawReversibleLine(this.PointToScreen(ps), this.PointToScreen(pe), Color.Black);
pe = e.Location;
ControlPaint.DrawReversibleLine(this.PointToScreen(ps), this.PointToScreen(pe), Color.Black);
}
else
{
ControlPaint.DrawReversibleFrame(this.RectangleToScreen(SelectRect), Color.Black, FrameStyle.Dashed);
SelectRect.Width = e.X - SelectRect.X;
SelectRect.Height = e.Y - SelectRect.Y;
ControlPaint.DrawReversibleFrame(this.RectangleToScreen(SelectRect), Color.Black, FrameStyle.Dashed);
}
} } private void Form1_MouseUp(object sender, MouseEventArgs e)
{
Graphics g = this.CreateGraphics();
Pen p = new Pen(Color.Blue, 2);
if (rbLine.Checked)
{
ControlPaint.DrawReversibleLine(this.PointToScreen(ps), this.PointToScreen(pe), Color.Black);
g.DrawLine(p, ps, pe);
}
else
{
ControlPaint.DrawReversibleFrame(this.RectangleToScreen(SelectRect), Color.Black, FrameStyle.Dashed);
g.DrawRectangle(p, SelectRect);
}
g.Dispose();
}
--------------------------------------------------------------------------------
下面来介绍解决办法的具体细节:
--------------------------------------------------------------------------------
解决双缓冲的关键技术:1、设置显示图元控件的几个属性: 必须要设置,否则效果不是很明显!this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true);2、窗口刷新一次的过程中,让所有图元同时显示到窗口。 可以通过以下几种方式实现,这几种方式都涉及到Graphics对象的创建方式。Graphics对象的创建方式:a、在内存上创建一块和显示控件相同大小的画布,在这块画布上创建Graphics对象。 接着所有的图元都在这块画布上绘制,绘制完成以后再使用该画布覆盖显示控件的背景,从而达到“显示一次仅刷新一次”的效果! 实现代码(在OnPaint方法中): Rectangle rect = e.ClipRectangle; Bitmap bufferimage = new Bitmap(this.Width, this.Height);
Graphics g = Graphics.FromImage(bufferimage); g.Clear(this.BackColor);
g.SmoothingMode = SmoothingMode.HighQuality; //高质量
g.PixelOffsetMode = PixelOffsetMode.HighQuality; //高像素偏移质量 foreach (IShape drawobject in doc.drawObjectList)
{ if (rect.IntersectsWith(drawobject.Rect))
{
drawobject.Draw(g);
if (drawobject.TrackerState == config.Module.Core.TrackerState.Selected
&& this.CurrentOperator == Enum.Operator.Transfrom)//仅当编辑节点操作时显示图元热点
{
drawobject.DrawTracker(g);
}
} } using (Graphics tg = e.Graphics)
{
tg.DrawImage(bufferimage, 0, 0); //把画布贴到画面上
}b、直接在内存上创建Graphics对象: Rectangle rect = e.ClipRectangle; BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current;
BufferedGraphics myBuffer = currentContext.Allocate(e.Graphics, e.ClipRectangle);
Graphics g = myBuffer.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
g.Clear(this.BackColor);
foreach (IShape drawobject in doc.drawObjectList)
{
if (rect.IntersectsWith(drawobject.Rect))
{
drawobject.Draw(g);
if (drawobject.TrackerState == config.Module.Core.TrackerState.Selected
&& this.CurrentOperator == Enum.Operator.Transfrom)//仅当编辑节点操作时显示图元热点
{
drawobject.DrawTracker(g);
}
}
} myBuffer.Render(e.Graphics);
g.Dispose();
myBuffer.Dispose();//释放资源至此,双缓冲问题解决,两种方式的实现效果都一样,但最后一种方式的占有的内存很少,不会出现内存泄露!