gpt4 book ai didi

c# - 在 FlowLayoutPanel 中居中放置多行控件

转载 作者:行者123 更新时间:2023-11-30 21:30:20 35 4
gpt4 key购买 nike

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

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

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

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

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

编辑:
以下是功能草案:

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

Draft

最佳答案

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

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

请注意,在 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. 将代码粘贴到表单的代码文件中

TableLayoutPanel Flow

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

关于c# - 在 FlowLayoutPanel 中居中放置多行控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54542104/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com