Reduce Padding Around Text in WinForms Button

2019-02-08 14:55发布

问题:

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:

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.

回答1:

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


回答2:

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


回答3:

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.

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.



回答4:

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

    }

}