如何从 table 布局面板 vb.net 获取单元格
How do I get the cell from a table layout panel vb.net
如果用户在单元格中没有控件,我如何获取用户单击的单元格。我真正需要的是当图像被点击时出现在单元格位置而不是在其中。
我想它会类似于这个伪代码
myimage.location = get.cellLocation()
之类的。感谢您的帮助。
问题是没有实际的 "cell" 容器集合。单元格是动态的,基于 ColumnCount
和 RowCount
,以及相应的 ColumnStyles
和 RowStyles
。
如果您的样式使用固定大小,您可以编写自己的方法来计算和存储每个单元格的详细信息——可能在结构或 class 中包含每个单元格的 Rectangle
(将计算位置,并且可以从配对的 ColumnStyle
和 RowStyle
中检索大小)和一个 Point
或 2 int
用于存储列和行。然后,在 TableLayoutPanel
的 MouseClick
事件中,您可以使用 e.Location
并使用 Rectangle.Contains
对照所有单元格矩形检查它。然后,使用 TableLayoutPanel
的 SetCellPosition
方法移动控件。例如:
tableLayoutPanel1.SetCellPosition(pictureBox1, new TableLayoutPanelCellPosition(1, 1));
如果您的任何列或行具有动态大小(百分比等),那么您将需要做更多的工作来计算每个列或行的详细信息。
如果定位可以改变,您将需要重新计算。因此,您需要确保每组计算都在可以从 Resize 事件等调用的方法中完成。
如果你不想经历所有这些疯狂的事情,你可以做一些其他的事情(也许更多,但这些只是我的头脑):
在每个单元格中放入相同的控件类型,例如 PictureBox
。单击其中一个时,将图像设置为源代码管理的图像。单击另一个时,清除前一个,然后设置新的。
通过将任何类型的控件(例如 Label
)放入每个单元格来执行一些控件交换魔术。单击一个时,将其从单元格中删除并将图像控件放入其中。单击另一个时,将其删除,将图像控件放回原处,然后将第一个删除的控件放回原来的单元格中。
我认为第一个选项是最简单的。但是,最终的方法取决于您。
根据您对接受点击的 'chess' 样式 table 的需求,我创建了这个。我不需要它,但我认为这将是一种有趣的消遣。此示例创建 63 个单元格,因此它非常接近您想要的。由于它是即时计算的,您应该能够根据需要对其进行返工。
首先,您的表单将设置一个名为 picBoard
的 PictureBox
(无需计算边距等更容易呈现),另一个名为 picTile
的 PictureBox
,然后一个名为 lblDetails
的 Label
停靠在底部作为状态栏。我的 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
,您还可以将线条设为点线、虚线等
如果用户在单元格中没有控件,我如何获取用户单击的单元格。我真正需要的是当图像被点击时出现在单元格位置而不是在其中。
我想它会类似于这个伪代码
myimage.location = get.cellLocation()
之类的。感谢您的帮助。
问题是没有实际的 "cell" 容器集合。单元格是动态的,基于 ColumnCount
和 RowCount
,以及相应的 ColumnStyles
和 RowStyles
。
如果您的样式使用固定大小,您可以编写自己的方法来计算和存储每个单元格的详细信息——可能在结构或 class 中包含每个单元格的 Rectangle
(将计算位置,并且可以从配对的 ColumnStyle
和 RowStyle
中检索大小)和一个 Point
或 2 int
用于存储列和行。然后,在 TableLayoutPanel
的 MouseClick
事件中,您可以使用 e.Location
并使用 Rectangle.Contains
对照所有单元格矩形检查它。然后,使用 TableLayoutPanel
的 SetCellPosition
方法移动控件。例如:
tableLayoutPanel1.SetCellPosition(pictureBox1, new TableLayoutPanelCellPosition(1, 1));
如果您的任何列或行具有动态大小(百分比等),那么您将需要做更多的工作来计算每个列或行的详细信息。
如果定位可以改变,您将需要重新计算。因此,您需要确保每组计算都在可以从 Resize 事件等调用的方法中完成。
如果你不想经历所有这些疯狂的事情,你可以做一些其他的事情(也许更多,但这些只是我的头脑):
在每个单元格中放入相同的控件类型,例如
PictureBox
。单击其中一个时,将图像设置为源代码管理的图像。单击另一个时,清除前一个,然后设置新的。通过将任何类型的控件(例如
Label
)放入每个单元格来执行一些控件交换魔术。单击一个时,将其从单元格中删除并将图像控件放入其中。单击另一个时,将其删除,将图像控件放回原处,然后将第一个删除的控件放回原来的单元格中。
我认为第一个选项是最简单的。但是,最终的方法取决于您。
根据您对接受点击的 'chess' 样式 table 的需求,我创建了这个。我不需要它,但我认为这将是一种有趣的消遣。此示例创建 63 个单元格,因此它非常接近您想要的。由于它是即时计算的,您应该能够根据需要对其进行返工。
首先,您的表单将设置一个名为 picBoard
的 PictureBox
(无需计算边距等更容易呈现),另一个名为 picTile
的 PictureBox
,然后一个名为 lblDetails
的 Label
停靠在底部作为状态栏。我的 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
,您还可以将线条设为点线、虚线等