Winforms图形闪烁。 (双缓冲没有帮助!)

时间:2015-12-30 23:05:53

标签: c# winforms visual-studio graphics double-buffering

我正在尝试创建一个简单的Windows窗体图形应用程序,每次用户点击并扩展时,基本上会绘制一个圆圈,同时慢慢消失。

当我尝试将Paint()事件用于我的图形功能时,没有任何反应,因此我创建了一个名为“Render”的单独函数,该函数在我的主要更新Timer中调用。

该应用程序工作但图形闪烁。经过一些研究后,我意识到我必须启用双缓冲,以便渲染到缓冲区,然后缓冲区将呈现在屏幕上。

闪烁仍然没有停止! 这是因为双缓冲仅适用于Paint()事件,如果是,我如何才能使Paint()事件起作用,或者我没有启用Double Buffering?

这是我的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Widget
{

public class Circle
{
    public float X;
    public float Y;
    public float Radius;
    public int Alpha;

    public Circle(float X, float Y, float Radius, int Alpha)
    {
        this.X = X;
        this.Y = Y;
        this.Radius = Radius;
        this.Alpha = Alpha;
    }
}

public partial class Form1 : Form
{
    public static readonly int ScreenX = Screen.PrimaryScreen.Bounds.Width;
    public static readonly int ScreenY = Screen.PrimaryScreen.Bounds.Height;

    public int WindowWidth = 500, WindowHeight = 500;
    public Graphics G;
    private Pen Pen;

    private Timer timer = new Timer();
    private List<Circle> Circles;

    public Form1()
    {
        this.Text = "Widget - Sam Brandt";
        this.Size = new Size(WindowWidth, WindowHeight);
        this.StartPosition = FormStartPosition.Manual;
        this.Location = new Point(ScreenX - WindowWidth - 100, 0);
        this.FormBorderStyle = FormBorderStyle.FixedSingle;
        this.MaximizeBox = false;
        this.Icon = new Icon("C:\\Users\\Admin\\Desktop\\Code Repositories\\Visual Studios\\Widget\\Widget\\Properties\\WidgetIcon.ico");
        Pen = new Pen(Color.Black, 1);
        G = CreateGraphics();
        //this.Paint += new PaintEventHandler(OnPaint);
        ConstructMouse();
        FormWithTimer();
        DoubleBuffered = true;

        Circles = new List<Circle>();
    }

    public void ConstructMouse()
    {
        this.MouseUp += new MouseEventHandler(OnMouseUp);
        this.MouseMove += new MouseEventHandler(OnMouseMove);
        this.MouseDown += new MouseEventHandler(OnMouseDown);
    }

    public void FormWithTimer()
    {
        timer.Tick += new EventHandler(timer_Tick);
        timer.Interval = (10);
        timer.Enabled = true;
        timer.Start();
    }

    protected void OnMouseUp(object sender, MouseEventArgs e)
    {
    }

    protected void OnMouseMove(object sender, MouseEventArgs e)
    {
    }

    public void OnMouseDown(object sender, MouseEventArgs e)
    {
        Circles.Add(new Circle(e.Location.X, e.Location.Y, 0, 255));
    }

   /*public void OnPaint(object sender, PaintEventArgs e)
    {
        e.Graphics.Clear(Color.White);
        for (int i = 0; i < Circles.Count; i++)
        {
            Circle C = Circles[i];
            e.Graphics.DrawEllipse(new Pen(Color.FromArgb(C.Alpha, 0, 0, 0), 1), C.X - C.Radius, C.Y - C.Radius, 2 * C.Radius, 2 * C.Radius);
        }
    }*/

    private void Tick()
    {
        for (int i = 0; i < Circles.Count; i++)
        {
            Circle C = Circles[i];
            C.Radius++;
            C.Alpha -= 3;
            if (C.Alpha == 0)
            {
                Circles.RemoveAt(i);
            }
        }
    }

    public void Render()
    {
        G.Clear(Color.White);
        for (int i = 0; i < Circles.Count; i++)
        {
            Circle C = Circles[i];
            G.DrawEllipse(new Pen(Color.FromArgb(C.Alpha, 0, 0, 0), 1), C.X - C.Radius, C.Y - C.Radius, 2 * C.Radius, 2 * C.Radius);
        }
    }

    public void timer_Tick(object sender, EventArgs e)
    {
        Render();
        Tick();
    }
}
}

4 个答案:

答案 0 :(得分:4)

简短回答 - 保持DoubleBuffered = true并使用Paint活动。

  

当我尝试将PaintEvent用于我的图形功能时,没有发生任何事情

当您进行一些修改并希望反映它们时,请使用Control.Invalidate方法,根据文档

  

使控件的整个表面无效并导致重绘控件。

在你的情况下,像这样

void timer_Tick(object sender, EventArgs e)
{
    Tick();
    Invalidate();
}

答案 1 :(得分:0)

此处有更多观察,但可能就是答案。

  • 为什么要定时?
  • 使用Paint事件,当GDI +确定它需要时调用它,你不断按原样绘制代码。
  • 您的代码使您看起来没有使用双缓冲。

答案 2 :(得分:0)

我将所有绘图都绘制到一个单独的Graphics对象,然后只有在进行了更改时才将其复制到计时器tick事件的主Graphics对象上。您可能需要使用布尔成员跟踪它。这意味着您的背景图必须由其他一些事件触发。

如果您的图片实际上每10毫秒更换一次,我会稍微减慢计时器的速度并将其设置为50毫秒。

答案 3 :(得分:0)

试试这个(在VB中):

Dim aProp = GetType(Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance)
aProp.SetValue(Me, True, Nothing)

双缓冲也有问题,而且通常设置属性DoubleBuffered为true不起作用。我在网上找到了这个解决方案