【问题标题】:Draw text with overlay in center of rectangle (ProgressBar)在矩形中心绘制带有叠加层的文本(ProgressBar)
【发布时间】:2015-12-03 16:24:16
【问题描述】:

我正在扩展内置进度条,能够以百分比显示进度,如下所示:

我正在尝试将叠加层添加到显示的文本中,这样它会更具可读性。我已设法添加它,但现在我的文本未对齐:

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。 文字向右下角移动了一点。

下面是我的控件有和没有覆盖的比较:

【问题讨论】:

  • 当您提供位置时,而不是使用表单的高度和宽度,将面板添加到表单并将 DockStyle 更改为“填充”,然后使用此面板的高度和宽度。
  • @Rariolu 我正在扩展 ProgressBar 控件,所以没有表单。我将在我的问题中添加完整代码

标签: c# .net gdi+


【解决方案1】:

我建议你通过 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); // !!!

这种方法可以摆脱任何测量和位置计算,并且始终使事物与我正确对齐。

【讨论】:

  • 谢谢你!我唯一添加的是Trimming = StringTrimming.None, FormatFlags = StringFormatFlags.NoWrap 进行格式化。我试过用 p.Transform 做类似的事情,但你的解决方案更好更容易。
  • 我已将Font.Size 更改为Font.Height
  • 使用Font.Height是不正确的,因为它应该是em-Size(包围字符的em方形框的高度)。请查看我的更新答案。
  • 我不知道 em-Size(它应该在 AddString 中使用),已经在我的代码中修复了。感谢您的帮助!
猜你喜欢
  • 2011-10-23
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-07
  • 1970-01-01
  • 2021-06-30
相关资源
最近更新 更多