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();
}
};
}
}