Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
194 views
in Technique[技术] by (71.8m points)

c# - Setting form's width according to text in title bar

When (or after) I call my Form.Show() method, I would like to set the form's width (or minimum width) according to the string in the title bar (Form.Text), since this text is changing according to a user's choice. The form width should end up being the perfect amount so that the title bar text doesn't cut off and end with "...".
Currently, I'm simply setting the MinimumSize property to a value that accommodates for all choices, but an automatic sizing would look slightly neater. My problem here is that the title bar text doesn't have any properties to get its actual width. AutoSize also only changes the size according to the controls in the form.

Is there anything I can do?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can get the width of the system menu, width of the title text and width of control box buttons, then calculate the preferred width and check if the current width is less that the preferred with, then change the widths of the for to preferred width.

auto-size based on title text width

To get the information about titlebar elements, you can send a WM_GETTITLEBARINFOEX message to window and get an instance of TITLEBARINFOEX structure which contains information about titlebar.

You can also use SystemInformation.CaptionButtonSize to get control button sizes and SystemInformation.SmallIconSize to get system menu icon size and add a bit of extra padding space.

Example

You can override OnShown method of the form like this:

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

And here is 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
    }
}

So having such form in designer:

form in design mode

But at runtime:

auto-size based on title text width

Alternative solution - Set tooltip for titlebar

As an alternative solution you can add a ToolTip to the Form titlebar:

Tooltip for titlebar


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...