c# - Circulo translucido con texto
winforms transparency (1)
Este es un control personalizado derivado de una
Label
estándar, que puede hacerse translúcida.
La interfaz es un círculo de color que puede contener un par de números.
El Control expone estas propiedades personalizadas:
Opacity
: el nivel de opacidad del control
BackGround
[0, 255]
InnerPadding
: la distancia entre el rectángulo interior, que define los límites del círculo y los límites del control.
FontPadding
: la distancia entre el texto y el rectángulo interior.
La transparencia se obtiene anulando
CreateParams
, luego configurando
ExStyle |= WS_EX_TRANSPARENT;
El método
Control.SetStyle()
se usa para modificar el comportamiento del control, agregando estos
ControlStyles
:
ControlStyles.Opaque
evita la pintura del control de
BackGround
, por lo que no es administrado por el sistema.
ControlStyles.SupportsTransparentBackColor
el control acepta valores Alpha para su color de fondo.
El nuevo control personalizado aparecerá en la caja de herramientas.
Colóquelo en un formulario. Modificar sus propiedades personalizadas según sea necesario.
Una representación visual del control:
Al parecer,
ScreenToGif
ignora el cambio de píxel en la opacidad total.
En su opinión nada cambia, por lo que lo
optimizes
mostrando nada.
Nota:
No
TextRenderer
aquí debido a su relleno.
Es más difícil de controlar en este contexto: la posición central vertical debe ajustarse y no ofrece mejoras de calidad
.
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;
}
}
}
Estoy trabajando en un proyecto en el que necesito agregar un Círculo con texto en el medio. Estoy usando el código de abajo. Pero mi problema es que el círculo es demasiado pequeño, cuando lo redimensiono, se superpone a otro control. Quiero dibujar el círculo con el mismo ancho que el cuadrado o ¿cómo se volverá transparente el fondo?
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();
}
}
}