【问题标题】:Center multiple rows of controls in a FlowLayoutPanel在 FlowLayoutPanel 中将多行控件居中
【发布时间】:2019-06-29 17:25:38
【问题描述】:

我正在尝试制作一个面板来承载动态添加的控件。有两个注意事项:

  • 将有很多控件,因此面板应在达到其宽度限制并垂直滚动时将元素包装到新行中。
  • 控件可以改变大小,这会改变元素的数量
    可以放在一行中。

我已经看到了一些将动态控件集中在表单中的解决方案,但出于以下原因拒绝了这些解决方案:

  • TableLayoutPanel - 我使用它时遇到的主要问题是 元素增长并且必须从 3-2 网格转移到 2-4,如 TableLayoutPanel 似乎不能很好地处理这些。
  • AutoSize FlowLayoutPanel 可以在内部扩展和收缩 TableLayoutControl - 我对这个解决方案的主要问题是它 仅在表单内居中一行,一旦换行到新行, 元素开始与右侧对齐。我想我可以动态 将新的 FlowLayoutPanels 添加到 TableLayoutControl 的新行中,但随后 我有一个与我需要手动的第一个场景类似的问题 如果元素大小增加/缩小,则在行之间重新分配元素。

我想知道我是否缺少一些可以帮助我处理增长/收缩事件而无需创建自己的 TableLayoutPanel 变体的功能?

编辑:
以下是功能草稿:

  • A - 两个元素在面板中居中
  • B - 添加第三个元素,三个元素都居中
  • C - 添加第四个元素,换行并居中
  • D - 元素放大,现在包裹在第二个元素上,居中

【问题讨论】:

    标签: c# .net winforms tablelayoutpanel flowlayoutpanel


    【解决方案1】:

    这是一个重现您描述的行为的示例。
    它利用了承载多个 FlowLayoutPanel 的 TableLayoutPanel。

    一个重要的细节是子 FlowLayoutPanel 的锚定:它们需要锚定到 Top-Bottom:这会导致面板位于 TableLayoutPanel Row 的中心。

    请注意,在 Form 构造函数中,RowStyles 之一已被删除。这一点也很重要:TLP(这是个很古怪的家伙),即使你只有一行(或一列,同样的东西),也会保留 2 个RowStyles。第二种样式将应用于您添加的第一行;只针对第一个,而不是其他:这可能会破坏布局。

    另一个异常,它没有提供删除行的方法,所以我做了一个。它功能齐全,但很简单,需要扩展,包括进一步的验证。

    查看有关当前功能的图形示例。如果您在实施其他方面需要帮助,请发表评论。


    要构建它,请将以下控件添加到表单(此处称为 FLPTest1):

    1. 添加一个面板,设置Dock.Bottom。右键点击SendToBack()
    2. 添加一个TableLayoutPanel(这里称为tlp1),设置:
      • AutoScroll = true, AutoSize = true,
      • AutoSizeMode = GrowAndShrink, Dock.Fill
      • 保留 1 列,设置为 AutoSize,保留 1 行,设置为 AutoSize
    3. 添加一个FlowLayoutPanel(此处称为flp1),位于TableLayoutPanel 内。实际上没有必要,仅用于此示例代码
      • 将其 Anchor 设置为 Top, Bottom <= 这是!important,如果没有它,布局将无法正常工作:它允许将FLP 居中在TLP 行内,李>
      • AutoSize = true, AutoSizeMode = GrowAndShrink
    4. 添加按钮(称为btnAddControl
    5. 添加第二个按钮(称为btnRemoveControl
    6. 添加一个复选框(称为chkRandom
    7. 将此处的代码粘贴到表单的代码文件中

    using System.Drawing;
    using System.Linq;
    using System.Windows.Forms;
    
    
    public partial class TLPTest1 : Form
    {
        public TLPTest1()
        {
            InitializeComponent();
            tlp1.RowStyles.RemoveAt(1);
        }
    
        private void TLPTest1_Load(object sender, EventArgs e)
        {
            PictureBox pBox = new PictureBox() {
                Anchor = AnchorStyles.None,
                BackColor = Color.Orange,
                MinimumSize = new Size(125, 125),
                Size = new Size(125, 125),
            };
            flp1.Controls.Add(pBox);
            tlp1.Controls.Add(flp1);
        }
    
        Random rnd = new Random();
        Size[] sizes = new Size[] { new Size(75, 75), new Size(100, 100), new Size(125, 125)};
        Color[] colors = new Color[] { Color.Red, Color.LightGreen, Color.YellowGreen, Color.SteelBlue };
        Control selectedObject = null;
    
        private void btnAddControl_Click(object sender, EventArgs e)
        {
            Size size = new Size(125, 125);
            if (chkRandom.Checked) size = sizes[rnd.Next(sizes.Length)];
            
            var pBox = new PictureBox() {
                Anchor = AnchorStyles.None,
                BackColor = colors[rnd.Next(colors.Length)],
                MinimumSize = size,
                Size = size
            };
    
            bool drawborder = false;
            // Just for testing - use standard delegates instead of Lambdas in real code
            pBox.MouseEnter += (s, evt) => { drawborder = true;  pBox.Invalidate(); };
            pBox.MouseLeave += (s, evt) => { drawborder = false; pBox.Invalidate(); };
            pBox.MouseDown += (s, evt) => { selectedObject = pBox;  pBox.Invalidate(); };
            pBox.Paint += (s, evt) => { if (drawborder) {
                ControlPaint.DrawBorder(evt.Graphics, pBox.ClientRectangle, 
                                        Color.White, ButtonBorderStyle.Solid);
                }
            };
    
            var ctl = tlp1.GetControlFromPosition(0, tlp1.RowCount - 1);
            int overallWith = ctl.Controls.OfType<Control>().Sum(c => c.Width + c.Margin.Left + c.Margin.Right);
            overallWith += (ctl.Margin.Right + ctl.Margin.Left);
    
            if ((overallWith + pBox.Size.Width + pBox.Margin.Left + pBox.Margin.Right) >= tlp1.Width) {
                var flp = new FlowLayoutPanel() {
                    Anchor = AnchorStyles.Top | AnchorStyles.Bottom,
                    AutoSize = true,
                    AutoSizeMode = AutoSizeMode.GrowAndShrink,
                };
    
                flp.Controls.Add(pBox);
    
                tlp1.SuspendLayout();
                tlp1.RowCount += 1;
                tlp1.Controls.Add(flp, 0, tlp1.RowCount - 1);
                tlp1.ResumeLayout(true);
            }
            else {
                ctl.Controls.Add(pBox);
            }
        }
    
        private void btnRemoveControl_Click(object sender, EventArgs e)
        {
            if (selectedObject is null) return;
            Control parent = selectedObject.Parent;
            selectedObject.Dispose();
    
            if (parent?.Controls.Count == 0) {
                TLPRemoveRow(tlp1, parent);
                parent.Dispose();
            }
        }
    
        private void TLPRemoveRow(TableLayoutPanel tlp, Control control)
        {
            int ctlPosition = tlp.GetRow(control);
            if (ctlPosition < tlp.RowCount - 1) {
                for (int i = ctlPosition; i < tlp.RowCount - 1; i++) {
                    tlp.SetRow(tlp.GetControlFromPosition(0, i + 1), i);
                }
            }
            tlp.RowCount -= 1;
        }
    }
    

    【讨论】:

    • 非常感谢。这比我希望的要详细得多,哈哈
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多