将行动态添加到TableLayoutPanel会在不同的行号(位置)上显示

问题描述 投票:0回答:1

我正在尝试通过单击按钮将TextBox动态添加到TableLayoutPanel。通过单击鼠标选择一行。在选择行之后,单击按钮会在所选行号上插入TextBox。 问题是在不同选择的行上正确地[文本框3或4次后,单击以下按钮将开始在随机行上显示文本框,即使调试显示正确的行号也是如此。需要帮助请,这里是完整的代码:

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); } }
winforms dynamic position row tablelayoutpanel
1个回答
0
投票
当前代码中缺少某些部分。它不考虑滚动条和当前TableLayoutPanel的DisplayRectangle。如您在.Net源代码中所看到的,TableLayoutPanel's OnPaintBackGround方法已经执行了这些计算,以获取每个单元格的坐标,并调用使用当前单元格的Bounds和ClipBounds初始化的OnPaintCell() with a TableLayoutCellPaintEventArgs类。

您可以在代码中使用相同的逻辑,也可以使用已知的方法,从e.CellBounds事件中的

CellPaint参数检索单击的单元格边界。

这里的例子,从TLP的MouseClick事件中获取鼠标位置,并使用

Rectangle.Contains(Point)

中的e.CellBounds.Contains(currentPointerLocation)方法在单元格的边界包含鼠标指针并更新几个具有当前坐标的标签,存储在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(); }
有了这些值,在将控件添加到使用鼠标指针选定的单元格时,确定当前单元格的坐标并使用它们就更加容易。 

例如,使用按钮(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); } }

视觉结果:

TabelLayoutPanel Cell Coordinates

© www.soinside.com 2019 - 2024. All rights reserved.