我需要编写一个代码,在单击按钮后将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;
}
}
任何想法如何解决?
答案 0 :(得分:3)
这似乎不对:
for (int i = b; i < 20; i--)
{
pictureBox1.Top = i;
System.Threading.Thread.Sleep(20);
}
这会在i < 20
时循环。但是,从您的代码中可以看出,如果达到Top == 20
,则您希望显示另一张图片。所以我想那应该是i >= 20
而if
应该是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。