[英]Dynamically added rows to a TableLayoutPanel are displayed on a different row position
我正在尝试通过单击按钮将 TextBox 动态添加到 TableLayoutPanel。 通过单击鼠标选择行。
在行选择之后,单击按钮会在所选行号上插入一个文本框。
问题是,在不同选择的行上正确显示TextBox 3 或 4 次后,进一步的按钮单击开始在随机行上显示 TextBox,即使在调试时显示了正确的行号。
我需要帮助,这是完整的代码:
public partial class Form1 : Form
{
private TableLayoutPanel _tableLayout;
private int _selectedRow = -1;
public Form1()
{
InitializeComponent();
var button = new Button()
{
Text = "Add Text"
};
button.MouseClick += AddText;
this.Controls.Add(button);
_tableLayout = new TableLayoutPanel()
{
Dock = DockStyle.Fill,
AutoScroll = true,
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink,
CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
};
_tableLayout.MouseClick += SelectRow;
this.Controls.Add(_tableLayout);
}
private void SelectRow(object sender, MouseEventArgs e)
{
_selectedRow = GetRowColIndex(_tableLayout, e.Location).Value.Y;
}
private void AddText(object sender, MouseEventArgs e)
{
_tableLayout.ColumnStyles.Add(new ColumnStyle() { SizeType = SizeType.AutoSize });
_tableLayout.RowStyles.Add(new RowStyle() { SizeType = SizeType.AutoSize });
_tableLayout.Controls.Add(new TextBox(), 0, _selectedRow);
}
Point? GetRowColIndex(TableLayoutPanel tlp, Point point)
{
if (point.X > tlp.Width || point.Y > tlp.Height)
return null;
int w = tlp.Width;
int h = tlp.Height;
int[] widths = tlp.GetColumnWidths();
int i;
for (i = widths.Length - 1; i >= 0 && point.X < w; i--)
w -= widths[i];
int col = i + 1;
int[] heights = tlp.GetRowHeights();
for (i = heights.Length - 1; i >= 0 && point.Y < h; i--)
h -= heights[i];
int row = i + 1;
return new Point(col, row);
}
}
当前代码中缺少某些部分。 它不考虑滚动条和当前 TableLayoutPanel 的 DisplayRectangle。 正如您在 .Net 源代码中看到的, TableLayoutPanel 的 OnPaintBackGround方法已经执行了这些计算,以获取每个单元格的坐标,并使用使用当前单元格的 Bounds 和 ClipBounds 初始化的 TableLayoutCellPaintEventArgs类调用OnPaintCell() 。
您可以在代码中使用相同的逻辑或使用已知的度量,从CellPaint事件中的e.CellBounds
参数检索单击的单元边界。
此处的示例从 TLP 的MouseClick
事件中获取鼠标位置,并使用e.CellBounds.Contains(currentPointerLocation)
的Rectangle.Contains(Point)方法在 Cell 的 Bounds 包含鼠标指针时绘制 Cell 的背景并更新几个带有当前坐标的标签,存储在 2 个字段中,这里是为了简单起见:
Point currentPointerLocation = Point.Empty;
Rectangle currentCellBounds = Rectangle.Empty;
Point currentCell = Point.Empty;
private void tableLayoutPanel1_CellPaint(object sender, TableLayoutCellPaintEventArgs e)
{
if (e.CellBounds.Contains(currentPointerLocation)) {
currentCellBounds = e.CellBounds;
currentCell = new Point(e.Row, e.Column);
e.Graphics.FillRectangle(Brushes.Red, e.CellBounds);
}
else {
using (var brush = new SolidBrush(tableLayoutPanel1.BackColor)) {
e.Graphics.FillRectangle(brush, e.CellBounds);
}
}
}
private void tableLayoutPanel1_MouseClick(object sender, MouseEventArgs e)
{
currentPointerLocation = e.Location;
this.tableLayoutPanel1.Invalidate();
this.tableLayoutPanel1.Update();
lblCurrentCell.Text = currentCell.ToString();
lblCellBounds.Text = currentCellBounds.ToString();
}
使用这些值,可以更轻松地确定当前单元格的坐标并在将控件添加到使用鼠标指针选定的单元格时使用它们。
例如,使用 Button ( btnAddControl
) 和 ContextMenuStrip 将不同的控件添加到 TableLayoutPanel:
private void btnAddControl_Click(object sender, EventArgs e)
{
tableLayoutPanel1.Controls.Add(new TextBox() {
Multiline = true, Text = "TextBox from Button", Dock = DockStyle.Fill }, currentCell.Y, currentCell.X);
}
// Each ToolStripMenuItem sub-item subscribes to the event using this handler
private void contextTLPMenu_Clicked(object sender, EventArgs e)
{
Control ctl = null;
switch ((sender as ToolStripMenuItem).Text)
{
case "TextBox":
ctl = new TextBox() { Multiline = true, Text = "TextBox from ContextMenu" };
break;
case "Button":
ctl = new Button() { Text = "A Button", ForeColor = Color.White };
break;
case "Panel":
ctl = new Panel() { BackColor = Color.LightGreen };
break;
default:
break;
}
if (ctl != null) {
ctl.Dock = DockStyle.Fill;
tableLayoutPanel1.Controls.Add(ctl, currentCell.Y, currentCell.X);
}
}
视觉结果:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.