繁体   English   中英

如何使像素像效果一样淡入/淡出?

[英]How can i make on the pixels fade in/out like effect?

今天,即时通讯正在绘制事件中的像素闪烁。 在form1中,我在计时器滴答事件中将此代码设置为1000ms。

private void timer1_Tick(object sender, EventArgs e)
        {
            CloudEnteringAlert.cloudColorIndex = (CloudEnteringAlert.cloudColorIndex + 1) % CloudEnteringAlert.cloudColors.Length;
            pictureBox1.Invalidate();
        }

在CloudEntering类中,我位于顶部:

public static Brush[] cloudColors = new[] { Brushes.Yellow, Brushes.Transparent };

然后在paint方法中,此paint方法是从form1 pictureBox1 paint事件调用的:

foreach (PointF pt in clouds)
                {
                    e.FillEllipse(cloudColors[cloudColorIndex], pt.X * (float)currentFactor, pt.Y * (float)currentFactor, 7f, 7f);
                }

所以我现在看到的是像素为黄色的一秒钟,像素为透明的一秒钟。

现在我想做的是:

  1. 每个像素将从半径5开始。

  2. 每个像素半径将增大到25。

  3. 动画将自上而下。

  4. 到达半径25的每个像素将开始变小,回到半径5。

  5. 当第一个像素从5开始时将变为半径15,下一个像素将开始变得更大。

因此,如果第一个像素从5开始,现在是15,那么下一个像素将开始变大,第一个像素将继续增加到25,而第一个像素是25时它将变小。 第二个在其15时变大,第三个将变大,依此类推。

所有像素将以半径5开始,但是只有第一个像素开始变大,然后变为15,然后是下一个像素;当第一个为25时,它将变小。

这是每个像素之间的时间。

并且每个像素半径大小的变化应花费300ms!

我该怎么做 ?

首先,您需要将渲染单个椭圆所需的所有信息封装到一个单独的类中。 就像这样:

public class Ellipse
{
    public PointF Center { get; set; }
    public Brush Brush { get; set; }
    public float Diameter { get; set; }
    public float DiameterDelta { get; set; }

    public Ellipse(float x, float y)
    {
        Center = new PointF(x, y);
        Brush = Brushes.Blue;
        Diameter = 5;
        DiameterDelta = 1;
    }
}

Ellipse.DiameterDelta属性是将用于动画的delta值,它可以是正值(从直径5到直径25 ),也可以是负值(反向时)。 此属性的值(我在上面使用过1 )和Timer.Interval一起将影响动画的速度。

更好的OOP设计可能会主张将动画相关的属性移出此类,但为简单起见,最好从此开始。

在您的计时器事件中,您可能会遇到以下情况:

private void timer_Tick(object sender, EventArgs e)
{
    // presuming that you made a separate user control
    // which has a collection of ellipses in a `Clouds` property

    foreach (var c in cloudBox.Clouds)
        Animate(c);

    cloudBox.Invalidate();
}

private void Animate(Ellipse c)
{
    // update diameter
    c.Diameter += c.DiameterDelta;

    // when you reach bounds, change delta direction
    if ((c.DiameterDelta < 0 && c.Diameter <= 5) ||
        (c.DiameterDelta > 0 && c.Diameter >= 25))
        c.DiameterDelta = -c.DiameterDelta;
}

为了获得平滑,不闪烁的动画,您很可能必须使用在其构造函数中设置了ControlStyles.AllPaintingInWmPaintControlStyles.OptimizedDoubleBuffer的自定义控件,所以我要做的不是PictureBox ,而是:

public partial class CloudBox : UserControl
{
    public CloudBox()
    {
        InitializeComponent();
        SetStyle(
            ControlStyles.AllPaintingInWmPaint |
            ControlStyles.OptimizedDoubleBuffer |
            ControlStyles.UserPaint |
            ControlStyles.ResizeRedraw, true);
    }

    private readonly List<Ellipse> _clouds = new List<Ellipse>();
    public List<Ellipse> Clouds
    {
        get { return _clouds; }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
        e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        e.Graphics.SmoothingMode = SmoothingMode.HighQuality;

        foreach (var cloud in _clouds)
        {
            e.Graphics.FillEllipse(
               cloud.Brush, cloud.Center.X, cloud.Center.Y,
               cloud.Diameter, cloud.Diameter);
        }

        base.OnPaint(e);
    }
}

我尚未对此进行测试,但我相信您可以填写详细信息。 Timer.Interval设置为10或20 ms应该会产生非常流畅的动画恕我直言。

[编辑]要用一些测试数据实例化整个事情(我不知道从哪里获得),可以在Form.Load事件处理程序中使用类似以下内容的东西:

for (int i = 0; i < 400; i += 50)
    for (int j = 0; j < 400; j += 50)
        cloudBox.Clouds.Add(new Ellipse(i, j));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM