问题
Is there a way to adapt the size of a form to the size of its title / caption text?
For example, official C# Message Box forms will adjust to the size of its title text (Note the lorem ipsum):
Other forms will not adjust their size to that of their title text:
Instead, an ellipsis is added at the end to fit the size mentioned in the "Size" property of the designer.
Is there a way to make the form adjust to the size of the title instead of the size we mention? If not, is there a way to get the full length of the text so that we can assign it to the form?
I tried setting the width of the form using
int topTextWidth = TextRenderer.MeasureText(this.Text, this.Font).Width;
this.Width = topTextWidth;
But this.Font
apparently refers to another font size.
回答1:
For those who wants a full answer, here it is.
The actual line that resizes the form according to the caption text is the following:
this.Width = TextRenderer.MeasureText(this.Text, SystemFonts.CaptionFont).Width + AllButtonsAndPadding;
AllButtonsAndPadding
contains the width of all the buttons (minimize, maximize and close), the window borders and the icon. Getting these information takes a bit of coding. Here's a full example of a form that resizes itself, no matter what buttons or icon you put.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
namespace WindowAutoAdapt
{
public partial class Form1 : Form
{
//A default value in case Application.RenderWithVisualStyles == false
private int AllButtonsAndPadding = 0;
private VisualStyleRenderer renderer = null;
public Form1()
{
InitializeComponent();
this.Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; //A big text in the title
GetElementsSize();
ResizeForm();
}
//This gets the size of the X and the border of the form
private void GetElementsSize()
{
var g = this.CreateGraphics();
// Get the size of the close button.
if (SetRenderer(VisualStyleElement.Window.CloseButton.Normal))
{
AllButtonsAndPadding += renderer.GetPartSize(g, ThemeSizeType.True).Width;
}
// Get the size of the minimize button.
if (this.MinimizeBox && SetRenderer(VisualStyleElement.Window.MinButton.Normal))
{
AllButtonsAndPadding += renderer.GetPartSize(g, ThemeSizeType.True).Width;
}
// Get the size of the maximize button.
if (this.MaximizeBox && SetRenderer(VisualStyleElement.Window.MaxButton.Normal))
{
AllButtonsAndPadding += renderer.GetPartSize(g, ThemeSizeType.True).Width;
}
// Get the size of the icon.
if (this.ShowIcon)
{
AllButtonsAndPadding += this.Icon.Width;
}
// Get the thickness of the left, bottom,
// and right window frame.
if (SetRenderer(VisualStyleElement.Window.FrameLeft.Active))
{
AllButtonsAndPadding += (renderer.GetPartSize(g, ThemeSizeType.True).Width) * 2; //Borders on both side
}
}
//This resizes the form
private void ResizeForm()
{
this.Width = TextRenderer.MeasureText(this.Text, SystemFonts.CaptionFont).Width + AllButtonsAndPadding;
}
//This sets the renderer to the element we want
private bool SetRenderer(VisualStyleElement element)
{
bool bReturn = VisualStyleRenderer.IsElementDefined(element);
if (bReturn && renderer == null)
renderer = new VisualStyleRenderer(element);
else
renderer.SetParameters(element);
return bReturn;
}
}
}
回答2:
Thanks @CydrickT, that was helpful. I have some modification that were needed when applying this to a window with FormBorderStyle
of FixedDialog
and if ControlBox == false
on the form (needs try catch to handle error thrown).
Also even though and icon is specified, certain FormBorderStyle
's don't display them (even though ShowIcon == true which your code based some logic on) so this version of code adjusts for that.
I also added a new private property that holds the minimum width of the window that is set in the constructor to the minimum width if it was specified or the design time width if not. This allows contraction of the window's width if it were to have its text (title) changed in code and then the form redisplayed.
I added a text changed method for the form's text: Form1_TextChanged()
so that anytime the form's title text is changed the form width adjusts (again, if reusing the form instance). The form's designer of course would need to set this for the Text Changed event to be used.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
namespace WindowAutoAdapt
{
public partial class Form1: Form
{
private int AllButtonsAndPadding = 10;//seems things are coming up about this amount short so. . .
private VisualStyleRenderer renderer = null;
private int minWidth = 0;//will hold either the minimum size width if specified or the design time width of the form.
public Form1()
{
InitializeComponent();
//Capture an explicit minimum width if present else store the design time width.
if (this.MinimumSize.Width > 0)
{
minWidth = this.MinimumSize.Width;//use an explicit minimum width if present.
}
else
{
minWidth = this.Size.Width;//use design time width
}
GetElementsSize();
ResizeForm();
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_TextChanged(object sender, EventArgs e)
{
GetElementsSize();
ResizeForm();
}
//This gets the size of the X and the border of the form
private void GetElementsSize()
{
var g = this.CreateGraphics();
// Get the size of the close button.
if (SetRenderer(VisualStyleElement.Window.CloseButton.Normal))
{
AllButtonsAndPadding += renderer.GetPartSize(g, ThemeSizeType.True).Width;
}
// Get the size of the minimize button.
if (this.MinimizeBox && SetRenderer(VisualStyleElement.Window.MinButton.Normal))
{
AllButtonsAndPadding += renderer.GetPartSize(g, ThemeSizeType.True).Width;
}
// Get the size of the maximize button.
if (this.MaximizeBox && SetRenderer(VisualStyleElement.Window.MaxButton.Normal))
{
AllButtonsAndPadding += renderer.GetPartSize(g, ThemeSizeType.True).Width;
}
// Get the size of the icon only if it is actually going to be displayed.
if (this.ShowIcon && this.ControlBox && (this.FormBorderStyle == FormBorderStyle.Fixed3D || this.FormBorderStyle == FormBorderStyle.Sizable || this.FormBorderStyle == FormBorderStyle.FixedSingle))
{
AllButtonsAndPadding += this.Icon.Width;
}
// Get the thickness of the left and right window frame.
if (SetRenderer(VisualStyleElement.Window.FrameLeft.Active))
{
AllButtonsAndPadding += (renderer.GetPartSize(g, ThemeSizeType.True).Width) * 2; //Borders on both side
}
}
//This resizes the form
private void ResizeForm()
{
//widen window if title length requires it else contract it to the minWidth if required.
int newWidth = TextRenderer.MeasureText(this.Text, SystemFonts.CaptionFont).Width + AllButtonsAndPadding;
if (newWidth > minWidth)
{
this.Width = newWidth;
}
else
{
this.Width = minWidth;
}
}
//This sets the renderer to the element we want
private bool SetRenderer(VisualStyleElement element)
{
try
{
bool bReturn = VisualStyleRenderer.IsElementDefined(element);
if (bReturn && renderer == null)
{
renderer = new VisualStyleRenderer(element);
}
else
{
renderer.SetParameters(element);
}
return bReturn;
}
catch (Exception)
{
return false;
}
}
}
}
来源:https://stackoverflow.com/questions/18089280/adapt-the-size-of-a-form-to-its-title-text-in-c-sharp