【发布时间】:2015-04-21 03:43:10
【问题描述】:
我正在尝试用 C# 制作一个简单的项目,但是由于我是新手,所以遇到了很多麻烦。 我想做的是模拟苍蝇在一个圆圈内的运动。 它应该与鼠标点击一起工作——第一次点击,你选择了一个圆的中心。第二次单击,您选择了圆的半径并绘制它。在第三次单击时(在圆圈内),您应该画一只苍蝇(我们现在将其设为一个小的填充椭圆),它应该立即开始四处移动。
我已经尝试完成这项工作一个多星期了,但几乎没有任何结果。
我使用面板作为画布。
这是我目前所拥有的:
private int start_x = 0;
private int start_y = 0;
private int end_x = 0;
private int end_y = 0;
private int fly_x = 0;
private int fly_y = 0;
private int clicks = 0;
private int distance = 0;
public Form1()
{
InitializeComponent();
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
clicks++;
if (clicks == 1)
{
start_x = e.X;
start_y = e.Y;
}
else if (clicks == 2)
{
end_x = e.X;
end_y = e.Y;
}
else if (clicks == 3)
{
fly_x = e.X;
fly_y = e.Y;
}
else if (clicks == 4)
{
}
this.panel1.Refresh();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
Random r = new Random();
Thread t = new Thread(new ThreadStart(Fly));
if (clicks == 1)
{
e.Graphics.DrawEllipse(Pens.Black, start_x - 2, start_y - 2, 4, 4);
}
else if (clicks == 2)
{
distance = Distance(start_x, start_y, end_x, end_y);
e.Graphics.DrawEllipse(Pens.Black, start_x - 2, start_y - 2, 4, 4);
e.Graphics.DrawEllipse(Pens.Black, start_x - distance, start_y - distance, distance * 2, distance * 2);
}
else if (clicks == 3)
{
t.Start();
}
else if (clicks == 4)
{
t.Abort();
clicks = 0;
}
}
private int Distance(int a_x, int a_y, int b_x, int b_y)
{
int a, b;
a = a_x - b_x;
b = a_y - b_y;
return (Convert.ToInt32(Math.Sqrt(a * a + b * b)));
}
private void Fly()
{
Random r = new Random();
Graphics e = CreateGraphics();
distance = Distance(start_x, start_y, end_x, end_y);
while (clicks < 4)
{
e.DrawEllipse(Pens.Black, start_x - 2, start_y - 2, 4, 4);
e.DrawEllipse(Pens.Black, start_x - distance, start_y - distance, distance * 2, distance * 2);
e.FillEllipse(Brushes.Red, fly_x - 3, fly_y - 3, 6, 6);
fly_x = fly_x - 5 + r.Next(1, 11);
fly_y = fly_y - 5 + r.Next(1, 11);
Invalidate();
if (Distance(start_x, start_y, fly_x, fly_y) > distance - 1)
{
if (fly_x < start_x)
{
fly_x = fly_x + 5;
}
else
{
fly_x = fly_x - 5;
}
if (fly_y < start_y)
{
fly_y = fly_y + 5;
}
else
{
fly_y = fly_y - 5;
}
}
}
}
但是,显然,它根本不起作用。我可以画圆圈,但是一旦我再次点击面板,圆圈就会消失。你能指出我正确的方向吗?我的意思是,我做错了什么? 我试图在不使用线程的情况下做到这一点,甚至可以画出苍蝇,但在那一刻,整个事情都冻结了。 编辑: 我删除了线程并放了一个计时器:
private void panel1_Paint(object sender, PaintEventArgs e)
{
Random r = new Random();
this.DoubleBuffered = true;
if (clicks == 1)
{
e.Graphics.DrawEllipse(Pens.Black, start_x - 2, start_y - 2, 4, 4);
}
else if (clicks == 2)
{
distance = Distance(start_x, start_y, end_x, end_y);
e.Graphics.DrawEllipse(Pens.Black, start_x - 2, start_y - 2, 4, 4);
e.Graphics.DrawEllipse(Pens.Black, start_x - distance, start_y - distance, distance * 2, distance * 2);
}
else if (clicks == 3)
{
e.Graphics.DrawEllipse(Pens.Black, start_x - 2, start_y - 2, 4, 4);
e.Graphics.DrawEllipse(Pens.Black, start_x - distance, start_y - distance, distance * 2, distance * 2);
e.Graphics.FillEllipse(Brushes.Red, fly_x - 3, fly_y - 3, 6, 6);
}
else if (clicks == 4)
{
clicks = 0;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
Random r = new Random();
fly_x = fly_x - 5 + r.Next(1, 11);
fly_y = fly_y - 5 + r.Next(1, 11);
if (Distance(start_x, start_y, fly_x, fly_y) > distance - 1)
{
if (fly_x < start_x)
{
fly_x = fly_x + 5;
}
else
{
fly_x = fly_x - 5;
}
if (fly_y < start_y)
{
fly_y = fly_y + 5;
}
else
{
fly_y = fly_y - 5;
}
}
panel1.Invalidate();
}
现在它可以工作了,但图像仍然闪烁很多,即使我使用了双缓冲。我从我的同事那里得到了一个解决方案,不知何故,他的任何方式都没有闪烁。除了双缓冲还有其他方法可以解决这个问题吗?
【问题讨论】:
-
你不需要线程你需要一个计时器。
-
您可以使用计时器,或者您可以在 Paint 方法的末尾调用 panel.Invalidate() 以确保它不断被重绘。我还建议您使用自定义控件而不是面板。这将允许您在构造函数中启用 OptimizedDoubleBuffer 样式。没有它,您会看到一些难看的闪烁,因为 Windows 在每次调用 Paint 之前都会使用背景颜色擦除您的绘图。
-
我确实尝试使用计时器,但它没有做任何事情。然而,很有可能是我用错了。使用定时器有什么需要注意的吗?
-
您的计时器应该在每个滴答声中调用 panel.Invalidate()。此外,请确保您已通过设置 Enabled = true 或调用 Start() 方法来启动计时器。我建议滴答间隔不超过 50 毫秒。
-
只需在 Paint 结束时调用 panel.Invalidate() 不,这将导致循环&crash|freeze!使用计时器并将 Intervall (ms) 设置为您想要的速度。将随机变量移动到类级别也是一个好习惯。