C#动画冻结程序

时间:2015-07-28 04:58:29

标签: c# winforms animation

由于某种原因,这冻结了程序:

private void Form1_Shown(object sender, EventArgs e)
{
    int x = 1;
    var frame1 = pictureBox2.BackgroundImage;
    var frame2 = pictureBox3.BackgroundImage;
    while(x < 2)
    {
        pictureBox1.BackgroundImage = frame1;
        pictureBox1.BackgroundImage = frame2;
    }
}

为什么?
pictureBox2包含第一帧,pictureBox3包含第二帧 pictureBox1包含'动画'。 (如代码所示)

编辑:我不希望它为 ONCE 制作动画,我希望它能为 FOREVER设置动画。

5 个答案:

答案 0 :(得分:2)

这是单程......

使用async标记您的已显示()事件,然后在帧之间使用await Task.Delay()

    private async void Form1_Shown(object sender, EventArgs e)
    {
        bool first = true;
        var frame1 = pictureBox2.BackgroundImage;
        var frame2 = pictureBox3.BackgroundImage;
        while (true)
        {
            pictureBox1.BackgroundImage = first ? frame1 : frame2;
            first = !first;
            await Task.Delay(500); // 1/2 second delay <-- set it to your desired delay between frames
        }
    }

----------编辑----------

使用Timer和IEnumerator的替代方法。如果你有两个以上的框架,这将是一个很好的方法:

    private IEnumerator<Image> frames;
    private System.Windows.Forms.Timer tmr;

    private void Form1_Shown(object sender, EventArgs e)
    {
        List<Image> lstFrames = new List<Image>();
        lstFrames.Add(pictureBox2.BackgroundImage);
        lstFrames.Add(pictureBox3.BackgroundImage);
        lstFrames.Add(pictureBox4.BackgroundImage);
        // etc...
        frames = lstFrames.GetEnumerator();
        DisplayNextFrame();

        tmr = new System.Windows.Forms.Timer();
        tmr.Interval = 500;
        tmr.Tick += Tmr_Tick;
        tmr.Start();
    }

    private void Tmr_Tick(object sender, EventArgs e)
    {
        DisplayNextFrame();
    }

    private void DisplayNextFrame()
    {
        if (!frames.MoveNext())
        {
            frames.Reset();
            frames.MoveNext();
        }
        pictureBox1.BackgroundImage = frames.Current;
    }

答案 1 :(得分:1)

在您的情况下,x的值始终为1,这就是while循环继续迭代并且程序进入无限循环的原因。

解决方案:

您应该使用BackgroundWorker将代码作为Asynchronous

运行

在表单中插入新的BackgroundWorker

将您的函数插入DoWork事件。

private void bWorker1_DoWork(object sender, DoWorkEventArgs e)  
{  
    var frame1;
    var frame2;

    if (pictureBox2.InvokeRequired) { pictureBox2.Invoke((MethodInvoker)delegate { frame1 = pictureBox2.BackgroundImage; }); } else { frame1 = pictureBox2.BackgroundImage; }
    if (pictureBox3.InvokeRequired) { pictureBox3.Invoke((MethodInvoker)delegate { frame2 = pictureBox3.BackgroundImage; }); } else { frame2 = pictureBox3.BackgroundImage; }

    while (true)
    {
        if (pictureBox1.InvokeRequired) { pictureBox1.Invoke((MethodInvoker)delegate { pictureBox1.BackgroundImage = frame1; }); } else { pictureBox1.BackgroundImage = frame1; }
        if (pictureBox1.InvokeRequired) { pictureBox1.Invoke((MethodInvoker)delegate { pictureBox1.BackgroundImage = frame2; }); } else { pictureBox1.BackgroundImage = frame2; }
    }
}

现在,开始运行BackgroundWorker

bWorker1.RunWorkerAsync();

答案 2 :(得分:0)

为您的animiation创建一个并行线程:

private void Form1_Shown(object sender, EventArgs e)
{
    //create parallel thread
    Thread animationThread = new Thread(Animation);
    animationThread.Start();
}

//create a new method for animation to run on a parallel thread
private void Animation()
{
    int x = 1;
    var frame1 = pictureBox1.Image;
    var frame2 = pictureBox2.Image;
    while (x < 2)
    {
        this.Invoke(new Action(() => pictureBox3.Image = frame1));
        this.Invoke(new Action(() => pictureBox3.Refresh()));
        Thread.Sleep(100); //you must keep a dealy other wise it will consume too much processing
        this.Invoke(new Action(() =>  pictureBox3.Image = frame2));
        this.Invoke(new Action(() => pictureBox3.Refresh()));
    }
}

答案 3 :(得分:0)

你的循环永远运行,永远不会终止。

while (x < 2)循环没有终止条款,因此你的程序会冻结; x总是小于2.如果您不允许应用程序呼吸,它就会冻结。试试这个:

private void Form1_Shown(object sender, EventArgs e)
{
    var frame1 = pictureBox2.BackgroundImage;
    var frame2 = pictureBox3.BackgroundImage;
    while(true)
    {
        pictureBox1.BackgroundImage = frame1;
        Application.DoEvents(); // give the thread room to run background tasks

        pictureBox1.BackgroundImage = frame2;
        Application.DoEvents(); // give the thread room to run background tasks
    }
}

DoEvents()只是一个选项,可能不是最适合您的情况。你可能最好写一个适当的计时器,它可以在两个图像之间切换40毫秒或者你的动画速度。

答案 4 :(得分:0)

我认为你应该在循环中的frame1和frame2之间添加一些时间延迟,以查看动画效果。