在矩形中心绘制带有叠加层的文本 (ProgressBar)
Draw text with overlay in center of rectangle (ProgressBar)
我正在扩展内置进度条,使其能够以百分比形式显示进度,如下所示:
我正在尝试为显示的文本添加叠加层,以使其更具可读性。我已经成功添加了它,但现在我的文字错位了:
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x000F)
{
using (Graphics graphics = CreateGraphics())
using (var brush = new SolidBrush(ForeColor))
{
var newText = Math.Floor(((float) Value/Maximum)*100).ToString(CultureInfo.InvariantCulture) + '%';
SizeF textSize = graphics.MeasureString(newText, Font);
graphics.InterpolationMode = InterpolationMode.High;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
graphics.CompositingQuality = CompositingQuality.HighQuality;
if (Overlay)
{
var p = new GraphicsPath();
p.AddString(
newText,
Font.FontFamily,
(int) Font.Style,
Font.SizeInPoints,
new Point((int) ((Width - textSize.Width)/2), (int) ((Height - textSize.Height)/2)),
StringFormat.GenericDefault);
graphics.FillPath(brush, p);
graphics.DrawPath(new Pen(Brushes.Black, 1), p);
}
else
{
graphics.DrawString(newText, Font, brush, (Width - textSize.Width) / 2, (Height - textSize.Height) / 2);
}
}
}
}
在使用 g.DrawPath
而不是 g.DrawString
时如何修复文本大小和对齐方式。
理想情况下,我想从第一个屏幕获取文本,但有覆盖。
下面是我的控件的完整代码:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Globalization;
using System.Windows.Forms;
namespace Misiu.Controls
{
public sealed class ProgressBarWithText : ProgressBar
{
public ProgressBarWithText()
{
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
ForeColor = Color.White;
BackColor = Color.Black;
}
protected override CreateParams CreateParams
{
get
{
CreateParams result = base.CreateParams;
if (Environment.OSVersion.Platform == PlatformID.Win32NT
&& Environment.OSVersion.Version.Major >= 6)
{
result.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
}
return result;
}
}
public bool Overlay { get; set; }
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x000F)
{
using (Graphics graphics = CreateGraphics())
using (var brush = new SolidBrush(ForeColor))
{
var newText = string.Empty;
switch (DisplayStyle)
{
case ProgressBarDisplayStyle.ValueAndMax:
newText = string.Format("{0}/{1}", Value, Maximum);
break;
case ProgressBarDisplayStyle.Text:
newText = Text;
break;
case ProgressBarDisplayStyle.Percentage:
newText = Math.Floor(((float) Value/Maximum)*100).ToString(CultureInfo.InvariantCulture) + '%';
break;
}
//var newText1 = DisplayStyle == ProgressBarDisplayStyle.Percentage ? Value == 0 ? "0%" : Math.Floor(((float)Value / Maximum) * 100).ToString(CultureInfo.InvariantCulture) + '%' : DisplayStyle == ProgressBarDisplayStyle.ValueAndMax ? string.Format("{0}/{1}", Value,Maximum) : Text;
SizeF textSize = graphics.MeasureString(newText, Font);
graphics.InterpolationMode = InterpolationMode.High;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
graphics.CompositingQuality = CompositingQuality.HighQuality;
//graphics.SmoothingMode = SmoothingMode.AntiAlias;
if (Overlay)
{
var p = new GraphicsPath();
p.AddString(
newText,
Font.FontFamily,
(int) Font.Style,
Font.SizeInPoints,
new Point((int) ((Width - textSize.Width)/2), (int) ((Height - textSize.Height)/2)),
StringFormat.GenericDefault);
graphics.FillPath(brush, p);
graphics.DrawPath(new Pen(Brushes.Black, 1), p);
}
else
{
graphics.DrawString(newText, Font, brush, (Width - textSize.Width)/2, (Height - textSize.Height)/2);
}
}
}
}
private ProgressBarDisplayStyle _displayStyle = ProgressBarDisplayStyle.Percentage;
//Property to set to decide whether to print a % or Text
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
public ProgressBarDisplayStyle DisplayStyle
{
get { return _displayStyle; }
set
{
if (_displayStyle == value) return;
_displayStyle = value;
Refresh();
}
}
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
public override string Text
{
get { return base.Text; }
set
{
base.Text = value;
Refresh();
}
}
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
public override Font Font
{
get { return base.Font; }
set
{
base.Font = value;
Refresh();
}
}
}
public enum ProgressBarDisplayStyle
{
Percentage,
ValueAndMax,
Text
}
}
编辑:
感谢@Hans Passant,大部分问题已经解决,但文本仍然有点错位,如下所示:
左侧进度条使用 Lucida Handwriting, 30pt, style=Bold
,右侧进度条使用 `Microsoft Sans Serif,20pt。
文本向右下角移动了一点。
下面是我的控件有无覆盖的比较:
我建议您通过 StringFormat 在控件的客户端矩形内对齐整个文本:
StringFormat format = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
float emSize = graphics.DpiY * Font.Size / 72;
var p = new GraphicsPath();
p.AddString(
newText,
Font.FontFamily,
(int)Font.Style,
emSize ,
ClientRectangle, // !!!
format); // !!!
这种方法允许摆脱任何测量和位置计算,它总是使事物正确对齐我。
我正在扩展内置进度条,使其能够以百分比形式显示进度,如下所示:
我正在尝试为显示的文本添加叠加层,以使其更具可读性。我已经成功添加了它,但现在我的文字错位了:
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x000F)
{
using (Graphics graphics = CreateGraphics())
using (var brush = new SolidBrush(ForeColor))
{
var newText = Math.Floor(((float) Value/Maximum)*100).ToString(CultureInfo.InvariantCulture) + '%';
SizeF textSize = graphics.MeasureString(newText, Font);
graphics.InterpolationMode = InterpolationMode.High;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
graphics.CompositingQuality = CompositingQuality.HighQuality;
if (Overlay)
{
var p = new GraphicsPath();
p.AddString(
newText,
Font.FontFamily,
(int) Font.Style,
Font.SizeInPoints,
new Point((int) ((Width - textSize.Width)/2), (int) ((Height - textSize.Height)/2)),
StringFormat.GenericDefault);
graphics.FillPath(brush, p);
graphics.DrawPath(new Pen(Brushes.Black, 1), p);
}
else
{
graphics.DrawString(newText, Font, brush, (Width - textSize.Width) / 2, (Height - textSize.Height) / 2);
}
}
}
}
在使用 g.DrawPath
而不是 g.DrawString
时如何修复文本大小和对齐方式。
理想情况下,我想从第一个屏幕获取文本,但有覆盖。
下面是我的控件的完整代码:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Globalization;
using System.Windows.Forms;
namespace Misiu.Controls
{
public sealed class ProgressBarWithText : ProgressBar
{
public ProgressBarWithText()
{
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
ForeColor = Color.White;
BackColor = Color.Black;
}
protected override CreateParams CreateParams
{
get
{
CreateParams result = base.CreateParams;
if (Environment.OSVersion.Platform == PlatformID.Win32NT
&& Environment.OSVersion.Version.Major >= 6)
{
result.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
}
return result;
}
}
public bool Overlay { get; set; }
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x000F)
{
using (Graphics graphics = CreateGraphics())
using (var brush = new SolidBrush(ForeColor))
{
var newText = string.Empty;
switch (DisplayStyle)
{
case ProgressBarDisplayStyle.ValueAndMax:
newText = string.Format("{0}/{1}", Value, Maximum);
break;
case ProgressBarDisplayStyle.Text:
newText = Text;
break;
case ProgressBarDisplayStyle.Percentage:
newText = Math.Floor(((float) Value/Maximum)*100).ToString(CultureInfo.InvariantCulture) + '%';
break;
}
//var newText1 = DisplayStyle == ProgressBarDisplayStyle.Percentage ? Value == 0 ? "0%" : Math.Floor(((float)Value / Maximum) * 100).ToString(CultureInfo.InvariantCulture) + '%' : DisplayStyle == ProgressBarDisplayStyle.ValueAndMax ? string.Format("{0}/{1}", Value,Maximum) : Text;
SizeF textSize = graphics.MeasureString(newText, Font);
graphics.InterpolationMode = InterpolationMode.High;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
graphics.CompositingQuality = CompositingQuality.HighQuality;
//graphics.SmoothingMode = SmoothingMode.AntiAlias;
if (Overlay)
{
var p = new GraphicsPath();
p.AddString(
newText,
Font.FontFamily,
(int) Font.Style,
Font.SizeInPoints,
new Point((int) ((Width - textSize.Width)/2), (int) ((Height - textSize.Height)/2)),
StringFormat.GenericDefault);
graphics.FillPath(brush, p);
graphics.DrawPath(new Pen(Brushes.Black, 1), p);
}
else
{
graphics.DrawString(newText, Font, brush, (Width - textSize.Width)/2, (Height - textSize.Height)/2);
}
}
}
}
private ProgressBarDisplayStyle _displayStyle = ProgressBarDisplayStyle.Percentage;
//Property to set to decide whether to print a % or Text
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
public ProgressBarDisplayStyle DisplayStyle
{
get { return _displayStyle; }
set
{
if (_displayStyle == value) return;
_displayStyle = value;
Refresh();
}
}
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
public override string Text
{
get { return base.Text; }
set
{
base.Text = value;
Refresh();
}
}
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
public override Font Font
{
get { return base.Font; }
set
{
base.Font = value;
Refresh();
}
}
}
public enum ProgressBarDisplayStyle
{
Percentage,
ValueAndMax,
Text
}
}
编辑:
感谢@Hans Passant,大部分问题已经解决,但文本仍然有点错位,如下所示:
左侧进度条使用 Lucida Handwriting, 30pt, style=Bold
,右侧进度条使用 `Microsoft Sans Serif,20pt。
文本向右下角移动了一点。
下面是我的控件有无覆盖的比较:
我建议您通过 StringFormat 在控件的客户端矩形内对齐整个文本:
StringFormat format = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
float emSize = graphics.DpiY * Font.Size / 72;
var p = new GraphicsPath();
p.AddString(
newText,
Font.FontFamily,
(int)Font.Style,
emSize ,
ClientRectangle, // !!!
format); // !!!
这种方法允许摆脱任何测量和位置计算,它总是使事物正确对齐我。