动态更改表单项的位置
Changing position of a Form Item Dynamically
我创建了一个表单,其中 'Rectangle' 项目的位置需要动态更改,以便获得 'constant movement' 效果。
我希望黑色矩形在表单的边界内继续移动。我试过这个:
//globally decalred variables
Random locationRandomizer = new Random();
int count = 0;
private void Form1_Load(object sender, EventArgs e)
{
Thread movementThread = new Thread(new ThreadStart(movementFunction));
movementThread.Start();
}
public void movementFunction()
{
try
{
int x;
int y;
int windowHeight = this.Height;
int windowWidth = this.Width;
do
{
x = locationRandomizer.Next(1, windowWidth);
y = locationRandomizer.Next(1, windowWidth);
animalDot.Location = new Point(x, y);
}
while (count == 0);
}
catch (Exception ex)
{
}
}
但是矩形在加载表单时移动一次,之后不会改变。我做错了什么?
当我删除空的 try catch 块时,这是我得到的错误:
跨线程操作无效:控件 'shapeContainer1' 从创建它的线程以外的线程访问。
您可以创建一个从 Rectange 继承并包含在内部计时器实例中的自主 'Moveable' class。当计时器触发时,将 'velocity' 增量添加到该位置。对于碰撞,您可以下降到 'Collidable' class ,当它移动时,它会迭代所有其他 Collidables 的集合,并以碰撞对象作为参数触发 'OnCollision' 事件,所以允许您决定如何处理与墙壁、其他可移动物体等的碰撞
您收到该错误是因为您正在从非 UI 线程访问 UI 元素。您可以通过调用控件上的 Invoke 方法来绕过它,将调用编组回 UI 线程:
textBox1.Invoke((MethodInvoker)(() => textBox1.Location = new Point(x, y)));
定期执行一些影响 UI 的代码的更好方法是使用 System.Windows.Forms.Timer
,这是您可以直接放入设计器中的 Timer
控件。
订阅Tick
事件,运行在UI线程上,避免上述错误
private void timer_Tick(object sender, EventArgs e)
{
var x = locationRandomizer.Next(1, Width - animalDot.Width);
var y = locationRandomizer.Next(1, Height - animalDot.Height);
animalDot.Location = new Point(x, y);
}
然后在构造函数中,您可以将间隔设置为相对较小的值并启用计时器。
timer.Interval = 100;
timer.Enabled = true;
我创建了一个表单,其中 'Rectangle' 项目的位置需要动态更改,以便获得 'constant movement' 效果。
我希望黑色矩形在表单的边界内继续移动。我试过这个:
//globally decalred variables
Random locationRandomizer = new Random();
int count = 0;
private void Form1_Load(object sender, EventArgs e)
{
Thread movementThread = new Thread(new ThreadStart(movementFunction));
movementThread.Start();
}
public void movementFunction()
{
try
{
int x;
int y;
int windowHeight = this.Height;
int windowWidth = this.Width;
do
{
x = locationRandomizer.Next(1, windowWidth);
y = locationRandomizer.Next(1, windowWidth);
animalDot.Location = new Point(x, y);
}
while (count == 0);
}
catch (Exception ex)
{
}
}
但是矩形在加载表单时移动一次,之后不会改变。我做错了什么?
当我删除空的 try catch 块时,这是我得到的错误:
跨线程操作无效:控件 'shapeContainer1' 从创建它的线程以外的线程访问。
您可以创建一个从 Rectange 继承并包含在内部计时器实例中的自主 'Moveable' class。当计时器触发时,将 'velocity' 增量添加到该位置。对于碰撞,您可以下降到 'Collidable' class ,当它移动时,它会迭代所有其他 Collidables 的集合,并以碰撞对象作为参数触发 'OnCollision' 事件,所以允许您决定如何处理与墙壁、其他可移动物体等的碰撞
您收到该错误是因为您正在从非 UI 线程访问 UI 元素。您可以通过调用控件上的 Invoke 方法来绕过它,将调用编组回 UI 线程:
textBox1.Invoke((MethodInvoker)(() => textBox1.Location = new Point(x, y)));
定期执行一些影响 UI 的代码的更好方法是使用 System.Windows.Forms.Timer
,这是您可以直接放入设计器中的 Timer
控件。
订阅Tick
事件,运行在UI线程上,避免上述错误
private void timer_Tick(object sender, EventArgs e)
{
var x = locationRandomizer.Next(1, Width - animalDot.Width);
var y = locationRandomizer.Next(1, Height - animalDot.Height);
animalDot.Location = new Point(x, y);
}
然后在构造函数中,您可以将间隔设置为相对较小的值并启用计时器。
timer.Interval = 100;
timer.Enabled = true;