C#、Windows 窗体、最佳/最小适合窗口内容

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/864130/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 04:43:18  来源:igfitidea点击:

C#, Windows Forms, Best/min fit window to contents

c#.netwinforms

提问by Thanatos

I have a form with some controls. (Actually, this is a sort of ongoing problem.) Some of the forms I have had are resizable, some are not. Regardless, when the form is displayed, it would be nice to have it appear in the "minimum" size needed. Other Windowing toolkits, such as wxWidgets (wxWindow::GetMinSize) and Qt (QWidget::minimumSize) have this functionality.

我有一个带有一些控件的表单。(实际上,这是一种持续存在的问题。)我拥有的一些表格可以调整大小,有些则不是。无论如何,当表单显示时,让它以所需的“最小”尺寸显示会很好。其他窗口工具包,例如 wxWidgets (wxWindow::GetMinSize) 和 Qt (QWidget::minimumSize) 具有此功能。

This functionality, if you are not familiar with it, allows a window to resize itself to a minimum size, which is often all the window needs, and looks quite nice. If I have two static texts, and two edit boxes laid out thusly:

如果您不熟悉此功能,它允许窗口将自身调整为最小尺寸,这通常是窗口所需的全部尺寸,并且看起来相当不错。如果我有两个静态文本,并且有两个编辑框这样布置:

Username:
[ Edit/text box for user's password]
Password:
[ Edit/text box for user's password]
              [  Cancel  ][   OK   ]

I can then tell this form to size itself to it's "minimum size", and it would appear much like above. (Minimum width in a text box is partly subjective - I would have to set that myself in one/both of the text boxes, but the form would query the child controls and learn of that minimum width) This is usually combined with layouts of some sort. (Which .Net has.)

然后我可以告诉这个表单将自身的大小调整为它的“最小大小”,它看起来很像上面。(文本框中的最小宽度部分是主观的 - 我必须自己在一个/两个文本框中设置它,但表单会查询子控件并了解该最小宽度)这通常与某些布局结合使用种类。(.Net 有。)

This has the added benefit that the form is the correct size regardless of font settings, locale, dpi, gui skin, etc. (If done right, at least.)

这有一个额外的好处,即无论字体设置、语言环境、dpi、gui 皮肤等如何,表单都是正确的大小(如果做得对,至少。)

Does this exist in .Net, and if so, where? If you need any more description, ask, and I'll be glad to provide.

这是否存在于 .Net 中,如果存在,在哪里?如果您需要更多描述,请询问,我很乐意提供。

Edit: What I'm looking for is the above example, resizable only in the X direction (I'm willing to accept both) but can't be resized smaller than a certain W/H. The controls should anchor - ie, the text boxes get bigger, the buttons stay right aligned.

编辑:我正在寻找的是上面的例子,只能在 X 方向调整大小(我愿意接受两者)但不能调整为小于某个 W/H。控件应该锚定——即,文本框变大,按钮保持右对齐。

Edit: I can do images! Supposedly they're worth a thousand words: alt text http://www.freeimagehosting.net/uploads/79e9ee10e5.png

编辑:我可以做图像!据说它们值一千个字: 替代文本 http://www.freeimagehosting.net/uploads/79e9ee10e5.png

Edit:I guess I'm going to start marking answers. Henk's answer has gotten me pretty far with a non-resizable dialog that fits to it's contents. Most of the posts below are valuable, but miss the point (unless I'm really off base here?): I understand how to use Anchor/TableLayout, and to get controls to flow there - it was mostly getting one or both dimensions of the dialog to fit to the contents of the dialog. You essentially have three cases:

编辑:我想我要开始标记答案了。Henk 的回答让我得到了一个适合其内容的不可调整大小的对话框。下面的大多数帖子都很有价值,但没有抓住重点(除非我真的不在乎?):我了解如何使用 Anchor/TableLayout,并让控件在那里流动 - 它主要是获得一个或两个维度的对话框以适应对话框的内容。您基本上有三种情况:

  1. The dialog is not resizable - See Henk's answer. Combined with TableLayout and Anchors, you'll get a decent dialog.

  2. The dialog is only resizable in one dimension - Go with 1 or 3 - You can constrain a dimension by using the Resize event, but the dialog flickers horribly. (This seems to be a defect in Win32 as far as I can tell - there is some stuff out there about overriding the background erase, which works for controls, but not windows, as you'll get artifacts in the form's background (because you're not erasing them). The real answer is that this should probably be handled by Win32 itself - I should not have to reinvent the double-buffer wheel just to get a decent look dialog...))

  3. The dialog is fully resizable. Anchors and TableLayout are your friend. Unfortunately, the MinimumSize attribute seems to be bogus (at least, I don't know what it is for...) - for example, if you query the MinimumSize of a textbox, by default the height is 4 pixels. Further, the MinimumSize property doesn't seem to propogate - a control does not query it's children. (I can resize the form smaller than the textbox within the form, and the textbox is then off the form.) If you wonder what I'm babbling about, see wxWidgets and how layouts and minimum size work for it.

  1. 对话框不可调整大小 - 请参阅 Henk 的回答。结合 TableLayout 和 Anchors,您将获得一个不错的对话框。

  2. 对话框只能在一维中调整大小 - 选择 1 或 3 - 您可以使用 Resize 事件来约束一个维度,但对话框闪烁得可怕。(据我所知,这似乎是 Win32 中的一个缺陷 - 有一些关于覆盖背景擦除的内容,这适用于控件,但不适用于 Windows,因为您将在表单的背景中获得工件(因为您'不是擦除它们。真正的答案是这可能应该由 Win32 本身来处理 - 我不应该为了获得一个像样的外观对话框而重新发明双缓冲轮......))

  3. 该对话框是完全可调整大小的。Anchors 和 TableLayout 是你的朋友。不幸的是,MinimumSize 属性似乎是假的(至少,我不知道它是做什么用的……)-例如,如果您查询文本框的 MinimumSize,默认情况下高度为 4 像素。此外,MinimumSize 属性似乎没有传播 - 控件不会查询它的子项。(我可以将表单的大小调整为小于表单中的文本框,然后文本框离开表单。)如果您想知道我在胡说八道什么,请参阅 wxWidgets 以及布局和最小尺寸如何为它工作。

I've also since discovered that .Net does not seem to respect the system font, and always uses the same font for Forms, so font changes won't affect my dialog (sadly) which alieviates most of my worries (happily?). Again, refer to how wxWidgets does it - if the system font is 22pt, all wxFrames (forms) respect and resize appropriately. .Net should get onboard this train... (And I know someone who uses 22+pt font day-to-day for their standard GUI font.)

我还发现 .Net 似乎不尊重系统字体,并且总是为 Forms 使用相同的字体,因此字体更改不会影响我的对话框(可悲的是),这消除了我的大部分担忧(快乐?)。再次参考 wxWidgets 是如何做到的——如果系统字体是 22pt,所有 wxFrames(表单)都会尊重并适当调整大小。.Net 应该登上这列火车......(我知道有人每天使用 22+pt 字体作为他们的标准 GUI 字体。)

采纳答案by Henk Holterman

There is something that comes close, try the following: design your Form a bit large and avoid Right and Bottom docked controls. Then some code like this:

有一些接近的东西,请尝试以下操作:将您的表单设计得有点大,并避免右和底部停靠控件。然后是这样的一些代码:

private void button1_Click(object sender, EventArgs e)
{
    this.AutoSize = true;
    this.Size = new Size(10, 10);
}

The AutoSize will find the extend of the Controls.

AutoSize 将找到控件的扩展。

回答by Austin Salonen

It sounds like you want the Dock and Anchor properties.

听起来您想要 Dock 和 Anchor 属性。

Hereis the first link from Google.

是来自谷歌的第一个链接。

回答by NascarEd

Here's how I typically handle this case with anchoring: Set the anchor of the labels to Top, Left (the default); The text boxes to Top, Left, Right; and the buttons to Bottom, Right. Size the form in the designer to your desired minimum size. In the designer, set the MinimumSize property of the form to its current size.

以下是我通常使用锚定处理这种情况的方法:将标签的锚点设置为顶部、左侧(默认值);文本框到顶部、左侧、右侧;和按钮底部,右侧。将设计器中的表单大小调整为所需的最小尺寸。在设计器中,将窗体的 MinimumSize 属性设置为其当前大小。

At run-time, the user can resize the form. The labels will not move, the text boxes will stretch horizontally, but not vertically. The buttons will move with the right and bottom edges of the form. The user will not be able to make the form (and its controls smaller than the MinimumSize).

在运行时,用户可以调整表单的大小。标签不会移动,文本框会水平拉伸,但不会垂直拉伸。按钮将随着表单的右边缘和下边缘移动。用户将无法制作表单(及其控件小于 MinimumSize)。

Hope this helps.

希望这可以帮助。

回答by Zach Johnson

I handle these sort of things using TableLayoutPanel. TableLayoutPanel lets you layout your controls in columns and rows. Columns and rows have three SizeTypes: AutoSize, Percent, and Absolute. AutoSize sizes the column or row according to the minimum necessary value, Percent sizes the column or row according a percent of unused area, and Absolute sizes the column or row according to an absolute number of pixels.

我使用TableLayoutPanel处理这些事情。TableLayoutPanel 允许您按列和行布置控件。列和行具有三种 SizeType:AutoSize、Percent 和 Absolute。AutoSize 根据最小必要值调整列或行的大小,Percent 根据未使用区域的百分比调整列或行的大小,而 Absolute 根据绝对像素数调整列或行的大小。

The VisualStudio designer is helpful. If you would rather write all code by hand, it is still a good idea to play with TableLayoutPanel in the designer and examine the resulting designer code to learn how to operate TableLayoutPanel.

VisualStudio 设计器很有帮助。如果您更愿意手动编写所有代码,在设计器中使用 TableLayoutPanel 并检查生成的设计器代码以了解如何操作 TableLayoutPanel 仍然是一个好主意。

In order to get the minimum necessary size, you should:

为了获得所需的最小尺寸,您应该:

  • Dock.Fill the TableLayoutPanel in your form.
  • Dock.Fill controls in cells.
  • Handle spacing between controls using Control.Margin.
  • Make the SizeType of all the columns and rows AutoSize.
  • Dock.Fill TableLayoutPanel 在您的表单中。
  • 单元格中的 Dock.Fill 控件。
  • 使用 Control.Margin 处理控件之间的间距。
  • 使所有列和行的 SizeType 为 AutoSize。

Also, you can use ColumnSpan and RowSpan to make a control take up multiple cells.

此外,您可以使用 ColumnSpan 和 RowSpan 使控件占据多个单元格。

Once you set things up the way you want them to look, you can use TableLayoutPanel.GetPreferredSize() to determine the minimum required area of the TableLayoutPanel and assign that value to Form.ClientSize.

按照您希望的方式进行设置后,您可以使用 TableLayoutPanel.GetPreferredSize() 来确定 TableLayoutPanel 所需的最小面积并将该值分配给 Form.ClientSize。

If the user will be able to resize your form, after you determine the minimum required size you should set the SizeType of the column and row you want to grow with the form to SizeType.Percent and use a value of 100, like this:

如果用户能够调整表单的大小,在确定所需的最小大小后,您应该将要随表单增长的列和行的 SizeType 设置为 SizeType.Percent 并使用值 100,如下所示:

// "columnIndex" is the zero based index of the column
this.tableLayoutPanel.ColumnStyles[columnIndex] = new ColumnStyle(SizeType.Percent, 100);

// "rowIndex" is the zero based index of the row
this.tableLayoutPanel.RowStyles[rowIndex] = new RowStyle(SizeType.Percent, 100);

回答by Fredrik M?rk

Use the MaximumSizeand MinimumSizeproperties of the form, along with the Anchor properties of the controls.

使用窗体的MaximumSizeMinimumSize属性,以及控件的 Anchor 属性。

// make the form 200 pixels high, without possibility to resize the height
// and restrict the minimum width to 200 pixels
this.MinimumSize = new Size(200, 200);
this.MaximumSize = new Size(30000, 200);

回答by Lucas

Off the top of my head (read: I haven't tested this), I would think you can iterate through all the child controls when the form loads and determine it's minimum size. You can then set the form to this size and set it's MinimumSizeproperty so it can never be resized to anything smaller.

在我的头顶上(阅读:我还没有测试过这个),我认为你可以在表单加载时遍历所有子控件并确定它的最小大小。然后,您可以将表单设置为这个大小并设置它的MinimumSize属性,这样它就永远不会被调整为更小的尺寸。

Something like this, using some LINQ:

像这样,使用一些 LINQ:

OnLoad()
{
    int right = this.Controls.Cast<Control>().Max(c => c.Right);
    int bottom = this.Controls.Cast<Control>().Max(c => c.Bottom);

    // leave a little padding, add maybe 10px or 10%?
    int minWidth = right + 10;
    int minHeight = bottom + 10;

    this.Size = new Size(minWidth, minHeight);
    this.MinimumSize = new Size(minWidth, minHeight);
}

About the WinForms font, apparently it's a bug from 1.0 that has been carried over for compatibility's sake. (see hereand here.) You can work around it by setting this.Font = SystemFonts.DialogFontwhen the form loads. This however doesn't show up in design mode. To work around this, set the font in a BaseForm and derive all your forms from it.

关于 WinForms 字体,显然它是 1.0 的一个错误,为了兼容性而被保留。(请参阅此处此处。)您可以通过设置this.Font = SystemFonts.DialogFont表单加载时间来解决此问题。但是,这不会在设计模式中显示。要解决此问题,请在 BaseForm 中设置字体并从中派生所有表单。

Update: I see how this can be a problem if you have right or bottom-anchored controls. It will use they current position and size and not compute a minimum for size where they won't squish into other controls or become too small. Maybe you can set their anchors programatically afteryou have resized the form.

更新:我明白如果你有正确的或底部锚定的控件,这可能是一个问题。它将使用它们当前的位置和大小,而不是计算它们不会挤入其他控件或变得太小的大小的最小值。也许您可以调整表单大小以编程方式设置它们的锚点。