如何从 table 布局面板 vb.net 获取单元格

How do I get the cell from a table layout panel vb.net

如果用户在单元格中没有控件,我如何获取用户单击的单元格。我真正需要的是当图像被点击时出现在单元格位置而不是在其中。

我想它会类似于这个伪代码

myimage.location = get.cellLocation()

之类的。感谢您的帮助。

问题是没有实际的 "cell" 容器集合。单元格是动态的,基于 ColumnCountRowCount,以及相应的 ColumnStylesRowStyles

如果您的样式使用固定大小,您可以编写自己的方法来计算和存储每个单元格的详细信息——可能在结构或 class 中包含每个单元格的 Rectangle (将计算位置,并且可以从配对的 ColumnStyleRowStyle 中检索大小)和一个 Point 或 2 int 用于存储列和行。然后,在 TableLayoutPanelMouseClick 事件中,您可以使用 e.Location 并使用 Rectangle.Contains 对照所有单元格矩形检查它。然后,使用 TableLayoutPanelSetCellPosition 方法移动控件。例如:

tableLayoutPanel1.SetCellPosition(pictureBox1, new TableLayoutPanelCellPosition(1, 1));

如果您的任何列或行具有动态大小(百分比等),那么您将需要做更多的工作来计算每个列或行的详细信息。

如果定位可以改变,您将需要重新计算。因此,您需要确保每组计算都在可以从 Resize 事件等调用的方法中完成。

如果你不想经历所有这些疯狂的事情,你可以做一些其他的事情(也许更多,但这些只是我的头脑):

  1. 在每个单元格中放入相同的控件类型,例如 PictureBox。单击其中一个时,将图像设置为源代码管理的图像。单击另一个时,清除前一个,然后设置新的。

  2. 通过将任何类型的控件(例如 Label)放入每个单元格来执行一些控件交换魔术。单击一个时,将其从单元格中删除并将图像控件放入其中。单击另一个时,将其删除,将图像控件放回原处,然后将第一个删除的控件放回原来的单元格中。

我认为第一个选项是最简单的。但是,最终的方法取决于您。

根据您对接受点击的 'chess' 样式 table 的需求,我创建了这个。我不需要它,但我认为这将是一种有趣的消遣。此示例创建 63 个单元格,因此它非常接近您想要的。由于它是即时计算的,您应该能够根据需要对其进行返工。

首先,您的表单将设置一个名为 picBoardPictureBox(无需计算边距等更容易呈现),另一个名为 picTilePictureBox,然后一个名为 lblDetailsLabel 停靠在底部作为状态栏。我的 InitializeComponent 看起来像这样:

  private void InitializeComponent()
  {
     this.picBoard = new System.Windows.Forms.PictureBox();
     this.picTile = new System.Windows.Forms.PictureBox();
     this.lblDetails = new System.Windows.Forms.Label();
     ((System.ComponentModel.ISupportInitialize)(this.picBoard)).BeginInit();
     ((System.ComponentModel.ISupportInitialize)(this.picTile)).BeginInit();
     this.SuspendLayout();
     // 
     // picBoard
     // 
     this.picBoard.Location = new System.Drawing.Point(12, 21);
     this.picBoard.Name = "picBoard";
     this.picBoard.Size = new System.Drawing.Size(360, 280);
     this.picBoard.TabIndex = 0;
     this.picBoard.TabStop = false;
     // 
     // picTile
     // 
     this.picTile.BackColor = System.Drawing.Color.Red;
     this.picTile.Location = new System.Drawing.Point(143, 67);
     this.picTile.Name = "picTile";
     this.picTile.Size = new System.Drawing.Size(51, 51);
     this.picTile.TabIndex = 1;
     this.picTile.TabStop = false;
     this.picTile.Visible = false;
     // 
     // lblDetails
     // 
     this.lblDetails.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
     this.lblDetails.Dock = System.Windows.Forms.DockStyle.Bottom;
     this.lblDetails.Location = new System.Drawing.Point(0, 326);
     this.lblDetails.Name = "lblDetails";
     this.lblDetails.Size = new System.Drawing.Size(393, 23);
     this.lblDetails.TabIndex = 2;
     this.lblDetails.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
     // 
     // Form1
     // 
     this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
     this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
     this.ClientSize = new System.Drawing.Size(393, 349);
     this.Controls.Add(this.lblDetails);
     this.Controls.Add(this.picTile);
     this.Controls.Add(this.picBoard);
     this.Name = "Form1";
     this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
     this.Text = "Grid Test";
     ((System.ComponentModel.ISupportInitialize)(this.picBoard)).EndInit();
     ((System.ComponentModel.ISupportInitialize)(this.picTile)).EndInit();
     this.ResumeLayout(false);

  }

这是完整的 Form 代码,以及底部的自定义 class、CellDetails(我不想单独制作一个) .请记住,这只是我匆忙创建的东西,看看它对你来说有多难。如果您对发生的事情有任何疑问,请提问。

   public partial class Form1 : Form
   {

      List<CellDetails> cells = new List<CellDetails>();
      // Defines the size of each cell.
      const int cCellSize = 40;
      int boardLeft = 0;
      int boardTop = 0;
      public Form1()
      {
         InitializeComponent();

         picTile.Size = new Size(cCellSize, cCellSize);

         picBoard.MouseMove += PicBoard_MouseMove;
         picBoard.MouseClick += PicBoard_MouseClick;
         picBoard.Paint += PicBoard_Paint;
         CreateCells();

         boardLeft = picBoard.Location.X;
         boardTop = picBoard.Location.Y;
      }

      private void PicBoard_Paint(object sender, PaintEventArgs e)
      {
         if (cells.Count > 0)
         {
            bool alt = false;
            SolidBrush cellBrush1 = new SolidBrush(Color.LightGray);
            SolidBrush cellBrush2 = new SolidBrush(Color.DarkGray);

            foreach (CellDetails cell in cells)
            {
               e.Graphics.FillRectangle((alt ? cellBrush1 : cellBrush2), cell.Dimension);
               alt = !alt;
            }

            cellBrush1.Dispose();
            cellBrush2.Dispose();
         }
      }

      private void PicBoard_MouseClick(object sender, MouseEventArgs e)
      {
         CellDetails cell = FindCell(e);
         if (cell != null && cell.Location.X > -1 && cell.Location.Y > -1)
         {
            picTile.Location = new Point(cell.Dimension.X + boardLeft, cell.Dimension.Y + boardTop);
            picTile.Visible = true;
         }
         else
         {
            picTile.Visible = false;
         }
      }

      private void PicBoard_MouseMove(object sender, MouseEventArgs e)
      {
         CellDetails cell = FindCell(e);
         string details;

         if (cell == null || cell.Location.X < 0 || cell.Location.Y < 0)
         {
            details = "Could not find cell";
         } else
         {
            details = string.Format("Row: {0}, Col: {1}", cell.Location.Y, cell.Location.X);
         }
         lblDetails.Text = String.Format("{0}, {1} = {2}", e.X, e.Y, details);
      }

      private CellDetails FindCell(MouseEventArgs e)
      {
         CellDetails ret = null;
         foreach (CellDetails cell in cells)
         {
            if (cell.Dimension.Contains(e.Location))
            {
               ret = cell;
               break;
            }
         }
         return ret;
      }

      private void CreateCells()
      {
         CellDetails cell;
         Point cellLoc;
         int rows = (picBoard.ClientSize.Height / cCellSize);
         int cols = (picBoard.ClientSize.Width / cCellSize);

         // Loop through the rows
         for (int row = 0; row < rows; row++)
         {
            // Loop through the columns
            for (int col = 0; col < cols; col++)
            {
               cell = new CellDetails();
               cellLoc = new Point();
               cellLoc.Y = row + 1; 
               cellLoc.X = col + 1; 
               cell.Location = cellLoc;
               cell.Dimension = new Rectangle(col * cCellSize, row * cCellSize, cCellSize, cCellSize);
               cells.Add(cell);
            }
         }
         lblDetails.Text = String.Format("Generated {0} cells.", cells.Count);
      }

   }
   public class CellDetails
   {
      public CellDetails() { }
      public Rectangle Dimension { get; set; }
      public Point Location { get; set; }
   }

最终结果如下所示:

如果您知道所需的行数和列数,则可以通过将 ClientSize 除以计数而不是预定义的单元格大小来计算单元格 width/height。如果您可以调整大小,这也会有所帮助,这会导致单元格大小发生变化。只需更改代码以这种方式计算,然后让它在调整大小后调用 CreateCells。您可能还想在顶部添加一行 if (cells.Count > 0) cells.Clear();

它可能不需要提及,但万一有人出现:如果您只需要对不可见单元格进行命中测试(无渲染),您可以完全删除 Paint 事件。如果您想要网格线而不是填充框,请将 FilledRectangle 更改为 DrawRectangle,并使用 Pen 而不是 SolidBrush。使用 Pen,您还可以将线条设为点线、虚线等