【问题标题】:Translucent circular Control with text带文字的半透明圆形控件
【发布时间】:2018-12-26 01:24:41
【问题描述】:

我正在做一个项目,我需要添加一个圆形的控件,中间有一些文本。
我的问题是圆圈太小,当我调整它的大小时,它会与其他控件重叠。我想画一个和正方形一样宽的圆。
否则。如何使控件的背景透明?

我正在使用下面的代码:

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

【问题讨论】:

  • 好像你把圈子弄得太小了。您是否尝试过增加 graphics.FillEllipse 的值?
  • 你的圈子和我预期的一样大,它基于你的代码。您的问题是您在 18、18 处绘制它,近似大小为 41x41,但您希望它为 0、0,近似大小为 77x77。在我看来,你需要的只是graphics.FillEllipse(brush, e.ClipRectangle); 没有所有额外的Bitmap 东西等等。
  • @john 谢谢,效果很好。但是我没有删除 Bitmap 的东西,当我删除它时,圆圈没有显示。
  • 我的意思是你为什么不直接使用e.Graphics 而不是创建位图,为位图创建Graphics 的实例,在最后使用e.Graphics 绘制之前绘制所有内容它到控件?
  • 在 winforms 中没有“圆”之类的东西。只有表面由像素组成的控件。还有位图。我们不知道你想做什么。所以真的没有建议做什么最好。要将文本居中放置在位图中,您应该:使用 TextRenderer.DrawText 而不是 Graphics.DrawString b) 绘制到矩形 c) 使用居中的 StringFormat。

标签: c# winforms graphics transparency gdi+


【解决方案1】:

这是一个从Control 派生的自定义控件,可以做成半透明的。
界面是一个彩色圆圈,可以包含几个数字。

控件公开了这些自定义属性:

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

通过覆盖CreateParams 获得透明度,然后设置ExStyle |= WS_EX_TRANSPARENT;

Control.SetStyle()方法用于修改控制行为,添加这些ControlStyles

ControlStyles.Opaque:防止绘制控件的背景,因此它不受系统管理。结合 CreateParams 设置控件的扩展样式为WS_EX_TRANSPARENT,控件变得完全透明。

ControlStyles.SupportsTransparentBackColor 控件接受 Alpha 值,因为它是 BackGround 颜色。如果不设置ControlStyles.UserPaint,它将不会用于模拟透明度。我们正在通过其他方式自己做到这一点。


要查看它的工作情况,请创建一个新的 Class 文件,用此代码替换其中的所有代码保留名称空间并构建项目/解决方案。
新的自定义控件将出现在工具箱中。将其放在表单上。根据需要修改其自定义属性。

控件的可视化表示:

注意和免责声明

  • 这是一个原型控件,缺少自定义设计器(此处无法发布,代码太多,还连接到框架)。
    如此处所述,它可用于完全重叠表单或其他容器中的其他控件。在这个简化的实现中不处理部分重叠。
  • 字体被硬编码为Segoe UI,因为此字体具有简化圆形区域中间文本位置的基线。
    其他字体有不同的基线,需要更复杂的处理。
    请参阅:TextBox with dotted lines for typing 了解基础数学。

using System;
using System.ComponentModel;
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 RoundCenterControl : Control, INotifyPropertyChanged, ISupportInitialize
{
    private const int WS_EX_TRANSPARENT = 0x00000020;
    private readonly int internalFontPadding = 10;
    private bool initializing = false;
    private Font m_CustomFont = null;
    private Color m_BackGroundColor;
    private int m_InnerPadding = 0;
    private int m_FontPadding = 20;
    private int m_Opacity = 128;

    public event PropertyChangedEventHandler PropertyChanged;

    public RoundCenterControl() => InitializeComponent();

    private void InitializeComponent()
    {
        SetStyle(ControlStyles.Opaque |
                 ControlStyles.SupportsTransparentBackColor |
                 ControlStyles.ResizeRedraw, true);
        SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
        BackColor = Color.LimeGreen;
        ForeColor = Color.White;
    }

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

    public new Font Font
    {
        get => m_CustomFont;
        set {
            m_CustomFont = value;
            if (initializing) return;
            FontAdapter(m_CustomFont, DeviceDpi);
            NotifyPropertyChanged();
        }
    }

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

    public int InnerPadding {
        get => m_InnerPadding;
        set {
            m_InnerPadding = value;
            if (initializing) return;
            m_InnerPadding = (int)ValidateRange(value, 0, ClientRectangle.Height - internalFontPadding);
            NotifyPropertyChanged();
        }
    }

    public int FontPadding {
        get => m_FontPadding;
        set {
            m_FontPadding = value;
            if (initializing) return;
            m_FontPadding = (int)ValidateRange(value, internalFontPadding, ClientRectangle.Height - internalFontPadding);
            FontAdapter(m_CustomFont, DeviceDpi);
            NotifyPropertyChanged();
        }
    }

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

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

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


    protected override void OnPaint(PaintEventArgs e)
    {
        using (var 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 (var circleBrush = new SolidBrush(m_BackGroundColor))
            using (var foreBrush = new SolidBrush(ForeColor))
            {
                FontAdapter(m_CustomFont, e.Graphics.DpiY);
                RectangleF rect = InnerRectangle();
                e.Graphics.FillEllipse(circleBrush, rect);
                e.Graphics.DrawString(Text, m_CustomFont, foreBrush, rect, format);
            };
        };
    }

    private RectangleF InnerRectangle()
    {
        var minMax = GetMinMax(ClientRectangle.Height, ClientRectangle.Width);
        var size = new SizeF(minMax.min - m_InnerPadding,
                             minMax.min - m_InnerPadding);
        var position = new PointF((ClientRectangle.Width - size.Width) / 2,
                                  (ClientRectangle.Height - size.Height) / 2);
        return new RectangleF(position, size);
    }

    private void FontAdapter(Font font, float Dpi)
    {
        RectangleF rect = InnerRectangle();
        float size = (rect.Height - m_FontPadding) * (72.0f / Dpi) - internalFontPadding;
        int fontSize = (int)ValidateRange(size, 6, size);

        m_CustomFont = new Font(font.FontFamily, fontSize, font.Style, GraphicsUnit.Pixel);
    }

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

    private float ValidateRange(float Value, float Min, float Max)
        => Math.Max(Math.Min(Value, Max), Min); //(Value < Min) ? Min : ((Value > Max) ? Max : Value);

    private (float min, float max) GetMinMax(float value1, float value2) 
        => (Math.Min(value1, value2), Math.Max(value1, value2));

    public void BeginInit() => initializing = true;

    public void EndInit()
    {
        initializing = false;
        Font = new Font("Segoe UI", 50, FontStyle.Regular, GraphicsUnit.Pixel);
        FontPadding = m_FontPadding;
        InnerPadding = m_InnerPadding;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-09
    • 1970-01-01
    • 2020-08-10
    • 2011-04-16
    • 2011-08-13
    • 1970-01-01
    • 2011-08-31
    • 1970-01-01
    相关资源
    最近更新 更多