根据标题栏中的文本设置表单的宽度
Setting form's width according to text in title bar
当(或之后)调用我的 Form.Show()
方法时,我想根据标题栏中的字符串 (Form.Text
) 设置表单的宽度(或最小宽度),因为此文本根据用户的选择而变化。表单宽度最终应该是完美的宽度,这样标题栏文本就不会被截断并以“...”结尾。
目前,我只是将 MinimumSize
属性 设置为适合所有选择的值,但自动调整大小看起来会稍微整洁一些。我的问题是标题栏文本没有任何属性来获取其实际宽度。 AutoSize
也只是根据表单中的控件改变大小。
有什么我可以做的吗?
你可以得到系统菜单的宽度,标题文本的宽度和控制框按钮的宽度,然后计算出首选宽度,并检查当前宽度是否小于首选宽度,然后更改宽度首选宽度。
要获取有关标题栏元素的信息,您可以发送包含有关标题栏信息的 WM_GETTITLEBARINFOEX message to window and get an instance of TITLEBARINFOEX 结构。
您还可以使用 SystemInformation.CaptionButtonSize to get control button sizes and SystemInformation.SmallIconSize 获取系统菜单图标大小并添加一些额外的填充 space。
例子
您可以覆盖如下形式的 OnShown 方法:
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
var info = NativeMethods.GetTitleBarInfo(this.Handle);
var systemMenuWidth = info.rcTitleBar.Left - this.Left;
var controlBoxWidth =
info.rgrect[(int)NativeMethods.TitleBarRectangles.CloseButton].Right -
info.rgrect[(int)NativeMethods.TitleBarRectangles.MinimizeButton].Left;
var titleWidth = TextRenderer.MeasureText(this.Text, SystemFonts.CaptionFont).Width;
//var preferred = titleWidth + systemMenuWidth + controlBoxWidth + 16;
//if (this.Width < preferred)
// this.Width = preferred;
var preferred = titleWidth + systemMenuWidth + controlBoxWidth;
if (this.Width < preferred)
this.ClientSize = new Size(preferred, this.ClientSize.Height);
}
这里是 NativeMethods:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
public static class NativeMethods
{
public const int WM_GETTITLEBARINFOEX = 0x033F;
public static TITLEBARINFOEX GetTitleBarInfo(IntPtr hwnd)
{
var info = new TITLEBARINFOEX()
{ cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFOEX)) };
SendMessage(hwnd, WM_GETTITLEBARINFOEX, IntPtr.Zero, ref info);
return info;
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr SendMessage(
IntPtr hWnd, int Msg, IntPtr wParam, ref TITLEBARINFOEX lParam);
[StructLayout(LayoutKind.Sequential)]
public struct TITLEBARINFOEX
{
public const int CCHILDREN_TITLEBAR = 5;
public uint cbSize;
public RECT rcTitleBar;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
public uint[] rgstate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
public RECT[] rgrect;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left, Top, Right, Bottom;
public Rectangle ToRectangle() => Rectangle.FromLTRB(Left, Top, Right, Bottom);
}
public enum TitleBarRectangles
{
TitleBar = 0,
Reserved = 1,
MinimizeButton = 2,
MaximizeButton = 3,
HelpButton = 4,
CloseButton = 5
}
}
所以在设计器中有这样的表格:
但在运行时:
替代解决方案 - 为标题栏设置工具提示
作为替代解决方案,您可以 add a ToolTip to the Form titlebar:
当(或之后)调用我的 Form.Show()
方法时,我想根据标题栏中的字符串 (Form.Text
) 设置表单的宽度(或最小宽度),因为此文本根据用户的选择而变化。表单宽度最终应该是完美的宽度,这样标题栏文本就不会被截断并以“...”结尾。
目前,我只是将 MinimumSize
属性 设置为适合所有选择的值,但自动调整大小看起来会稍微整洁一些。我的问题是标题栏文本没有任何属性来获取其实际宽度。 AutoSize
也只是根据表单中的控件改变大小。
有什么我可以做的吗?
你可以得到系统菜单的宽度,标题文本的宽度和控制框按钮的宽度,然后计算出首选宽度,并检查当前宽度是否小于首选宽度,然后更改宽度首选宽度。
要获取有关标题栏元素的信息,您可以发送包含有关标题栏信息的 WM_GETTITLEBARINFOEX message to window and get an instance of TITLEBARINFOEX 结构。
您还可以使用 SystemInformation.CaptionButtonSize to get control button sizes and SystemInformation.SmallIconSize 获取系统菜单图标大小并添加一些额外的填充 space。
例子
您可以覆盖如下形式的 OnShown 方法:
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
var info = NativeMethods.GetTitleBarInfo(this.Handle);
var systemMenuWidth = info.rcTitleBar.Left - this.Left;
var controlBoxWidth =
info.rgrect[(int)NativeMethods.TitleBarRectangles.CloseButton].Right -
info.rgrect[(int)NativeMethods.TitleBarRectangles.MinimizeButton].Left;
var titleWidth = TextRenderer.MeasureText(this.Text, SystemFonts.CaptionFont).Width;
//var preferred = titleWidth + systemMenuWidth + controlBoxWidth + 16;
//if (this.Width < preferred)
// this.Width = preferred;
var preferred = titleWidth + systemMenuWidth + controlBoxWidth;
if (this.Width < preferred)
this.ClientSize = new Size(preferred, this.ClientSize.Height);
}
这里是 NativeMethods:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
public static class NativeMethods
{
public const int WM_GETTITLEBARINFOEX = 0x033F;
public static TITLEBARINFOEX GetTitleBarInfo(IntPtr hwnd)
{
var info = new TITLEBARINFOEX()
{ cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFOEX)) };
SendMessage(hwnd, WM_GETTITLEBARINFOEX, IntPtr.Zero, ref info);
return info;
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr SendMessage(
IntPtr hWnd, int Msg, IntPtr wParam, ref TITLEBARINFOEX lParam);
[StructLayout(LayoutKind.Sequential)]
public struct TITLEBARINFOEX
{
public const int CCHILDREN_TITLEBAR = 5;
public uint cbSize;
public RECT rcTitleBar;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
public uint[] rgstate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
public RECT[] rgrect;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left, Top, Right, Bottom;
public Rectangle ToRectangle() => Rectangle.FromLTRB(Left, Top, Right, Bottom);
}
public enum TitleBarRectangles
{
TitleBar = 0,
Reserved = 1,
MinimizeButton = 2,
MaximizeButton = 3,
HelpButton = 4,
CloseButton = 5
}
}
所以在设计器中有这样的表格:
但在运行时:
替代解决方案 - 为标题栏设置工具提示
作为替代解决方案,您可以 add a ToolTip to the Form titlebar: