带文字的半透明圆形控件 [英] Translucent circular Control with text

查看:86
本文介绍了带文字的半透明圆形控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个项目,其中我需要添加一个圆形的控件,中间有一些文本。

我的问题是,当我调整大小时,圆圈太小了,它与其他控件重叠。我想绘制与正方形相同的宽度。

否则。如何使控件的背景透明?



我正在使用以下代码:

 受保护的覆盖无效OnPaint(PaintEventArgs e)
{
base.OnPaint(e);

使用(位图位图=新的位图(this.Width,this.Height))
{
使用(Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.Clear(this.BackColor);

使用(SolidBrush笔刷=新的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)),字体,FontColor,Convert.ToInt32((Width / 2-MS.Width / 2)+ 2),Convert .ToInt32((高度/ 2-MS。高度/ 2)+ 3));
bitmap.MakeTransparent(this.BackColor);
e.Graphics.DrawImage(bitmap,0,0);

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


解决方案

这是从标准 Label 派生而来的自定义控件,可以将其设为半透明。

接口是一个彩色圆圈,可以包含几个数字。


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


不透明度 :控件的不透明度 BackGround [0,255]

InnerPadding :内部矩形之间的距离,用于定义圆边界和控件边界。

FontPadding :文本与内部矩形之间的距离。


获得透明度覆盖

很明显, ScreenToGif 会忽略完全不透明的像素变化。

认为没有任何变化,因此优化它什么也没显示。


注意:

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

 使用系统; 
使用System.Drawing;
使用System.Drawing.Drawing2D;
使用System.Drawing.Text;
使用System.Globalization;
使用System.Runtime.CompilerServices;
使用System.Windows.Forms;

[DesignerCategory(代码))
类RoundCenterLabel:标签,INotifyPropertyChanged
{
内部const int WS_EX_TRANSPARENT = 0x00000020;
内部只读int internalFontPadding = 4;
内部字体m_CustomFont = null;
内部颜色m_BackGroundColor;
internal int m_InnerPadding = 0;
internal int m_FontPadding = 25;
internal int m_Opacity = 128;

公共事件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;
}

受保护的覆盖CreateParams CreateParams
{
get {
CreateParams cp = base.CreateParams;
cp.ExStyle | = WS_EX_TRANSPARENT;
return cp;
}
}

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

公共替代字符串文本{
get => base.Text;
set {base.Text = value;
NotifyPropertyChanged();
}
}

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

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

public int不透明度{
get => this.m_Opacity;
set {this.m_Opacity = CheckValue(value,0,255);
UpdateBackColor(this.m_BackGroundColor);
NotifyPropertyChanged();
}
}

公共优先级Color BackColor {
get => this.m_BackGroundColor;
set {UpdateBackColor(value);
NotifyPropertyChanged();
}
}

受保护的覆盖无效OnLayout(LayoutEventArgs e){
base.OnLayout(e);
base.AutoSize = false;
}

private void NotifyPropertyChanged([CallerMemberName] string PropertyName = null)
{
this.Parent?.Invalidate(this.Bounds,true);
this.Invalidate();
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(PropertyName));
}

受保护的覆盖无效OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;

使用(var format = new StringFormat(StringFormatFlags.LineLimit | StringFormatFlags.NoWrap,CultureInfo.CurrentUICulture.LCID)){
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Center;

使用(var circleBrush = new SolidBrush(this.m_BackGroundColor))
使用(var 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);
};
};
}

私人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);
返回新的RectangleF(position,size);
}

private void FontAdapter(字体,浮点Dpi)
{
RectangleF rect = InnerRectangle();
float FontSize = CheckValue((int)(rect.Height-this.m_FontPadding),6,
(int)(rect.Height-this.m_FontPadding))/(Dpi / 72.0F)-internalFontPadding ;
使用(字体customfont =新字体(font.FontFamily,FontSize,font.Style,GraphicsUnit.Pixel)){
this.m_CustomFont =(字体)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)
=> (值<最小值)?最小值:((值>最大值)?最大值:值);

私有元组< float,float> GetMinMax(ValueType Value1,ValueType Value2)
{
if(((Value1是Enum)||((Value1.GetType()。IsNested)))返回null;
if(((Value2是Enum)||(Value2.GetType()。IsNested))返回null;
返回新的元组< float,float>(
Math.Min(Convert.ToSingle(Value1),Convert.ToSingle(Value2)),
Math.Max(Convert.ToSingle(Value1) ,Convert.ToSingle(Value2))
);
}
}


I am working on a project wherein I need to add a Control with the shape of a Circle with some text in the middle.
My problem is the circle is too small, when I resize it, it overlaps other controls. I want to draw the circle same width as the square.
Otherwise. how can I make the Control's background transparent?

I am using the code below:

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();
        }
    }
}

解决方案

This is a Custom Control derived from a standard Label, which can be made translucent.
The interface is a colored circle which can contain a couple of numbers.

The Control exposes these custom properties:

Opacity: The level of opacity of the control BackGround [0, 255]
InnerPadding: The distance between the inner rectangle, which defines the circle bounds and the control bounds.
FontPadding: The distance between the Text and the Inner rectangle.

Transparency is obtained overriding CreateParams, then setting ExStyle |= WS_EX_TRANSPARENT;

The Control.SetStyle() method is used to modify the control behaviour, adding these ControlStyles:

ControlStyles.Opaque: prevents the painting of a Control's BackGround, so it's not managed by the System. Combined with CreateParams to set the Control's Extende Style to WS_EX_TRANSPARENT, the Control becomes completely transparent.

ControlStyles.SupportsTransparentBackColor the control accepts Alpha values for it's BackGround color. Without also setting ControlStyles.UserPaint it won't be used to simulate transparency. We're doing that ourselves with other means.


To see it at work, create a new Class file, substitute all the code inside with this code preserving the NameSpace and build the Project/Solution.
The new Custom Control will appear in the ToolBox. Drop it on a Form. Modify its custom properties as needed.

A visual representation of the control:


Apparently, ScreenToGif ignores the Pixel change on full opacity.
In its opinion nothing changes, so it optimizes it showing nothing.

Note:
I didn't use TextRenderer here because of its padding. It's harder to control in this context: the vertical center position needs to be adjusted and it doesn't provide any quality enhancements.

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

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

    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;
    }

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

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

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

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

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

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

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

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

    private void NotifyPropertyChanged([CallerMemberName] string PropertyName = null)
    {
        this.Parent?.Invalidate(this.Bounds, true);
        this.Invalidate();
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;

        using (var format = new StringFormat(StringFormatFlags.LineLimit | StringFormatFlags.NoWrap, CultureInfo.CurrentUICulture.LCID)) {
            format.LineAlignment = StringAlignment.Center;
            format.Alignment = StringAlignment.Center;

            using (var circleBrush = new SolidBrush(this.m_BackGroundColor))
            using (var 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) - internalFontPadding;
        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) 
        => (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))
        );
    }
}

这篇关于带文字的半透明圆形控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆