如何以不同的速度平滑地动画Windows窗体位置?

时间:2009-06-09 03:13:33

标签: c# winforms performance animation intervals

我一直试图平滑地为一些Windows窗体位置设置动画,但如果我希望速度可变,我会遇到一些问题。换句话说,如果我想让用户选择动画的首选速度。

我发现以下文章帮助我执行了我正在寻找的动画,对于我的表单。在各方面看起来比我过去尝试过的BackgroundWorker或Threads方法更好: http://www.vcskicks.com/animated-windows-form.html

我现在唯一的问题是,如果我想要动画的速度不同,可以保持平滑的动画效果。我的代码中有两个重要的值, FPS PX 。 FPS表示每秒帧数(除此之外),PX表示移动表单的像素数。

问题1)为了获得最流畅的动画,我希望一次只能移动1px,但我认为我不能像以前那样快速移动表单我想那样。将FPS值增加到非常高的值似乎没有任何影响,就像有一个限制并且超过该限制,将没有明显的差异。我确信这有一个很好的解释。

我的问题是:你对这个问题有什么好的解决方案,或者唯一的解决办法就是改变PX值并将表格移动1px以上,如果我想要更快的移动?

问题2)如果上述问题的解决方案是相应地更改PX值,我发现(通过测试不同的值)FPS值等于300就足以满足我的移动需求形式像我想要的那样缓慢而快速。然后,如果我想要10个速度,将表格移动1,2,3,4,5,6,7,8,9和10个像素可以提供缓慢而快速的平滑动画,就像我想要的那样。如果我想要5种速度,我可以使用2,4,6,8,10等。

我的问题是:对于FPS使用300这样的值有什么问题吗?对这样的价值有不良后果吗?

这是我目前的代码:

public partial class Form1 : Form {

    bool dir = true;

    public Form1() {
        InitializeComponent();

        Location = new Point(1280/2 - Width, 800/2 - Height/2);
    }

    private void button1_Click(object sender, EventArgs e) {
        double FPS = 300;
        int PX = 1;
        long lastTicks = 0;
        long currentTicks = 0;
        double interval = (double)Stopwatch.Frequency / FPS;

        while(dir ? Left <= 1280/2 : Left >= 1280/2 - Width) {
            Application.DoEvents();

            currentTicks = Stopwatch.GetTimestamp();

            if(currentTicks >= lastTicks + interval) {
                lastTicks = Stopwatch.GetTimestamp();

                this.Location = new Point(dir ? Left + PX : Left - PX, Top);

                this.Invalidate(); //refreshes the form
            }

            Thread.Sleep(1); //frees up the cpu
        }

        dir = !dir;
    }

}

注意:这只是示例代码,出于测试目的,不是真正的代码,但如果您想指出在将其移植到实际应用程序时应该考虑的一些非常重要的事情,请成为我的访客

4 个答案:

答案 0 :(得分:4)

尝试我先前建议的这个实现(不考虑FPS):

public partial class Form1 : Form
{
    private bool go;
    private int dx = 1;
    public Form1()
    {
        InitializeComponent();
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        if (go)
        {
            this.Location = new Point(this.Location.X + dx, this.Location.Y);
            if (Location.X < 10 || Location.X > 1200)
            {
                go = false;
                dx = -dx;
            }
            else
            {
                this.Invalidate();
            }
        }
    }
    private void button1_Click(object sender, EventArgs e)
    {
        go = true;
        this.Invalidate();
    }
}

我认为你可能不得不超越winforms以获得更高的FPS。

答案 1 :(得分:1)

我认为Windows限制了重绘率,因此如果你将FPS提升到疯狂值,那就无所谓了;如果你想看到更高的帧速率,你可能必须得到类似XNA / DirectX动画的东西。

你可以使用一个Timer,然后编写一个既可以移动又可以移动的事件处理程序。使表单无效。为此,您不必执行Thread.Sleep或使用最后一个ticks和interval calcs进行簿记,并且会以常规节奏进行。另外,代替'dir'布尔值周围的条件代码,当你想改变方向时,你可以否定PX值(并且只做加法而不是dir上的三元运算符);这是可能的,因为减法与添加负数相同。

这应该可以让你的动画更容易扩展以做其他事情。为了好玩,你也可以创建一个垂直移动的PY。无论如何,我希望你能玩得开心。 :)

答案 2 :(得分:0)

如果你得到你想要的结果,FPS值为300,那么我会继续这样做。 WinForms的每秒帧数概念与图形密集型视频游戏不同,因此高价值不会成为问题。这里的FPS值只是调整代码执行的频率。

答案 3 :(得分:-1)

超级杀戮解决方案

摘要:制作移动窗口的动画,然后播放(可能是全屏)

<强>详细信息:
假设您的窗口是100x100,并且是@ 0,0
屏幕截图,屏幕显示:(0,0) - (200,200) 使用屏幕截图创建一个剪辑,描绘将窗口从0,0移动到100,100 然后创建一个无边框窗口(0,0) - (200,200),并在其上放置一个视频播放器,并重放移动到其中的窗口的动画。

毋庸置疑,您的窗口将是静态的。但是你可以得到最好的动画。您甚至可以为移动的窗口添加一些效果,例如矩阵中的子弹或Necromunga船。