我正在尝试构建自定义用户控件,它将在winforms Button中显示Font Awesome Glyphs 我发现GitHub repo具有类似的控制权,但我想用Button作为我控制的基础 我能够显示字形,但我无法正确对齐:
绿色虚线显示按钮大小,蓝色线条表示控制中心,红色线条显示graphics.MeasureString
正在返回的矩形。
我的OnPaint
方法如下所示:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var graphics = e.Graphics;
// Set best quality
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
if(!DesignMode)
{
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.SmoothingMode = SmoothingMode.HighQuality;
}
var letter = char.ConvertFromUtf32((int)_icon);
Brush b;
if (!Enabled)
{
b = Brushes.LightGray;
}
else if (_mouseDown)
{
b = new SolidBrush(_clickColor);
}
else if (_mouseOver)
{
b = new SolidBrush(_hoverColor);
}
else
{
b = new SolidBrush(ForeColor);
}
SizeF s = graphics.MeasureString(letter, new Font(Fonts.Families[0], _iconSize, GraphicsUnit.Point), Width);
float w = s.Width;
float h = s.Height;
// center icon
float left = Padding.Left + (Width - w)/2;
float top = Padding.Top + (Height - h)/2;
if (DesignMode)
{
graphics.DrawRectangle(Pens.Red, top, left, w, h);
}
graphics.DrawString(letter, new Font(Fonts.Families[0], _iconSize, GraphicsUnit.Point), b, new PointF(left, top));
if (DesignMode)
{
var pen = new Pen(_hoverColor, 1) { DashStyle = DashStyle.Dash, Alignment = PenAlignment.Inset };
graphics.DrawRectangle(pen, Padding.Left, Padding.Top, Width - Padding.Left - Padding.Right - 1, Height - Padding.Top - Padding.Bottom - 1);
graphics.DrawLine(Pens.Blue, Padding.Left, Padding.Top, Width - Padding.Left, Height - Padding.Top);
graphics.DrawLine(Pens.Blue, Width - Padding.Left, Padding.Top, Padding.Left, Height - Padding.Top);
}
}
我尝试使用this question的解决方案,但没有任何运气。
如何在我的控制精确中心绘制单个字符(字形)(控制中心和字形中心应对齐)
以下是我控制的代码:
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace MyControls
{
class FontButton:Button
{
#region Public
public FontButton()
{
base.FlatStyle = FlatStyle.Flat;
base.FlatAppearance.BorderSize = 0;
base.FlatAppearance.MouseOverBackColor = Color.Transparent;
base.FlatAppearance.MouseDownBackColor = Color.Transparent;
base.Text = "";
base.MinimumSize = new Size(32,32);
Size = new Size(32,32);
_hoverColor = Color.FromArgb(144, 188, 0);
_clickColor = Color.Green;
_icon=IconType.Android;
_iconSize = 40;
}
private int _iconSize;
[DefaultValue(typeof(int), "40"), Category("Appearance"), Description("Icon size in points")]
public int IconSize
{
get { return _iconSize; }
set
{
_iconSize = value;
Invalidate();
}
}
private Color _hoverColor;
[DefaultValue(typeof(Color), "144, 188, 0"), Category("Appearance"), Description("Color when mouse over")]
public Color HoverColor
{
get { return _hoverColor; }
set
{
_hoverColor = value;
Invalidate();
}
}
private Color _clickColor;
[DefaultValue(typeof(Color), "Green"), Category("Appearance"), Description("Color when mouse click")]
public Color ClickColor
{
get { return _clickColor; }
set
{
_clickColor = value;
Invalidate();
}
}
private IconType _icon;
[DefaultValue(typeof(IconType), "Android"), Category("Appearance"), Description("Icon")]
public IconType Icon
{
get { return _icon; }
set
{
_icon = value;
Invalidate();
}
}
#endregion
#region Static
static FontButton()
{
InitialiseFont();
}
#region NATIVE
[DllImport("gdi32.dll")]
private static extern IntPtr AddFontMemResourceEx(byte[] pbFont, int cbFont, IntPtr pdv, out uint pcFonts);
#endregion
private static readonly PrivateFontCollection Fonts = new PrivateFontCollection();
private static void InitialiseFont()
{
try
{
byte[] fontdata = ImageButtonTest.Properties.Resources.fontawesome_webfont;
IntPtr ptrFont = Marshal.AllocCoTaskMem(fontdata.Length);
uint cFonts;
AddFontMemResourceEx(fontdata, fontdata.Length, IntPtr.Zero, out cFonts);
Marshal.Copy(fontdata, 0, ptrFont, fontdata.Length);
Fonts.AddMemoryFont(ptrFont, fontdata.Length);
Marshal.FreeCoTaskMem(ptrFont);
}
catch (Exception)
{
Debug.WriteLine("Error");
throw;
}
}
#endregion
#region Overrides
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var graphics = e.Graphics;
// Set best quality
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
if(!DesignMode)
{
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.SmoothingMode = SmoothingMode.HighQuality;
}
var letter = char.ConvertFromUtf32((int)_icon);//char.ConvertFromUtf32(0xf190);
Brush b;
if (!Enabled)
{
b = Brushes.LightGray;
}
else if (_mouseDown)
{
b = new SolidBrush(_clickColor);
}
else if (_mouseOver)
{
b = new SolidBrush(_hoverColor);
}
else
{
b = new SolidBrush(ForeColor);
}
SizeF s = graphics.MeasureString(letter, new Font(Fonts.Families[0], _iconSize, GraphicsUnit.Point), Width);
//SizeF s = TextRenderer.MeasureText(letter, new Font(Fonts.Families[0], _iconSize, GraphicsUnit.Point), new Size(20, 20), TextFormatFlags.NoPadding);
//Debug.WriteLine(stringSize);
//Debug.WriteLine(s);
float w = s.Width;
float h = s.Height;
// center icon
float left = Padding.Left + (Width - w)/2;
float top = Padding.Top + (Height - h)/2;
if (DesignMode)
{
graphics.DrawRectangle(Pens.Red, top, left, w, h);
}
graphics.DrawString(letter, new Font(Fonts.Families[0], _iconSize, GraphicsUnit.Point), b, new PointF(left, top));
if (DesignMode)//Process.GetCurrentProcess().ProcessName == "devenv")
{
var pen = new Pen(_hoverColor, 1) { DashStyle = DashStyle.Dash, Alignment = PenAlignment.Inset };
graphics.DrawRectangle(pen, Padding.Left, Padding.Top, Width - Padding.Left - Padding.Right - 1, Height - Padding.Top - Padding.Bottom - 1);
graphics.DrawLine(Pens.Blue, Padding.Left, Padding.Top, Width - Padding.Left, Height - Padding.Top);
graphics.DrawLine(Pens.Blue, Width - Padding.Left, Padding.Top, Padding.Left, Height - Padding.Top);
}
}
private bool _mouseOver;
protected override void OnMouseEnter(EventArgs e)
{
_mouseOver = true;
base.OnMouseEnter(e);
}
protected override void OnMouseLeave(EventArgs e)
{
_mouseOver = false;
base.OnMouseLeave(e);
}
private bool _mouseDown;
protected override void OnMouseDown(MouseEventArgs e)
{
_mouseDown = true;
base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
_mouseDown = false;
base.OnMouseUp(e);
}
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new FlatStyle FlatStyle { get; set; }
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new FlatButtonAppearance FlatAppearance { get; set; }
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new string Text { get; set; }
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new Size MinimumSize { get; set; }
#endregion
}
}
和IconType
枚举:
namespace MyControls
{
public enum IconType
{
Adjust = 0xf042,
Adn = 0xf170,
AlignCenter = 0xf037,
AlignJustify = 0xf039,
AlignLeft = 0xf036,
AlignRight = 0xf038,
Ambulance = 0xf0f9,
Anchor = 0xf13d,
Android = 0xf17b,
ArrowCircleDown = 0xf0ab,
ArrowCircleLeft = 0xf0a8,
ArrowCircleODown = 0xf01a,
ArrowCircleOLeft = 0xf190,
ArrowCircleORight = 0xf18e,
ArrowCircleOUp = 0xf01b,
ArrowCircleRight = 0xf0a9,
ArrowCircleUp = 0xf0aa,
ArrowDown = 0xf063,
ArrowLeft = 0xf060,
ArrowRight = 0xf061,
ArrowUp = 0xf062,
Arrows = 0xf047,
ArrowsAlt = 0xf0b2,
ArrowsH = 0xf07e,
ArrowsV = 0xf07d,
User = 0xf007,
UserMd = 0xf0f0,
Users = 0xf0c0,
Stop = 0xf04d
}
}
所有需要的是在资源中包含fontawesome_webfont.ttf。
答案 0 :(得分:1)
这是MSDN:
MeasureString方法设计用于单个字符串 并包括字符串前后的少量额外空间 允许悬垂的字形。此外,DrawString方法调整 字形指向优化显示质量并可能显示字符串 比MeasureString报告的要窄。获得适合的指标 对于布局中的相邻字符串(例如,实现时) 格式化文本),使用MeasureCharacterRanges方法或其中之一 采用StringFormat并传递的MeasureString方法 GenericTypographic。还要确保Graphics的TextRenderingHint 是AntiAlias。
所以要让MeasureString
省略GenericTypographic
这样的所有额外空格:
SizeF s = graphics.MeasureString(letter, new Font(Fonts.Families[0],
_iconSize, GraphicsUnit.Point), Width, StringFormat.GenericTypographic);
我发现这对我有很大的帮助,虽然我没有像你那样精确地做到这一点。
答案 1 :(得分:0)
我使用GraphicsPath
获得了最佳结果:
var path = new GraphicsPath()
path.AddString(_letter, font.FontFamily, (int) font.Style, font.Size, new Point(0, 0), StringFormat.GenericTypographic);
Rectangle area = Rectangle.Round(path.GetBounds());