优化自定义控件的动画

时间:2010-10-15 20:01:39

标签: user-controls

好吧所以我正在为一些使用C#的人创建一个“Windows Forms Application”,我想让他的UI更有趣。

主表格看起来像一个大表盘,上面有自定义按钮。 (我说的是自定义按钮,因为它们实际上是我创建的简单用户控件,它有一个 PictureBox 和一个 Label ,当用户指向它时会放大,然后缩小鼠标光标移到它外面。还有一个图像属性,用于设置 PictureBox 的图像,并用作所谓的自定义按钮的图标。)

我使用了两个名为 tmrEnlarge tmrShrink 的计时器,它们分别在 MouseEnter MouseLeave 事件上激活。基本上只有几个简单的函数来增加和减少我的自定义控件中使用的 PictureBox 的大小,并使它看起来像放大......

它工作得很好,但问题是,当鼠标同时徘徊几个控件时,动画会减慢dows(在我看来这是正常的,因为定时器不是像我这样做的最佳方式!) 我也试过使用线程,但问题还在这里! : - (

我想知道的是,做这样的事情最好的方法是什么?

修改

这是我用于直接在控件上绘制图像而不使用 PictureBox 的代码:

(它只是一个快速版本,在绘制图像后会留下残留,这对我来说并不重要)

public partial class DDAnimatingLabel : UserControl
{
    public Image Image { get; set; }

    public DDAnimatingLabel()
    {
        InitializeComponent();
    }

    private void DDAnimatingLabel_MouseEnter(object sender, EventArgs e)
    {
        tmrEnlarge.Enabled = true;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        if (Image != null)
        {
            e.Graphics.DrawImage(this.Image, e.ClipRectangle);
        }
        else
            base.OnPaint(e);
    }

    private void tmrEnlarge_Tick(object sender, EventArgs e)
    {
        if (Size.Width >= MaximumSize.Width)
        {
            tmrEnlarge.Enabled = false;
            return;
        }

        Size s = Size;
        s.Height += 4;
        s.Width += 4;
        Size = s;

        Point p = Location;
        p.X -= 2;
        p.Y -= 2;
        Location = p;
    }

    private void tmrShrink_Tick(object sender, EventArgs e)
    {
        if (tmrEnlarge.Enabled)
            return;

        if (Size.Width == MinimumSize.Width)
        {
            tmrShrink.Enabled = false;
            return;
        }

        Size s = Size;
        s.Height -= 4;
        s.Width -= 4;
        Size = s;

        Point p = Location;
        p.X += 2;
        p.Y += 2;
        Location = p;
    }

    private void DDAnimatingLabel_MouseLeave(object sender, EventArgs e)
    {
        tmrShrink.Enabled = true;
    }
}

1 个答案:

答案 0 :(得分:0)

我原本误解了你的问题。前段时间我为这种事情建立了一个动画系统。在这里您可以找到该代码: http://pastebin.com/k1XmRapH

这是我的动画系统的旧版本。它很粗糙,但相对较小且易于理解。下面是一个使用动画系统的演示应用程序。

该系统的关键点是:

  • 利用单个计时器为每个运行动画提供定时“脉冲”
  • 脉冲使用经过的时间来计算要应用的更改数量

演示应用程序使用AnimationGroup来改变Size和Location属性。当鼠标进入按钮时,我们首先取消任何现有动画,然后运行动画来增长按钮。当鼠标离开按钮时,我们再次取消任何现有动画,然后运行动画使其恢复正常。将AnimationTerminate.Cancel指定为AnimationManager.Remove会取消正在运行的动画而不调用其End方法(这将完成动画)。这使按钮的属性处于我们取消时所处的状态,并平滑地将按钮恢复为正常大小。

using System;
using System.Drawing;
using System.Windows.Forms;

class Form1 : Form
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    const int PulseInterval = 20;
    const int ButtonAnimateTime = 250;

    AnimationManager animate;
    Point[] buttonLocationsNormal, buttonLocationsHover;
    Size buttonSizeNormal, buttonSizeHover;

    public Form1()
    {
        Text = "Demo";
        ClientSize = new Size(480, 100);

        animate = new AnimationManager { PulseInterval = PulseInterval };

        buttonLocationsNormal = new Point[4];
        buttonLocationsHover = new Point[4];
        buttonSizeNormal = new Size(100, 80);
        buttonSizeHover = new Size(120, 100);

        for (int n = 0, x = 10; n < 4; n++, x += 120)
        {
            Point normalLocation = new Point(x, 10);
            buttonLocationsNormal[n] = normalLocation;
            buttonLocationsHover[n] = new Point(x - 10, 0);
            Button button = new Button { Text = "Text", Location = normalLocation, Size = buttonSizeNormal };
            button.MouseEnter += (s, e) => AnimateButton(s as Button, true);
            button.MouseLeave += (s, e) => AnimateButton(s as Button, false);
            Controls.Add(button);
        }
    }

    private void AnimateButton(Button button, bool hovering)
    {
        int index = Controls.IndexOf(button);
        AnimationGroup group = button.Tag as AnimationGroup;
        if (group != null)
            animate.Remove(group, AnimationTerminate.Cancel);

        Point newLocation;
        Size newSize;
        if (hovering)
        {
            newLocation = buttonLocationsHover[index];
            newSize = buttonSizeHover;
        }
        else
        {
            newLocation = buttonLocationsNormal[index];
            newSize = buttonSizeNormal;
        }
        group = new AnimationGroup(
            new PropertyAnimation("Location", button, newLocation, TimeSpan.FromMilliseconds(ButtonAnimateTime), new PointAnimator())
            , new PropertyAnimation("Size", button, newSize, TimeSpan.FromMilliseconds(ButtonAnimateTime), new SizeAnimator())
        );
        button.Tag = group;
        animate.Add(group);
    }
}