带有文字的半透明圆圈

时间:2018-07-18 08:03:31

标签: c# winforms transparency

我正在一个项目中,我需要在中间添加一个带有文本的Circle。我正在使用下面的代码。但是我的问题是圆圈太小,当我调整它的大小时,它与其他控件重叠。我想绘制与正方形相同的宽度,或者如何使背景透明?

enter image description here

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    using (Bitmap bitmap = new Bitmap(this.Width, this.Height))
    {
        using (Graphics graphics = Graphics.FromImage(bitmap))
        {
            graphics.SmoothingMode = SmoothingMode.HighQuality;
            graphics.Clear(this.BackColor);

            using (SolidBrush brush = new SolidBrush(this._FillColor))
            {                      
                graphics.FillEllipse(brush, 0x18 - 6, 0x18 - 6, (this.Width - 0x30) + 12, (this.Height - 0x30) + 12);
            }

            Brush FontColor = new SolidBrush(this.ForeColor);
            SizeF MS = graphics.MeasureString(Convert.ToString(Convert.ToInt32((100 / _Maximum) * _Value)), Font);
            graphics.DrawString(Convert.ToString(Convert.ToInt32((100 / _Maximum) * _Value)), Font, FontColor, Convert.ToInt32((Width / 2 - MS.Width / 2) + 2), Convert.ToInt32((Height / 2 - MS.Height / 2) + 3));
            bitmap.MakeTransparent(this.BackColor);
            e.Graphics.DrawImage(bitmap, 0, 0);

            graphics.Dispose();
            bitmap.Dispose();
        }
    }
}

1 个答案:

答案 0 :(得分:6)

这是从标准Label派生的自定义控件,可以将其设为半透明。
界面是一个彩色圆圈,其中可以包含几个数字。

该控件公开了以下自定义属性:

Opacity :控件BackGround [0, 255]
的不透明度 InnerPadding :内部矩形之间的距离,该矩形定义了圆形边界和控件边界。
FontPadding :“文本”和“内部矩形”之间的距离。

已获得覆盖CreateParams的透明度,然后设置了ExStyle |= WS_EX_TRANSPARENT;

Control.SetStyle()方法用于修改控件行为,并添加以下ControlStyles

ControlStyles.Opaque 阻止绘制控件BackGround,因此它不受系统管理。
ControlStyles.SupportsTransparentBackColor 控件接受BackGround颜色的Alpha值。


要在工作中看到它,请创建一个新的Class文件,用此代码保留名称空间替换其中的所有代码,然后构建Project / Solution。
新的自定义控件将出现在工具箱中。
将其放在窗体上。根据需要修改其自定义属性。

控件的直观表示形式:

WinForms Translucent Label
显然,ScreenToGif在完全不透明时会忽略像素变化。
它认为没有任何变化,因此optimizes没有任何变化。

注意:
由于填充,我在这里没有使用TextRenderer。在这种情况下很难控制:垂直中心位置需要调整,并且没有提供任何质量增强功能。

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Globalization;
using System.Windows.Forms;

[DesignerCategory("Code")]
class RoundCenterLabel : Label, INotifyPropertyChanged
{
    internal const int WS_EX_TRANSPARENT = 0x00000020;
    internal Font m_CustomFont = null;
    internal Color m_BackGroundColor;
    internal int m_InnerPadding = 0;
    internal int m_FontPadding = 25;
    internal int m_Opacity = 128;
    private readonly int fontPadding = 8;

    public event PropertyChangedEventHandler PropertyChanged;

    public RoundCenterLabel() => InitializeComponent();

    private void InitializeComponent()
    {
        this.SetStyle(ControlStyles.Opaque |
                      ControlStyles.SupportsTransparentBackColor |
                      ControlStyles.ResizeRedraw, true);
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
        this.m_CustomFont = new Font("Segoe UI", 50, FontStyle.Regular, GraphicsUnit.Pixel);
        this.BackColor = Color.LimeGreen;
        this.ForeColor = Color.White;
    }

    private void NotifyPropertyChanged(string PropertyName)
    {
        this.Invalidate();
        this.FindForm()?.Refresh();
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
    }

    public new Font Font
    {
        get => this.m_CustomFont;
        set { this.m_CustomFont = value;
              FontAdapter(value, this.DeviceDpi);
              NotifyPropertyChanged(nameof(this.Font));
        }
    }

    public override string Text {
        get => base.Text;
        set { base.Text = value;
              NotifyPropertyChanged(nameof(this.Text));
        }
    }

    public int InnerPadding {
        get => this.m_InnerPadding;
        set { this.m_InnerPadding = CheckValue(value, 0, this.ClientRectangle.Height - 10);
              NotifyPropertyChanged(nameof(this.InnerPadding)); }
    }

    public int FontPadding {
        get => this.m_FontPadding;
        set { this.m_FontPadding = CheckValue(value, 0, this.ClientRectangle.Height - 10);
              NotifyPropertyChanged(nameof(this.FontPadding));
        }
    }

    public int Opacity {
        get => this.m_Opacity;
        set { this.m_Opacity = CheckValue(value, 0, 255);
              UpdateBackColor(this.m_BackGroundColor);
              NotifyPropertyChanged(nameof(this.Opacity));
        }
    }

    public override Color BackColor {
        get => this.m_BackGroundColor;
        set { UpdateBackColor(value);
              NotifyPropertyChanged(nameof(this.BackColor));
        }
    }

    protected override void OnLayout(LayoutEventArgs e)
    {
        base.OnLayout(e);
        base.AutoSize = false;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        using (StringFormat format = new StringFormat(StringFormatFlags.LineLimit | StringFormatFlags.NoWrap, CultureInfo.CurrentUICulture.LCID))
        {
            format.LineAlignment = StringAlignment.Center;
            format.Alignment = StringAlignment.Center;

            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
            using (SolidBrush circleBrush = new SolidBrush(this.m_BackGroundColor))
            using (SolidBrush foreBrush = new SolidBrush(this.ForeColor))
            {
                this.FontAdapter(this.m_CustomFont, e.Graphics.DpiY);
                RectangleF rect = InnerRectangle();
                e.Graphics.FillEllipse(circleBrush, rect);
                e.Graphics.DrawString(this.Text, this.m_CustomFont, foreBrush, rect, format);
            };
        };
    }

    private RectangleF InnerRectangle()
    {
        Tuple<float, float> refSize = GetMinMax(this.ClientRectangle.Height, this.ClientRectangle.Width);
        SizeF size = new SizeF(refSize.Item1 - (this.m_InnerPadding / 2), 
                               refSize.Item1 - (this.m_InnerPadding / 2));
        PointF position = new PointF((this.ClientRectangle.Width - size.Width) / 2,
                                     (this.ClientRectangle.Height - size.Height) / 2);
        return new RectangleF(position, size);
    }

    private void FontAdapter(Font font, float Dpi)
    {
        RectangleF rect = InnerRectangle();
        float FontSize = CheckValue((int)(rect.Height - this.m_FontPadding), 6, 
                                    (int)(rect.Height - this.m_FontPadding)) / (Dpi / 72.0F) - fontPadding;
        using (Font customfont = new Font(font.FontFamily, FontSize, font.Style, GraphicsUnit.Pixel))
            this.m_CustomFont = (Font)customfont.Clone();
    }

    private void UpdateBackColor(Color color)
    {
        this.m_BackGroundColor = Color.FromArgb(this.m_Opacity, Color.FromArgb(color.R, color.G, color.B));
        base.BackColor = this.m_BackGroundColor;
    }

    private int CheckValue(int Value, int Min, int Max)
    {
        return (Value < Min) ? Min : ((Value > Max) ? Max : Value);
    }

    private Tuple<float, float> GetMinMax(ValueType Value1, ValueType Value2)
    {
        if ((Value1 is Enum) || (Value1.GetType().IsNested)) return null;
        if ((Value2 is Enum) || (Value2.GetType().IsNested)) return null;
        return new Tuple<float, float>(Math.Min(Convert.ToSingle(Value1), Convert.ToSingle(Value2)),
                                       Math.Max(Convert.ToSingle(Value1), Convert.ToSingle(Value2)));
    }

    protected override CreateParams CreateParams 
    {
        get
        {
            CreateParams parameters = base.CreateParams;
            parameters.ExStyle |= WS_EX_TRANSPARENT;
            return parameters;
        }
    }
}