Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw Windows Classic style window elements

We create a few custom 'windows' in our program and when VisualStyles are enabled we are able to find each element of the window and their size and paint them ourselves including the minimize and close buttons using the appropriate Renderers.

We'd like to do that same thing when VisualStyles are disabled and currently draw our own windows but they're quite ugly. Is it possible in WinForms C# to draw the Windows Classic style windows? I've found the ClassicBorderDecorator but it's for WPF.

Or, failing that, how can we get the pixel sizes of the window decorations which we do in the following way:

// Get the height of the window caption.
if (SetRenderer(windowElements["windowCaption"]))
{
  captionHeight = renderer.GetPartSize(graphics.Graphics, ThemeSizeType.True).Height;
}

// Get the thickness of the left, bottom, 
// and right window frame.
if (SetRenderer(windowElements["windowLeft"]))
{
  frameThickness = renderer.GetPartSize(graphics.Graphics, ThemeSizeType.True).Width;
}
like image 918
DTI-Matt Avatar asked Feb 14 '23 06:02

DTI-Matt


1 Answers

Windows doesn't provide a renderer for the classic style, you'll have to cook your own. Use the SystemInformation class to get the metrics, Color.FromKnownColor() to get colors.

The only tricky part is to get the frame buttons look good. Best thing to do is to use a glyph from a font instead of trying to paint them yourself. The Webdings font is ideal for this.

I cannot verify how close a match it will be, my machine boots Windows 8 and doesn't support classic style anymore. Otherwise a strong hint that you probably should not invest too much time into this :) Some example code:

protected override void OnPaintBackground(PaintEventArgs e) {
    base.OnPaintBackground(e);
    var captionHeight = SystemInformation.CaptionHeight;
    int border = SystemInformation.Border3DSize.Width;
    var color1 = Color.FromKnownColor(activated ? KnownColor.ActiveCaption : KnownColor.InactiveCaption);
    var color2 = Color.FromKnownColor(activated ? KnownColor.GradientActiveCaption : KnownColor.GradientInactiveCaption);
    var captionrc = new Rectangle(0, 0, this.ClientSize.Width, captionHeight);
    using (var brush = new LinearGradientBrush(captionrc, color1, color2, 0, false)) {
        e.Graphics.FillRectangle(brush, captionrc);
    }
    int textx = border;
    if (this.Icon != null) {
        int height = SystemInformation.SmallIconSize.Height;
        var iconrc = new Rectangle(border, (captionHeight - height)/2, height, height);
        textx += height + border;
        e.Graphics.DrawIcon(this.Icon, iconrc);
    }
    var color = Color.FromKnownColor(activated ? KnownColor.ActiveCaptionText : KnownColor.InactiveCaptionText);
    using (var font = new Font(this.Font.FontFamily, SystemInformation.CaptionHeight - 4 * border, GraphicsUnit.Pixel)) {
        TextRenderer.DrawText(e.Graphics, this.Text, font, new Point(textx, border), color);
    }
    using (var font = new Font(new FontFamily("Webdings"), captionHeight - 4 * border, GraphicsUnit.Pixel)) {
        var glyphs = this.WindowState == FormWindowState.Maximized ? "\u0030\u0031\u0072" : "\u0030\u0031\u0072";
        var width = TextRenderer.MeasureText(glyphs, font).Width;
        TextRenderer.DrawText(e.Graphics, glyphs, font, 
            new Point(this.ClientSize.Width - width, border),
            Color.FromKnownColor(KnownColor.WindowFrame));
    }
}

Looks like this on my machine, not entirely ugly :)

enter image description here

like image 180
Hans Passant Avatar answered Feb 15 '23 19:02

Hans Passant