我写了一个绘图的程序
发现,当只用像 直线、圆,矩形时 画面会闪烁具体情况是:当选择直线(以直线为例)时,拖动到自己想要的位置,过程中就会闪烁(就是选择直线,然后按住鼠标左键拖动画线,中途显示的时候)
因为在拖动的时候要显示出拖动的线,所以我不停的清除以前的再显示现在的线条。这就使得画面很闪。
我看了Windows自带的画图工具好像没有闪的情况,我想请教各位大侠,有什么好的方法吗????我用了双缓存绘图,还是没有用。我是先根据用户的拖动先显示轨迹(没有用双缓存),等用户确定了就用另一个Graphic绘制到Bitmap中。

解决方案 »

  1.   

    楼主你看一下 下面代码
    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();
            }
      

  2.   

    C#绘图双缓冲技术总结GDI+的双缓冲问题终于搞定了, 真是松了一口气!一直以来的误区:.net1.1 和 .net 2.0 在处理控件双缓冲上是有区别的。.net 1.1 中,使用:this.SetStyle(ControlStyles.DoubleBuffer, true); .net 2.0中,使用:this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);怪不说老是提示参数无效,一直也不知道是这个问题,呵呵要知道,图元无闪烁的实现和图元的绘制方法没有多少关系,只是绘制方法可以控制图元的刷新区域,使双缓冲性能更优!导致画面闪烁的关键原因分析:      一、绘制窗口由于大小位置状态改变进行重绘操作时     绘图窗口内容或大小每改变一次,都要调用Paint事件进行重绘操作,该操作会使画面重新刷新一次以维持窗口正常显示。刷新过程中会导致所有图元重新绘制,而各个图元的重绘操作并不会导致Paint事件发生,因此窗口的每一次刷新只会调用Paint事件一次。窗口刷新一次的过程中,每一个图元的重绘都会立即显示到窗口,因此整个窗口中,只要是图元所在的位置,都在刷新,而刷新的时间是有差别的,闪烁现象自然会出现。     所以说,此时导致窗口闪烁现象的关键因素并不在于Paint事件调用的次数多少,而在于各个图元的重绘。     根据以上分析可知,当图元数目不多时,窗口刷新的位置也不多,窗口闪烁效果并不严重;当图元数目较多时,绘图窗口进行重绘的图元数量增加,绘图窗口每一次刷新都会导致较多的图元重新绘制,窗口的较多位置都在刷新,闪烁现象自然就会越来越严重。特别是图元比较大绘制时间比较长时,闪烁问题会更加严重,因为时间延迟会更长。     解决上述问题的关键在于:窗口刷新一次的过程中,让所有图元同时显示到窗口。      二、进行鼠标跟踪绘制操作或者对图元进行变形操作时     当进行鼠标跟踪绘制操作或者对图元进行变形操作时,Paint事件会频繁发生,这会使窗口的刷新次数大大增加。虽然窗口刷新一次的过程中所有图元同时显示到窗口,但也会有时间延迟,因为此时窗口刷新的时间间隔远小于图元每一次显示到窗口所用的时间。因此闪烁现象并不能完全消除!     所以说,此时导致窗口闪烁现象的关键因素在于Paint事件发生的次数多少。      解决此问题的关键在于:设置窗体或控件的几个关键属性。  
    --------------------------------------------------------------------------------
    下面来介绍解决办法的具体细节: 
    --------------------------------------------------------------------------------
    解决双缓冲的关键技术: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();//释放资源至此,双缓冲问题解决,两种方式的实现效果都一样,但最后一种方式的占有的内存很少,不会出现内存泄露!