Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reduce Padding Around Text in WinForms Button

I have an application that is going to be used on a touch screen system, and it contains a number of buttons that are fairly large (~100px square).

Each button will have between 1 and 4 lines of text (typically one word per line).

Due to the large amount of padding in the button, I'm having to reduce the size of the text so that it becomes almost unreadable, however if I was able to reduce the internal padding so that the text would paint right up to the border, then I wouldn't have a problem.

I've attempted to reduce the padding of the control down to zero as follows, but it doesn't help.

this.Text = _label;
this.Font = new Font(this.Font.FontFamily, (float) _size);
this.Padding = new Padding(0);

An example of the problem is shown below:

Button with broken text

As you can see there is plenty of space for the word 'OVERVIEW' to fit on one line, but how can I achieve this without reducing the font size? I don't relish the thought of having to rewrite the control's text painting code.

Edit: I've noticed that increasing the padding to various values as high as 300, makes no difference to the internal padding of the control. Also for information, the button I'm using is a control I've inherited from the Windows.Forms.Button class, as I need to add a few properties, however I haven't interfered with any of the Button's own methods.

like image 941
Bryan Avatar asked May 24 '11 07:05

Bryan


5 Answers

On compatible WinForms controls you can also try setting the UseCompatibleTextRendering property to true. It uses the Graphics class instead of the default TextRenderer class for text rendering. While it worked for my specific application, your mileage may vary.

At least one con to this approach is the apparent font size seemed to change (reduced in my case).

Learn more here: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.label.usecompatibletextrendering?view=netframework-4.8

like image 166
pigeon Avatar answered Nov 02 '22 02:11

pigeon


You don't have to draw the whole button yourself. Just leave Text property empty and assign your text to OwnerDrawText

public class NoPaddingButton : Button
{
    private string ownerDrawText;
    public string OwnerDrawText
    {
        get { return ownerDrawText; }
        set { ownerDrawText = value; Invalidate(); }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        if (string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(ownerDrawText))
        {
            StringFormat stringFormat = new StringFormat();
            stringFormat.Alignment = StringAlignment.Center;
            stringFormat.LineAlignment = StringAlignment.Center;

            e.Graphics.DrawString(ownerDrawText, Font, new SolidBrush(ForeColor), ClientRectangle, stringFormat);
        }
    }
}
like image 38
chiper Avatar answered Nov 02 '22 02:11

chiper


You also simply override the OnPaint() method of the Button control from which you're inheriting, and omit to call base.OnPaint(), and replace it with your own draw code.

    protected override void OnPaint(PaintEventArgs pevent)
    {
        //omit base.OnPaint completely...

        //base.OnPaint(pevent); 

        using (Pen p = new Pen(BackColor))
        {
            pevent.Graphics.FillRectangle(p.Brush, ClientRectangle);
        }

        //add code here to draw borders...

        using (Pen p = new Pen(ForeColor))
        {
            pevent.Graphics.DrawString("Hello World!", Font, p.Brush, new PointF(0, 0));
        }
    }
like image 40
helloserve Avatar answered Nov 02 '22 04:11

helloserve


I have created a successful radio automation application back then in '98 using MFC. First thing we did is that we created whole new set of GUI controls for it, since for example, pressing the button on the screen with the finger obscures it, and standard buttons aren't so fancy for it.

fireplay image

My advice would be not to go with deriving your button from standard WinForms button, but from the Control and do the drawing yourself. If it is the simple button like one you presented, you won't have much to do, just DrawString, and if it is somewhat more complicated, you'll have complete control over it.

like image 38
Daniel Mošmondor Avatar answered Nov 02 '22 02:11

Daniel Mošmondor


@Bryan - both solutions proposed by @Henk Roux and @chiper are not perfect. First generate button without any visual attributes and second forces us to add new attribute like OwnerDrawText.

See my proposition below. I override Text property to be able to use its private part _Text and attach String.Empty just before MyBase.OnPaint(e) event. This makes that button is draw without text. Later on I reassign back old text to the private property and draw string myself. I add Inflate to Rectangle to make text nicer just touching border of button, not overlapping it. My proposition works with any flatstyle.

Here is comparison of standard and no padding button in two flatstyles: standard and flat

Imports System.ComponentModel
Imports System.Drawing
Imports System.Windows.Forms

Public Class ButtonNoPadding
    Inherits Button

    Private _textCurrent As String
    Private _Text As String

    <Category("Appearance")>
    Public Overrides Property Text() As String
        Get
            Return _Text
        End Get
        Set(ByVal value As String)
            If value <> _Text Then
                _Text = value
                Invalidate()
            End If
        End Set
    End Property

    Protected Overrides Sub OnPaint(e As PaintEventArgs)

        _textCurrent = Text
        _Text = String.Empty
        MyBase.OnPaint(e)
        _Text = _textCurrent

        Using brush = New SolidBrush(ForeColor)
            Using stringFormat = New StringFormat() With {.Alignment = StringAlignment.Center, .LineAlignment = StringAlignment.Center}
                e.Graphics.DrawString(Text, Font, brush, Rectangle.Inflate(ClientRectangle, -2, -2), stringFormat)
            End Using
        End Using

    End Sub

End Class

C# version:

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

public class ButtonNoPadding : Button
{

    private string _textCurrent;

    private string _Text;
    [Category("Appearance")]
    public override string Text {
        get { return _Text; }
        set {
            if (value != _Text) {
                _Text = value;
                Invalidate();
            }
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        _textCurrent = Text;
        _Text = string.Empty;
        base.OnPaint(e);
        _Text = _textCurrent;

        using (var brush = new SolidBrush(ForeColor)) {
            using (var stringFormat = new StringFormat {Alignment = StringAlignment.Center,LineAlignment = StringAlignment.Center}) {
                e.Graphics.DrawString(Text, Font, brush, Rectangle.Inflate(ClientRectangle, -2, -2), stringFormat);
            }
        }

    }

}
like image 2
yarecky Avatar answered Nov 02 '22 02:11

yarecky