C# 如何使用Thread.Sleep设置二叉树的动画?

C# 如何使用Thread.Sleep设置二叉树的动画?,c#,winforms,animation,binary-tree,C#,Winforms,Animation,Binary Tree,我一直在编写一个程序,该程序可以直观地输出二叉树的内容(由我自己编写的类依次表示)。我想在这个程序中包括的最后一个特性是树的后序、顺序和前序结构的动画 事实证明,这比我想象的更具挑战性。以下是原始的绘制方法: private void DrawNode(int x, int y, BinaryTreeNode<T> node, int nodeLevel, int maxDepth, int connectX = -1, int connectY = -1, ) {

我一直在编写一个程序,该程序可以直观地输出二叉树的内容(由我自己编写的类依次表示)。我想在这个程序中包括的最后一个特性是树的后序、顺序和前序结构的动画

事实证明,这比我想象的更具挑战性。以下是原始的绘制方法:

private void DrawNode(int x, int y, BinaryTreeNode<T> node, int nodeLevel, int maxDepth, int connectX = -1, int connectY = -1, )
    {
        //calculate distance between the node's children
        int distance = CalculateDistance(nodeLevel, maxDepth);

        //draw the node at the specified coordinate
        node.Draw(x, y, this.device);

        if (node.Left != null)
        {
            DrawNode(x - distance / 2, y + 50, node.Left, nodeLevel + 1, maxDepth, x, y, node);
        }
        if (node.Right != null)
        {
            DrawNode(x + distance / 2, y + 50, node.Right, nodeLevel + 1, maxDepth, x, y, node);
        }

        //connect the node to its parent
        if ((connectX != -1) && (connectY != -1))
        {
            node.Connect(connectX, connectY, device);
        }

        this.display.Image = surface;
    }

一种可能的解决方案是生成一个单独的线程,然后使用该线程定期调用DrawNode函数。这样就不会阻塞UI线程

由于生成的线程不是UI线程,因此需要在UI线程上显式调用DrawNode函数。这里有一种可能的方法:


一种可能的解决方案是生成一个单独的线程,然后使用该线程定期调用DrawNode函数。这样就不会阻塞UI线程

由于生成的线程不是UI线程,因此需要在UI线程上显式调用DrawNode函数。这里有一种可能的方法:


使用计时器并设置适当的更新间隔。在
勾选事件中,执行绘图的下一步并显示。

使用计时器并设置适当的更新间隔。在
勾选
事件中,执行绘图的下一步并显示它。

首先,编写一个
DrawNodesForLevel(int level)
函数。然后从顶层开始,启动计时器,每次它滴答作响时,使用适当的级别调用
DrawNodesForLevel()
,并递增该级别。当你到达终点时,停止计时器

编辑:更新时,您需要在每个节点之间暂停,而不是在每个级别之间暂停

将函数中的变量移动到它们自己的
drawNodeEstate
类,并在调用DrawNode()时传递该类的实例。然后,让DrawNode()启动计时器(也是
DrawNodeEstate
类的一部分),而不是让DrawNode()调用自身。当计时器计时时,tick函数调用DrawNode()并将状态结构传递给它


状态结构还必须跟踪它最后绘制的是左节点还是右节点,以便下一步可以绘制适当的节点。

首先,编写一个
DrawNodesForLevel(int-level)
函数。然后从顶层开始,启动计时器,每次它滴答作响时,使用适当的级别调用
DrawNodesForLevel()
,并递增该级别。当你到达终点时,停止计时器

编辑:更新时,您需要在每个节点之间暂停,而不是在每个级别之间暂停

将函数中的变量移动到它们自己的
drawNodeEstate
类,并在调用DrawNode()时传递该类的实例。然后,让DrawNode()启动计时器(也是
DrawNodeEstate
类的一部分),而不是让DrawNode()调用自身。当计时器计时时,tick函数调用DrawNode()并将状态结构传递给它


状态结构还必须跟踪它最后绘制的是左节点还是右节点,以便下一步可以绘制相应的节点。

将代码分成两部分-一部分遍历树,另一部分渲染(已经绘制)

将“遍历树”代码重写为
IEnumerable
,以便可以逐个拾取节点。对于任何顺序,都有非递归的树遍历验证,所以您可以使用“yield return”来生成迭代器。您应该能够创建简单的测试来验证代码(不需要UI)


而在计时器回调中,只需从迭代器中提取下一项,直到全部完成。

将代码分成两部分-一部分遍历树,另一部分呈现(您已经有了)

将“遍历树”代码重写为
IEnumerable
,以便可以逐个拾取节点。对于任何顺序,都有非递归的树遍历验证,所以您可以使用“yield return”来生成迭代器。您应该能够创建简单的测试来验证代码(不需要UI)


在计时器回调中,只需从迭代器中获取下一项,直到全部完成。

您需要使用计时器。你遇到了什么问题?你也可以在C#5中使用
等待任务。延迟(…)
计时器不工作,因为我需要对动画进行后期处理,而且我找不到一种方法使其与计时器一起工作(我有两个计时器)。以下是代码,如果您能找到一种方法使其工作:):编辑:字符限制阻止我将代码放在此处,我将其放在原始帖子中。您使用的是.Net 4.0还是4.5?我打开了Visual Studio 11,似乎找不到此任务。延迟方法。。我包括System.Threading.Tasks,并编写了您提到的代码行。编辑:我用4.0编程,但我可以很容易地切换到4.5。你需要使用定时器。你遇到了什么问题?你也可以在C#5中使用
等待任务。延迟(…)
计时器不工作,因为我需要对动画进行后期处理,而且我找不到一种方法使其与计时器一起工作(我有两个计时器)。以下是代码,如果您能找到一种方法使其工作:):编辑:字符限制阻止我将代码放在此处,我将其放在原始帖子中。您使用的是.Net 4.0还是4.5?我打开了Visual Studio 11,似乎找不到此任务。延迟方法。。我包括System.Threading.Tasks,并编写了您提到的代码行。编辑:我在4.0中编程,但我可以很容易地切换到4.5..1个计时器是为这一点构建的,您不必担心跨线程问题,因为
勾选
事件在UI线程上运行(假设生成图像所需的时间不太长,并且在UI线程上运行也可以)。为此构建了一个计时器,您不必担心跨线程问题,因为
勾选
事件在UI线程上运行(假设时间为
//draw the node's children
        if (drawChildren)
        {
            if (node.Left != null)
            {
                if (this.timer2.Enabled)
                {
                    this.timer2.Stop();
                }
                if (!this.timer1.Enabled)
                {
                    this.timer1.Start();
                }
                this.count1++;
                this.timer1.Tick += (object source, EventArgs e) =>
                {
                    this.count1--;
                    DrawNode(x - distance / 2, y + 50, node.Left, nodeLevel + 1, maxDepth, x, y, node);
                    if (this.count1 == 0)
                    {
                        this.timer1.Stop();
                    }
                };
            }
            else
            {
                this.timer1.Stop();
                this.timer2.Start();
            }
            if (node.Right != null)
            {
                this.count2++;
                this.timer2.Tick += (object source, EventArgs e) =>
                {
                    this.count2--;
                    DrawNode(x + distance / 2, y + 50, node.Right, nodeLevel + 1, maxDepth, x, y, node);
                    if (this.count2 == 0)
                    {
                        this.timer2.Stop();
                    }
                };
            }
        }