winforms 如何在UserControl Paint事件中动画点?

hmae6n7t  于 2022-11-17  发布在  其他
关注(0)|答案(2)|浏览(165)

在油漆事件,因为我想能够控制点的大小,颜色和更多的属性。

using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;

public partial class LoadingLabel : UserControl
{
    public LoadingLabel()
    {
        InitializeComponent();
    }

    private void LoadingLabel_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        e.Graphics.FillEllipse(Brushes.Red, 1, 1, 20, 20);
        Thread.Sleep(1);
        e.Graphics.FillEllipse(Brushes.Red, 1, 1, 0, 0);
        Thread.Sleep(1);
    }
}

我首先尝试做一个简单的点,一段时间后消失,然后再次显示,但它不工作,我看到一个红色的仍然点(点)。
稍后,当这将工作,我想使3点动画像加载动画。
我试过了

using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;

public partial class LoadingLabel : UserControl
{
    private bool animate = false;

    public LoadingLabel()
    {
        InitializeComponent();
        timer1.Enabled = true;
    }

    private void LoadingLabel_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        if (animate == false)
        {
            e.Graphics.FillEllipse(Brushes.Red, 1, 1, 20, 20);
        }
        else
        {
            e.Graphics.FillEllipse(Brushes.Red, 5, 1, 20, 20);
        }
    }

    int count = 0;
    private void timer1_Tick(object sender, EventArgs e)
    {
        count++;

        if(count == 10 && animate == false)
        {
            animate = true;
        }

        if(count == 20 && animate)
        {
            animate = false;
            count = 0;
        }
        this.Invalidate();
    }
}

结果是第一个点抽牌,然后是第二个点抽牌,但第一个点抽牌没有了:
看起来该点向右移动并向左返回。

但我想要一个加载效果与3点。而不是移动点。
这是工作与3点,但它看起来太复杂的3点。如果我想要100点?
也许我应该在paint事件中使用一个循环?

using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;

public partial class LoadingLabel : UserControl
{
    private int numofpoints = 0;

    public LoadingLabel()
    {
        InitializeComponent();
        timer1.Enabled = true;
    }

    private void LoadingLabel_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        if(numofpoints == 0)
        {
            e.Graphics.FillEllipse(Brushes.Red, 1, 1, 20, 20);
        }
        if(numofpoints == 1)
        {
            e.Graphics.FillEllipse(Brushes.Red, 5, 1, 20, 20);
        }
        if(numofpoints == 2)
        {
            e.Graphics.FillEllipse(Brushes.Red, 10, 1, 20, 20);
        }
    }

    int count = 0;
    private void timer1_Tick(object sender, EventArgs e)
    {
        count++;

        if(count == 10)
        {
            numofpoints = 0;
        }

        if(count == 20)
        {
            numofpoints = 1;
        }

        if(count == 30)
        {
            numofpoints = 2;
            count = 0;
        }
        this.Invalidate();
    }
}

我尝试过的另一个更新:

using System.ComponentModel;
 using System.Drawing;
 using System.Drawing.Drawing2D;
    
 public partial class LoadingLabel : UserControl
 {
     private List<PointF> points = new List<PointF>();

     public LoadingLabel()
     {
         InitializeComponent();
         points.Add(new PointF(0, 0));
         timer1.Enabled = true;
     }

     private void LoadingLabel_Paint(object sender, PaintEventArgs e)
     {
         e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            
         for (int i = 0; i < points.Count; i++)
         {
             e.Graphics.FillEllipse(Brushes.Red, points[i].X, points[i].Y, 20, 20);
         }
     }

     int count = 0;
     private void timer1_Tick(object sender, EventArgs e)
     {
         count++;

         if (count < 3)
         {
             points.Add(new PointF(count * 20, 0));
             //points = new List<PointF>();
         }
         //this.Invalidate();
     }
 }

如果我在tick事件中创建示例,它将不会绘制任何东西。如果我使用Invalidate线,它将使点像闪烁。我想要的是创建一个加载效果动画。
现在代码的结果仍然是3点,我想像在链接中那样动画化它们。

大概是这样的:

x7rlezfr

x7rlezfr1#

由于基于您发布的图像,您希望设置一系列点的动画,其中只有 active 点会改变颜色,因此您的UserControl可以定义允许指定点的数量、点的颜色和 active 点的颜色的属性。
计时器可用于更改当前活动的点,因此绘制程序知道何时更改其中一个点的颜色。
当指定的点数更改时,UserControl将自动调整大小。
此外,当第一次创建UserControl时,它会设置其MinimumSize,因此点始终可见。
您可以扩展此 * 模板 *,添加更多功能。
请注意UserControl的建构函式中的这些行:

components = new Container();
dotsTimer = new Timer(components) { ... };

这会指示Timer组件将其自身添加到Parent容器的组件中,因此在释放Parent时,Timer也会被释放,其事件处理程序也会被移除。
设置DoubleBuffered = true;可避免绘制点时出现闪烁。
调用Start()方法启动动画,调用Stop()方法停止动画。

using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;

public partial class LoadingLabel : UserControl {

    private int m_NumberOfDots = 5;
    private Color m_DotColor = Color.Cyan;
    private Color m_DotActiveColor = Color.Blue;
    private float dotSize = 20.0f;
    private float dotSpacing = 20.0f;
    private int currentDot = 0;
    private Timer dotsTimer = null;

    public LoadingLabel()
    {
        InitializeComponent();
        components = new Container();
        dotsTimer = new Timer(components) { Interval = 200 };
        dotsTimer.Tick += DotsTimer_Tick;

        DoubleBuffered = true;
        Padding = new Padding(5);
    }

    [DefaultValue(5)]
    public int NumberOfDots {
        get => m_NumberOfDots;
        set {
            value = Math.Max(3, Math.Min(value, 7));
            if (m_NumberOfDots != value) {
                m_NumberOfDots = value;

                bool running = dotsTimer.Enabled;
                Stop();
                SetMinSize();
                if (running) Start();
            }
        }
    }

    [DefaultValue(typeof(Color), "Cyan")]
    public Color DotColor { 
        get => m_DotColor;
        set {
            m_DotColor = value;
            Invalidate();
        } 
    }

    [DefaultValue(typeof(Color), "Blue")]
    public Color DotActiveColor { 
        get => m_DotActiveColor;
        set {
            m_DotActiveColor = value;
            Invalidate();
        } 
    }

    protected override void OnPaint(PaintEventArgs e) {
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        for (int dot = 0; dot < m_NumberOfDots; dot++) {
            var color = dot == currentDot ? DotActiveColor : DotColor;
            var pos = Padding.Left + (dotSize + dotSpacing) * dot;
            using (var brush = new SolidBrush(color)) {
                e.Graphics.FillEllipse(brush, pos, Padding.Top, dotSize, dotSize);
            }
        }
        base.OnPaint(e);
    }

    protected override void OnHandleCreated(EventArgs e) {
        base.OnHandleCreated(e);
        SetMinSize();
    }

    protected override void OnHandleDestroyed(EventArgs e) {
        Stop();
        base.OnHandleDestroyed(e);
    }

    private void DotsTimer_Tick(object sender, EventArgs e) {
        currentDot += 1;
        currentDot %= m_NumberOfDots;
        Invalidate();
    }

    public void Start() => dotsTimer.Start();

    public void Stop() {
        dotsTimer.Stop();
        currentDot = 0;
        Invalidate();
    }

    private void SetMinSize() {
        var width = Padding.Left + Padding.Right + 
            (dotSize * m_NumberOfDots) + (dotSpacing * (m_NumberOfDots - 1)) + 1;
        var height = Padding.Top + Padding.Bottom + dotSize + 1;
        MinimumSize = new Size((int)width, (int)height);
        Size = MinimumSize;
    }
}

它是这样工作的:

根据需要,自定义ComboBox控件的this is the PasteBin用于选择Color。

pjngdqdw

pjngdqdw2#

对Paint方法/事件的一次调用应该绘制该控件在该时刻的外观。如果希望添加动画,则应该使控件重复重绘自身,并使用某些内部状态来跟踪动画。

相关问题