簡體   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