用C#动画

时间:2013-12-11 15:36:12

标签: c# image

我需要编写一个代码,在单击按钮后将picture1移动到屏幕顶部。在pictire1到达前20个像素之后,屏幕必须变得不可见并使picture2可见。这是我的错误代码:

private void button1_Click(object sender, EventArgs e)
{
    int b = pictureBox1.Top;

    for (int i = b; i < 20; i--)
    {
        pictureBox1.Top = i;
        System.Threading.Thread.Sleep(20);
    }

    if (pictureBox1.Top < 20)
    {
        pictureBox1.Visible = false;
        pictureBox2.Visible = true;
    }
}

任何想法如何解决?

3 个答案:

答案 0 :(得分:3)

这似乎不对:

for (int i = b; i < 20; i--)
{
    pictureBox1.Top = i;
    System.Threading.Thread.Sleep(20);
}

这会在i < 20时循环。但是,从您的代码中可以看出,如果达到Top == 20,则您希望显示另一张图片。所以我想那应该是i >= 20if应该是Top <= 20

此外,您没有刷新显示器。由于循环和Sleep,将不会有UI更新。

像Cobra_Fast在Sleep

之前建议的那样添加它
this.Invalidate();
this.Refresh();

总结一下,以下内容应该可行(我还稍微修改了代码以使其更清晰):

private void button1_Click(object sender, EventArgs e)
{
    while (pictureBox1.Top >= 20)
    {
        pictureBox1.Top = pictureBox1.Top - 1;
        this.Invalidate();
        this.Refresh();
        System.Threading.Thread.Sleep(20);
    }

    // Here you KNOW that the picture box is at y-position 20, so there's not need
    // for the IF
    pictureBox1.Visible = false;
    pictureBox2.Visible = true;
}

上述代码的问题在于它阻止了UI。为了保持响应,我将按如下方式使用计时器:

private void button1_Click(object sender, EventArgs e)
{    
    // Create a threaded timer
    System.Timers.Timer animationTimer = new System.Timers.Timer();
    animationTimer.Interval = 20;
    animationTimer.AutoReset = false; // Only one Ping! We'll activate it if necessary
    animationTimer.Elapsed += new ElapsedEventHandler(AnimationStep);
    animationTimer.Start();

    // Disable the button also, because we don't want another timer instance to
    // interfere with our running animation
    button1.Enabled = false;
}

然后,创建计时器触发时调用的事件:

private void AnimationStep(object source, ElapsedEventArgs e)
{
    // The following code needs to be executed in the context of the UI thread.
    // We need to use this.Invoke in Forms or this.Dispatcher.Invoke in WPF
    this.Invoke((Action)delegate()
    {
        // Move picture. Note that we don't need to update the display here
        // because the UI thread gets time to do its work while the timer waits
        // to fire below
        if (pictureBox1.Top > 20)
            pictureBox1.Top--;

        // Show other picture maybe. I use <= here because initially, the
        // position of the picture box may already smaller than 20.
        if (pictureBox1.Top <= 20)
        {
            pictureBox1.Visible = false;
            pictureBox2.Visible = true;
        }

        // Or let the timer fire again if we still need to animate
        else
        {
            (source as System.Timers.Timer).Start();
        }
    }
}

其工作原理如下:创建一个在20ms后触发一次的计时器。然后它将图片向上移动一个像素,然后如果动画完成则显示另一个图片,或者再次启动计时器以将图片向上移动另一个像素。

这可以保持用户界面的响应速度,并且仍然允许您为图片制作动画。缺点是,动画可能不像你想要的那样平滑,以防你的窗户被移动或者其他“工作”需要由UI线程完成。

答案 1 :(得分:1)

如果最初b大于20,该怎么办?循环不会运行,因为循环中的条件是i < 20。因为循环没有运行,所以不会发生任何事情。

考虑改变循环中的条件。您可能希望图片向上移动,因为您正在减少Top - 属性。让我们说最初的pictureBox1的顶部是40.下面的代码将起作用:

while(pictureBox1.Top >= 20)
{
    pictureBox1.Top--;
    System.Threading.Thread.Sleep(20);
    Invalidate();
    Refresh();
}

由于Top现在小于20,因此可以省略if语句,只需调用:

pictureBox1.Visible = false;
pictureBox2.Visible = true;

完整代码:

while(pictureBox1.Top >= 20)
{
    pictureBox1.Top--;
    System.Threading.Thread.Sleep(20);
    Invalidate();
    Refresh();
}

pictureBox1.Visible = false;
pictureBox2.Visible = true;

答案 2 :(得分:0)

pictureBox1.Top分配后,请致电:

this.Invalidate();
this.Refresh();

假设您正在使用WinForms。