【问题标题】:Move Picturebox inside TableLayoutPanel from one cell to the other with delay延迟将 TableLayoutPanel 内的图片框从一个单元格移动到另一个单元格
【发布时间】:2016-02-16 06:50:07
【问题描述】:

我在 Form 中有一个 TableLayoutPanel,并且 TableLayoutPanel 在它的一些单元格中有五个 Picturebox 控件。我想做的是,根据作为参数传递的坐标列表将这些图片框移动到不同的单元格。从用户的角度来看,这些图片框将从一个单元格中消失并重新出现在另一个单元格中。(就像瓷砖基础游戏中的主角消失在一个单元格中并重新出现在相邻的单元格中一样)。 update 方法在 Form 类中,由另一个类的方法调用。问题是,它不显示每个动作。它只显示所有图片框的初始位置,然后是一些刷新,然后是最终位置。在到达最终坐标之前,它应该在每个坐标中显示 PictureBoxes。我试过 Thread.Sleep() 但它不起作用。我该如何解决这个问题?

public partial class CheckerBoard : Form
{
   ....
   ....
   public void update(Position k, List<Position> p)                
   { 

        p1_picturebox.Visible = false;
        p2_picturebox.Visible = false;
        p3_picturebox.Visible = false;
        p4_picturebox.Visible = false;
        p5_picturebox.Visible = false;

        // Load images in new positions            

        this.board.Controls.Add(k_picturebox, k.col, knight.row);
        this.board.Controls.Add(p1_picturebox, p[0].col, p[0].row);
        this.board.Controls.Add(p2_picturebox, p[1].col, p[1].row);
        this.board.Controls.Add(p3_picturebox, p[2].col, p[2].row);
        this.board.Controls.Add(p4_picturebox, p[3].col, p[3].row);
        this.board.Controls.Add(p5_picturebox, p[4].col, p[4].row);  

        ------UPDATED---------
        this.Invalidate();
        Thread.Sleep(3000);

   }
}  

更新 我根据建议修复了我的代码。但是,问题仍然存在。似乎它正在重新绘制整个表格布局面板,而不是将图片框从一个单元格移动到另一个单元格。我可以看到 tablelayoutpanel 的刷新。

    private void replay(State currentState)
    {            
        DispatcherTimer timer = new DispatcherTimer
        {
            Interval = TimeSpan.FromSeconds(0.5)
        };
        timer.Tick += (o, e) =>
        {
            List<Position> pos = new List<Position>();

            foreach(Position p in currentState.pawns)
            {
                pos.Add(p);
            }

            this.update(currentState.knight, pos);
            currentState = currentState.next;
            if (currentState == null)
            {
                timer.IsEnabled = false;
                //this.prepareDisplay();
            }
        };
        timer.IsEnabled = true;


    }


    public void update(Position knight, List<Position> pawns)                
    { 
        // Load images in new positions            
        this.board.Controls.Remove(knight_picturebox);
        this.board.Controls.Add(knight_picturebox, knight.col, knight.row);

        for(int i=0; i < pawns.Count; i++)
        { 
            //this.board.Controls.Add(this.picBoxList[i], pawns[i].col, pawns[i].row);
            this.picBoxList[i].WaitOnLoad = true;
            this.board.Controls.Remove(this.picBoxList[i]);
            this.board.Controls.Add(this.picBoxList[i], pawns[i].col, pawns[i].row);
        }

    }

更新 使用suspendLayout 和reproveLayout,改进了重绘。但我想知道是否可以不重绘表格布局而只重绘图片框,这样看起来只有图片框在移动。

【问题讨论】:

  • 你的目标是什么:Winforms? WPF? ASP? ...?? 总是相应地标记您的问题! - 而不是 Thread.Sleep 你应该使用 Timer 在 winforms 中做动画。
  • 在 GUI 程序中调用 Sleep() 是一个非常糟糕的主意,您永远不希望响应用户输入并保持窗口更新的线程进入紧张状态。您可以在睡觉前致电this.Update(); 取得成功。但是接下来需要学习如何使用 Timer。然后了解“游戏循环”是什么样的。
  • @TaW 这是 Winform。我更新了标签。
  • @Hans Passant :我在调用 update 后尝试睡眠,但结果完全相同。我会看看计时器。
  • 不幸的是,时间不起作用。我不确定我在哪里做错了

标签: c# winforms picturebox tablelayoutpanel


【解决方案1】:

我希望这有效。假设您已将图片框名称的临时列表放入 List 中,您可以从中检索名称并找到它们以移动到另一个位置。因此,基本上在我的方法中,您只需将它们的位置转移到表格布局面板中的另一个单元格。 您可以通过使用“foreach”循环来检索图片框而不是为图片框的每个 control.name 迭代相同的 Controls.Find() 函数来优化它。

public void update(Position k, List<Position> p)
    {
        PictureBox p1 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
        PictureBox p2 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
        PictureBox p3 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
        PictureBox p4 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
        PictureBox p5 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
        this.board.Controls.Remove(p1);
        this.board.Controls.Remove(p2);
        this.board.Controls.Remove(p3);
        this.board.Controls.Remove(p4);
        this.board.Controls.Remove(p5);

        //p1_picturebox.Visible = false;
        //p2_picturebox.Visible = false;
        //p3_picturebox.Visible = false;
        //p4_picturebox.Visible = false;
        //p5_picturebox.Visible = false;

        // Load images in new positions            

        //this.board.Controls.Add(k_picturebox, k.col, knight.row);
        this.board.Controls.Add(p1, p[0].col, p[0].row);
        this.board.Controls.Add(p2, p[1].col, p[1].row);
        this.board.Controls.Add(p3, p[2].col, p[2].row);
        this.board.Controls.Add(p4, p[3].col, p[3].row);
        this.board.Controls.Add(p5, p[4].col, p[4].row);

        //alternatively for the whole above code you may optimize like below.
        int i = 0;
        foreach(Control c in PictureBoxList)    //PictureBoxList is retrieved as List<Control>
        {
            PictureBox p1 = this.Controls.Find(c.Name, true).FirstOrDefault() as PictureBox;
            p1.Name = c.Name;   //assign new name from the same list which contains pictureboxes and can get name by using c.Name
            this.board.Controls.Remove(p1);
            this.board.Controls.Add(p1, p[i].col, p[i].row);
            i++;
        }


        ------UPDATED-------- -
        this.Invalidate();
        Thread.Sleep(3000);

    }

更新:

您是否尝试将 Picturebox 的 WaitOnLoad 属性设置为 true

更新2:

尝试使 board 无效,然后尤其是 new pictureBoxes

【讨论】:

  • 我做了,但没有解决问题。你可以在我更新的代码中看到它。
  • 您要更新整个表格布局吗?我的意思是除了您需要移动的控件之外,表格布局中还有其他控件吗??
猜你喜欢
  • 1970-01-01
  • 2018-04-22
  • 2018-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多