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

C# Winforms图形闪烁。(双缓冲没有帮助!),c#,winforms,visual-studio,graphics,double-buffering,C#,Winforms,Visual Studio,Graphics,Double Buffering,我正在尝试创建一个简单的Windows窗体图形应用程序,它基本上会在用户每次单击并展开时画一个圆圈,同时慢慢消失。 当我尝试将Paint()事件用于我的图形功能时,什么也没有发生,因此我创建了一个名为“Render”的单独函数,该函数在我的主更新计时器中调用 该应用程序运行正常,但图形闪烁。经过一些研究后,我意识到我必须启用双缓冲,以便它将渲染到缓冲区,然后将缓冲区渲染到屏幕。 闪烁的声音仍然没有停止 这是因为双缓冲仅适用于Paint()事件,如果是,如何使Paint()事件工作,还是我没有正确

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

当我尝试将
Paint()
事件用于我的图形功能时,什么也没有发生,因此我创建了一个名为“Render”的单独函数,该函数在我的主更新
计时器中调用

该应用程序运行正常,但图形闪烁。经过一些研究后,我意识到我必须启用双缓冲,以便它将渲染到缓冲区,然后将缓冲区渲染到屏幕。

闪烁的声音仍然没有停止
这是因为双缓冲仅适用于
Paint()
事件,如果是,如何使
Paint()
事件工作,还是我没有正确启用双缓冲?

这是我的代码:

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();
    }
}
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用系统数据;
使用系统图;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
使用System.Windows.Forms;
名称空间小部件
{
公共阶级圈子
{
公共浮动X;
公众浮躁;
公众浮标半径;
公共int-Alpha;
公共圆(浮动X、浮动Y、浮动半径、整数Alpha)
{
这个.X=X;
这个。Y=Y;
这个。半径=半径;
这个α=α;
}
}
公共部分类Form1:Form
{
public static readonly int ScreenX=Screen.PrimaryScreen.Bounds.Width;
public static readonly int ScreenY=Screen.PrimaryScreen.Bounds.Height;
公共int窗宽=500,窗高=500;
公共图形G;
私人钢笔;
专用计时器=新计时器();
私人名单圈;
公共表格1()
{
this.Text=“Widget-Sam Brandt”;
this.Size=新尺寸(窗宽、窗高);
this.StartPosition=FormStartPosition.Manual;
此位置=新点(ScreenX-WindowWidth-100,0);
this.FormBorderStyle=FormBorderStyle.FixedSingle;
this.ebox=false;
this.Icon=新图标(“C:\\Users\\Admin\\Desktop\\Code Repositories\\Visual Studio\\Widget\\Widget\\Properties\\WidgetIcon.ico”);
笔=新笔(颜色:黑色,1);
G=CreateGraphics();
//this.Paint+=新的PaintEventHandler(OnPaint);
鼠标();
FormWithTimer();
双缓冲=真;
圆圈=新列表();
}
公共鼠标()
{
this.MouseUp+=新的MouseEventHandler(OnMouseUp);
this.MouseMove+=新的MouseEventHandler(OnMouseMove);
this.MouseDown+=新的MouseEventHandler(OnMouseDown);
}
public void FormWithTimer()
{
timer.Tick+=新事件处理程序(timer\u Tick);
时间间隔=(10);
timer.Enabled=true;
timer.Start();
}
MouseUp上受保护的void(对象发送器、MouseEventArgs e)
{
}
MouseMove上的受保护无效(对象发送器、MouseEventArgs e)
{
}
mousedown上的公共void(对象发送器,MouseEventArgs e)
{
添加(新的圆(e.Location.X,e.Location.Y,0,255));
}
/*public void OnPaint(对象发送器、PaintEventArgs e)
{
e、 图形。清晰(颜色。白色);
对于(int i=0;i
这里有更多的观察结果,但可能就是答案

  • 为什么是计时器
  • 使用Paint事件,当GDI+确定需要时调用它,您将不断地按原样使用代码进行绘制
  • 您的代码使它看起来好像您没有使用双缓冲

    • 这里有更多的观察结果,但可能会是答案

      • 为什么是计时器
      • 使用Paint事件,当GDI+确定需要时调用它,您将不断地按原样使用代码进行绘制
      • 您的代码使它看起来好像您没有使用双缓冲

      简短回答-保持
      双缓冲=true
      并使用
      绘制事件

      当我尝试将PaintEvent用于图形功能时,什么也没发生

      当您进行一些修改并希望反映这些修改时,请使用方法,该方法符合文档的要求

      使控件的整个表面无效,并使控件重新绘制

      在你的情况下,像这样的

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

      简短回答-保持
      DoubleBuffered=true
      并使用
      Paint
      事件

      当我尝试将PaintEvent用于图形功能时,什么也没发生

      当您进行一些修改并希望反映这些修改时,请使用方法,该方法符合文档的要求

      使控件的整个表面无效,并使控件重新绘制

      在你的情况下,像这样的

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

      我会把你所有的绘图都复制到一个单独的图形对象上,然后在计时器滴答声事件中将它复制到你的主图形对象上,只有在有变化的情况下。您可能需要使用布尔成员跟踪它。这意味着您的背景图形将具有