Persistent graphics WinForms

ⅰ亾dé卋堺 提交于 2019-12-14 02:22:00

问题


I've a WinForms application on wich i have to draw some lines between controls. These lines need to be persistent, so i override the form OnPaint() event.

The problem is that, the re-draw of the lines aren't very smooth.

I'm creating the graphics as follows:

Graphics g;
g = this.CreateGraphics();
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.FillRectangle(Brushes.White, this.ClientRectangle);

And drawing the lines as follows:

public void lineDraw(Control L1, Control L2) {            
    using (Pen pen = new Pen(Color.Black, 4)) {
        pen.StartCap = System.Drawing.Drawing2D.LineCap.Flat;
        pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
        int x1, x2, y1, y2;
        //choose x/y coordinates
        g.DrawLine(pen, x1, y1, x2, y2);
    }
}

Is there any property i can set to improve the smoothness of the drawn graphics?


回答1:


Goal

An image is shown on a control (or form).

Invalidation

Any time the control (or form) is resized, minimalized/maximalized, partically obscured or moved around, it must be (partially) redrawn. When this happens the part of the control that must be redrawn is said to be invalidated.

When invalidated the control does something like this:

  1. Call OnPaintBackground: this fills the invalidated region with the background color.
  2. Call OnPaint: this draws the text and graphics on top of the background.

Why OnPaint causes flickering

You have overridden the OnPaint method of the control. Every time the control is redrawn you see a flash of the control with only its background color drawn in it. That is after OnPaintBackground has been called and before OnPaint has been called.

The solutions

  • If you have a static image (i.e. it never changes):

    1. In the Load event: create a new Bitmap object.
    2. Fill it with the background color and draw the lines and shapes on it.
    3. Assign this Bitmap object to the control's BackgroundImage property.
  • If you have a static image that must resize when the control resizes:

    1. Override the OnResize method and create the new Bitmap in there. Use the control's ClientSize property for the size of the Bitmap.
    2. Fill it with the background color and draw the lines and shapes on it.
    3. Assign this Bitmap object to the control's BackgroundImage property.
  • If you have an animated image:

    1. In the Load event set the DoubleBuffered property of the control to true. Setting this prevents the flicker you saw as it uses an invisible buffer to draw the control.
    2. Override the control's OnPaint method. Get the Graphics context of the control and draw the lines and shapes directly on the control.
    3. Create and enable a new Timer object and in its callback method call the control's Invalidate method followed by the Update method (as shown here). Set the timer to fire, for example, every 40 ms.



回答2:


You probably shouldn't use CreateGraphics here, and more importantly, don't use a local variable to store the graphic object. Use the graphic object obtained from the paint event and invalidate as needed.

protected override void OnPaint(PaintEventArgs e) {
  e.Graphics.Clear(Color.White);
  e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

  using (Pen pen = new Pen(Color.Black, 4)) {
    pen.StartCap = Drawing2D.LineCap.Flat;
    pen.EndCap = Drawing2D.LineCap.ArrowAnchor;
    int x1, x2, y1, y2;
    //choose x/y coordinates
    e.Graphics.DrawLine(pen, x1, y1, x2, y2);
  }

  base.OnPaint(e);
}



回答3:


This's my way, its works for me

//FormMain.cs
private const float DisplayRatio = 6;

private Bitmap _bmpDisp; //use an in-memory bitmap to Persistent graphics
private Graphics _grpDisp4Ctl;
private Graphics _grpDisp4Bmp;
private Point _ptOldDsp;


private void FormMain_Shown(object sender, EventArgs e)
{
    _grpDisp4Ctl = CreateGraphics();
    _grpDisp4Ctl.SetHighQulity();

    _bmpDisp = new Bitmap(ClientSize.Width, ClientSize.Height);
    _grpDisp4Bmp = Graphics.FromImage(_bmpDisp);
    _grpDisp4Bmp.SetHighQulity();

    _ptOldDsp = new Point(
        (int)((MousePosition.X - SystemInformation.VirtualScreen.Left) / DisplayRatio),
        (int)((MousePosition.Y - SystemInformation.VirtualScreen.Top) / DisplayRatio)
    );
}

private void UpdateDisplay(MouseHookEvent mhep) //your implement
{        
    var ptNew = mhep.Position;
    ptNew.Offset(new Point(-SystemInformation.VirtualScreen.Left, -SystemInformation.VirtualScreen.Top));
    ptNew.X = (int)(ptNew.X / DisplayRatio);
    ptNew.Y = (int)(ptNew.Y / DisplayRatio);

    _grpDisp4Ctl.DrawLine(Pens.White, _ptOldDsp, ptNew); //draw smooth lines to mem and ui
    _grpDisp4Bmp.DrawLine(Pens.White, _ptOldDsp, ptNew);

    _ptOldDsp = ptNew;

}

private void FormMain_Paint(object sender, PaintEventArgs e)
{
    // like vb6's auto redraw :)
    e.Graphics.DrawImage(_bmpDisp, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel);
}

//common.cs
internal static void SetHighQulity(this Graphics g)
{
    g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
    g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
}



回答4:


I know it's an older post, but you can also try setting DoubleBuffered property of the form to TRUE, read the following:

"Buffered graphics can reduce or eliminate flicker that is caused by progressive redrawing of parts of a displayed surface. Buffered graphics require that the updated graphics data is first written to a buffer. The data in the graphics buffer is then quickly written to displayed surface memory. The relatively quick switch of the displayed graphics memory typically reduces the flicker that can otherwise occur."



来源:https://stackoverflow.com/questions/14985570/persistent-graphics-winforms

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!