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:
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 notic开发者_StackOverflow中文版ed 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.
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);
}
}
}
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));
}
}
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.
@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);
}
}
}
}
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
精彩评论