动态添加到TableLayoutPanel的行将显示在不同的行位置 [英] Dynamically added rows to a TableLayoutPanel are displayed on a different row position

查看:46
本文介绍了动态添加到TableLayoutPanel的行将显示在不同的行位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过单击按钮将TextBox动态添加到TableLayoutPanel中.通过单击鼠标选择行".
在选择行之后,单击按钮会在选定的行号上插入一个文本框.
问题是,在不同选择的行上正确地显示文本框3或4次之后,再单击一次按钮就会开始在随机行上显示文本框,即使调试正确的行也是如此显示数字.

我需要帮助,这是完整的代码:

 公共局部类Form1:表单{私有TableLayoutPanel _tableLayout;private int _selectedRow = -1;公共Form1(){InitializeComponent();var button = new Button(){文字=添加文字"};button.MouseClick + = AddText;this.Controls.Add(button);_tableLayout =新的TableLayoutPanel(){Dock = DockStyle.Fill,AutoScroll = true,AutoSize = true,AutoSizeMode = AutoSizeMode.GrowAndShrink,CellBorderStyle = TableLayoutPanelCellBorderStyle.Single};_tableLayout.MouseClick + = SelectRow;this.Controls.Add(_tableLayout);}私有void SelectRow(对象发送者,MouseEventArgs e){_selectedRow = GetRowColIndex(_tableLayout,e.Location).Value.Y;}私有无效AddText(对象发送者,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);}观点?GetRowColIndex(TableLayoutPanel tlp,Point point){如果(point.X> tlp.Width || point.Y> tlp.Height)返回null;int w = tlp.Width;int h = tlp.Height;int [] widths = tlp.GetColumnWidths();我对于(i = widths.Length-1; i> = 0&& point.X< w; i--)w-=宽度[i];int col = i + 1;int [] heights = tlp.GetRowHeights();对于(i = heights.Length-1; i> = 0&& point.Y< h; i--)h-=高度[i];int行= i + 1;返回新的Point(col,row);}} 

解决方案

当前代码中缺少某些部分.它不考虑滚动条和当前TableLayoutPanel的DisplayRectangle.如您在.Net源代码中所看到的,

I am trying to dynamically add a TextBox to a TableLayoutPanel with the click of a Button. A Row is selected by click the mouse.
Following a Row selection, a button click inserts a TextBox on the selected Row number.
Problem is that after correctly displaying a TextBox 3 or 4 times on differently selected rows, further button clicks start displaying the TextBox on random rows, even if, debugging, the correct row number is shown.

I need help please, here is the full code:

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);
    }
}

解决方案

Some parts are missing in the current code. It doesn't account for Scrollbars and the current TableLayoutPanel's DisplayRectangle. As you can see in the .Net Source code, the TableLayoutPanel's OnPaintBackGround method already performs these calculation, to obtain the coordinates of each cell and call OnPaintCell() with a TableLayoutCellPaintEventArgs class initialized using the current cell's Bounds and ClipBounds.

You could use the same logic in your code or use the already known measures, retrieving the clicked Cell bounds from the e.CellBounds parameter in the CellPaint event.

The example here, take the Mouse location from the TLP's MouseClick event and uses the Rectangle.Contains(Point) method in e.CellBounds.Contains(currentPointerLocation) to paint a Cell's background when the Cell's Bounds contain the Mouse pointer and updates a couple of Labels with current coordinates, stored in 2 fields, here, for semplicity:

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();
}

With these values, it simpler to determine the current Cell's coordinates and use them when adding Controls to a Cell selected with the Mouse pointer.

For example, using a Button (btnAddControl) and a ContextMenuStrip to add different controls to the 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);
    }
}

Visual result:

这篇关于动态添加到TableLayoutPanel的行将显示在不同的行位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆