动态更改表单项的位置

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;