WinForms按钮:自动调整大小最大尺寸

4
我想将按钮添加到FlowLayoutPanel中。这些按钮可能包含有空格的长文本。这些按钮的AutoSize属性为true,AutoSizeMode属性为AutoSizeMode.GrowAndShrink。此外,我将MaximumSize属性设置为(maxwidth,0),其中maxwidth是面板的宽度。因此,按钮不会变得太宽。 我发现,按钮的宽度受到MaximumSize属性的限制,但当文本换行时,按钮的高度不会自动调整为文本的高度。有没有解决这个问题的方法? 我还尝试了手动调整按钮大小的方法:
using (Graphics cg = this.CreateGraphics()) {
SizeF size = cg.MeasureString(button.Text, button.Font, 200);
  button.Width = (int)size.Width+20;
  button.Height = (int)size.Height+20;
  button.Text = someLongTextWithSpaces;
}

但请注意,我在计算的大小上增加了20。虽然这样可以工作,但有没有确定这个额外大小的正确方法?也许是2倍填充 + ?????


几个小时后...

我想到了这个版本,它似乎运行得相当好。

using (Graphics cg = this.CreateGraphics()) {
  var fmt = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak;
  var prop = new Size(tableLayoutPanel1.Width - 20, 0);
  var size = TextRenderer.MeasureText(button.Text, button.Font, prop, fmt);

  int border = button.Height - button.Font.Height;
  button.Width = (int)size.Width + border;
  button.Height = (int)size.Height + border;
  button.Text = someLongTextWithSpaces;
}

看起来初始按钮高度是边框加上字体高度。因此,我计算了边框减去button.Height-button.font.Height。

根据Hans的建议,我现在使用TextRenderer.MeasureText。我测试了一下没有启用VisualStyles,它也可以正常工作。对此有什么评论吗?


尝试使用 FlowLayoutPanel1.ClientRectangle.Width(或您称呼的面板名称)而不是手动添加 maxwidth 数字。例如,在 Form_Resize 中放置代码:Button1.MaximumSize = new Size(FlowLayoutPanel1.ClientRectangle.Width, 0)(这是vb代码,请将其转换为c#)。我认为这是c#代码:Button1.MaximumSize == new Size(FlowLayoutPanel1.ClientRectangle.Width, 0); - nelek
我也手动设置了MaximumSize的固定值。这个值是正确的,只有高度调整不起作用。您也可以在FormDesigner中进行测试。添加一个具有grow/shring的自动大小按钮和一个带有空格的较长文本。将最大宽度设置为小于文本。按钮宽度受限,但高度不会增加。 - bebo
你为什么加了+20? - A G
@Aseem Gautam:只是猜测一个测试值,找出真正的值才是问题所在。 - bebo
我期望它只在布局期间或之后进行计算。但是,我认为你可以将其隐藏甚至在得到魔法数字后将其删除。 - TaW
显示剩余2条评论
3个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
3
有一种正确的方法,但并不是很微妙。从ButtonRenderer类源代码中反向工程, Winforms类绘制按钮文本,您必须使用TextRenderer类来测量文本。您必须使用VisualStyleRenderer.GetBackgroundContentRectangle()方法获取有效的绘图边界。请注意,由于边框和选定的视觉样式而得到的大小比按钮的大小要小。

非常复杂的问题是将计算出的内容矩形映射回外部按钮大小,并处理没有启用视觉样式的旧计算机。下面是一个看起来能够得到正确大小的示例代码:
    private static void SetButtonSize(Graphics gr, Button button) {
        VisualStyleElement ButtonElement = VisualStyleElement.Button.PushButton.Normal;
        var visualStyleRenderer = new VisualStyleRenderer(ButtonElement.ClassName, ButtonElement.Part, 0);
        var bounds = visualStyleRenderer.GetBackgroundContentRectangle(gr, button.Bounds);
        var margin =  button.Height - bounds.Height;
        var fmt = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak;
        var prop = new Size(bounds.Width, 0);
        var size = TextRenderer.MeasureText(button.Text, button.Font, prop, fmt);
        button.ClientSize = new Size(button.ClientSize.Width, size.Height - margin);
    }

    protected override void OnLoad(EventArgs e) {
        using (var gr = this.CreateGraphics()) {
            SetButtonSize(gr, this.button1);
        }
        base.OnLoad(e);
    }

没有进行充分的角落情况测试,不建议使用。


我创建了一种新的计算边框的方法(请参见我上面的帖子)。你认为这是一个合适的方式吗?至少对我来说,无论启用还是禁用VisualStyles,它都有效。 - bebo
哦,像“20”这样的魔数从来不是一个好主意,当视频 DPI 改变时它们就无法工作。 - Hans Passant
你是指“tableLayoutPanel1.Width - 20”中的“20”吗?我只是不想让按钮填满整个tableLayoutPanel1的宽度。实际上,居中的按钮与两侧之间的距离不是2x10,而是2x(10-边框大小)。因此,除非边框为10或更多,否则它应该适合。也许我应该使用2x(计算出的边框+某些内容)来代替“20”。 - bebo

2

看起来初始按钮高度是边框加上字体的高度。因此我计算了边框减去 button.Height-button.font.Height。(请参见我的原始帖子的最后一个代码块)

这也适用于启用/禁用 VisualStyles。


1
我不确定 button.Height-button.font.Height 是否等同于调用 VisualStyleRenderer.GetBackgroundContentRectangle()。我的测试显示,对于边框,button.Height-button.font.Height 返回的值比 VisualStyleRenderer.GetBackgroundContentRectangle() 大。这取决于 DPI、字体大小等因素。例如,在 96dpi 和 8.25pt 字体大小的情况下,你的方法返回 5px 作为边框,而 VisualStyles 的方法返回 3px 作为边框! - 23W

0

您应该通过在文本中添加换行符来控制换行。仅使用空格的自动文本换行无法正常工作:

button1.Text = "123232131232\r\nfgfdgfdgdfgdfgdf\r\nASDSADSDASD";

或者:

button1.Text = "123232131232" + Environment.NewLine + 
           "fgfdgfdgdfgdfgdf" + Environment.NewLine + "ASDSADSDASD";

如果您更喜欢自动换行,可以尝试使用TextMeasure来确定文本所需的高度,然后相应地设置按钮的高度,但这可能需要额外的注意。

但我建议考虑使用标签。对于标签,换行功能已经内置..巨大的按钮和不同大小的非标准UI元素。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,