透明的重叠圆形进度条(自定义控件)

时间:2018-11-18 22:04:50

标签: c# winforms user-interface user-controls transparency

自定义圆形进度栏控件遇到一些麻烦。我试图将它们两个重叠在右下角。它具有透明背景,显然在WinForms中显示了背景,但彼此之间没有影响。

这就是我所看到的:

Overlapping Circular Progress Bars

我一直在研究stackoverflow,并为使用自定义图片框控件遇到此问题的人们找到了一些答案。大多数解决方案似乎对循环进度条控件没有影响。我尝试过的一些解决方案是。

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;

            cp.ExStyle |= 0x20;

            return cp;
        }
    }

我在自定义控件上也有允许透明背景的代码。显然,正如我所说,这不会影响控件的重叠。

SetStyle(ControlStyles.SupportsTransparentBackColor, true);

我看到人们使用的还有stackoverflow上的TransparentControl解决方案。我已经创建了控件,但是不知道如何使用它,或者在我的情况下它不起作用。这是该控件的代码。

public class TransparentControl : Panel
{
    public bool drag = false;
    public bool enab = false;
    private int m_opacity = 100;

    private int alpha;
    public TransparentControl()
    {
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        SetStyle(ControlStyles.Opaque, true);
        this.BackColor = Color.Transparent;
    }

    public int Opacity
    {
        get
        {
            if (m_opacity > 100)
            {
                m_opacity = 100;
            }
            else if (m_opacity < 1)
            {
                m_opacity = 1;
            }
            return this.m_opacity;
        }
        set
        {
            this.m_opacity = value;
            if (this.Parent != null)
            {
                Parent.Invalidate(this.Bounds, true);
            }
        }
    }

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

    protected override void OnPaint(PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        Rectangle bounds = new Rectangle(0, 0, this.Width - 1, this.Height - 1);

        Color frmColor = this.Parent.BackColor;
        Brush bckColor = default(Brush);

        alpha = (m_opacity * 255) / 100;

        if (drag)
        {
            Color dragBckColor = default(Color);

            if (BackColor != Color.Transparent)
            {
                int Rb = BackColor.R * alpha / 255 + frmColor.R * (255 - alpha) / 255;
                int Gb = BackColor.G * alpha / 255 + frmColor.G * (255 - alpha) / 255;
                int Bb = BackColor.B * alpha / 255 + frmColor.B * (255 - alpha) / 255;
                dragBckColor = Color.FromArgb(Rb, Gb, Bb);
            }
            else
            {
                dragBckColor = frmColor;
            }

            alpha = 255;
            bckColor = new SolidBrush(Color.FromArgb(alpha, dragBckColor));
        }
        else
        {
            bckColor = new SolidBrush(Color.FromArgb(alpha, this.BackColor));
        }

        if (this.BackColor != Color.Transparent | drag)
        {
            g.FillRectangle(bckColor, bounds);
        }

        bckColor.Dispose();
        g.Dispose();
        base.OnPaint(e);
    }

    protected override void OnBackColorChanged(EventArgs e)
    {
        if (this.Parent != null)
        {
            Parent.Invalidate(this.Bounds, true);
        }
        base.OnBackColorChanged(e);
    }

    protected override void OnParentBackColorChanged(EventArgs e)
    {
        this.Invalidate();
        base.OnParentBackColorChanged(e);
    }
}

任何帮助将不胜感激。这使我疯了几个小时。谢谢:)

更新1:我尝试使用下面发布的示例中的以下代码段。这产生了相同的结果。我在圆形进度条之间仍然有空白(如图所示)。

                Parent.Controls.Cast<Control>()
                  .Where(c => Parent.Controls.GetChildIndex(c) > Parent.Controls.GetChildIndex(this))
                  .Where(c => c.Bounds.IntersectsWith(this.Bounds))
                  .OrderByDescending(c => Parent.Controls.GetChildIndex(c))
                  .ToList()
                  .ForEach(c => c.DrawToBitmap(bmp, c.Bounds));

仍然卡住了。 :(

更新2:我尝试将前circularprogressbar设置为使用后circularprogressbar作为FormLoad中的父级。那也没有解决。它使它们彼此透明,但是切除了顶部圆形进度条中不在背面边界内的任何部分。

var pts = this.PointToScreen(circularprogressbar1.Location);
pts = circularprogressbar2.PointToClient(pts);
circularprogressbar1.Parent = circularprogressbar2;
circularprogressbar1.Location = pts;

1 个答案:

答案 0 :(得分:2)

我将给您一些有关如何进行的建议。

从这个简单的透明控件(TransparentPanel)开始。
此类源自Panel。那是首先要做出的选择:Panel是从该任务继承/扩展的正确控件吗?也许是,也许不是。
例如,Panel是一个容器。您是否需要容器的功能?容器意味着很多。它继承了ScrollableControl,并且在其窗口样式中具有ContainerControl。它已经带有行李了。

您可以选择使用Label,因为它重量轻。或构建一个UserControl。
我认为没有绝对的最佳选择。这取决于此自定义控件的用途。您需要尝试一下。

class TransparentPanel : Panel
{
    internal const int WS_EX_TRANSPARENT = 0x00000020;

    public TransparentPanel() => InitializeComponent();

    protected void InitializeComponent()
    {
        this.SetStyle(ControlStyles.AllPaintingInWmPaint |
                      ControlStyles.Opaque |
                      ControlStyles.ResizeRedraw |
                      ControlStyles.SupportsTransparentBackColor |
                      ControlStyles.UserPaint, true);
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
    }

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


注释
在这里,ControlStyles.SupportsTransparentBackColor被明确设置。 Panel类已经支持此功能。之所以进行指定,是因为它给出了此自定义控件的含义,以供仅在其构造函数中读取。

此外,ControlStyles.OptimizedDoubleBuffer设置为false。
这样可以防止系统以任何方式干扰控件的绘制。没有缓存,自定义控件无效时会被涂上新的颜色。容器Form最好将其DoubleBuffer属性设置为true,但您可能需要对其进行测试,以查看是否存在差异。


自定义控件(不要与UserControl混淆)是完全透明的。它没有画出背景。但是您可以在其表面上绘制任何东西。

获取之前发布的链接:
 -此Translucent Label(无BackGround绘画,已禁用DoubleDuffering
 - Reza Aghaei transparent Panel(以其他方式使用Opacity
 - TaW Grid PanelColor.TransparentDoubleBuffer
 -这些注释:Reasons for why a WinForms label does not want to be transparent?

4种获得相同结果的方法。选择哪一个取决于上下文/目标。

设计时建议:在测试自定义控件功能时,请记住始终重建项目。在项目运行时,CustomControl(从FormToolbox的一个TransparentPanel上掉落的笔有可能没有用新的更改进行更新。
另外,如果添加或删除属性,则需要删除该控件,然后重新构建并将其拖放到窗体上。
如果您不这样做,则很有可能完全忽略您的修改/添加,并且继续测试永远不会起作用的功能。

使用两个重叠的自定义控件的示例。
(使用准系统自定义TransparentPanel

Transparent Overlapped Controls Rotate

这是用于生成这些图形的测试代码:
-使用前面显示的TransparentPanel类创建一个新的自定义控件:
-将两个 TransparentPanel1对象放在测试表单中
-将TransparentPanel2transparentPanel1_Paint事件处理程序分配给transparentPanel2_PaintbtnRotate
-将两个透明面板重叠,确保不要误将它们嵌套
-修改其余代码(您只需要一个按钮,在这里名为btnRotate_Click,分配private System.Windows.Forms.Timer RotateTimer = null; private float RotationAngle1 = 90F; private float RotationAngle2 = 0F; public bool RotateFigures = false; public form1() { InitializeComponent(); RotateTimer = new Timer(); RotateTimer.Interval = 50; RotateTimer.Enabled = false; RotateTimer.Tick += new EventHandler(this.RotateTick); } protected void RotateTick(object sender, EventArgs e) { RotationAngle1 += 10F; RotationAngle2 += 10F; transparentPanel1.Invalidate(); transparentPanel2.Invalidate(); } private void btnRotate_Click(object sender, EventArgs e) { RotateTimer.Enabled = !RotateTimer.Enabled; if (RotateTimer.Enabled == false) { RotateFigures = false; RotationAngle1 = 90F; RotationAngle2 = 0F; } else { RotateFigures = true; } } private void transparentPanel1_Paint(object sender, PaintEventArgs e) { if (!RotateFigures) return; e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; e.Graphics.CompositingQuality = CompositingQuality.HighQuality; e.Graphics.CompositingMode = CompositingMode.SourceOver; Rectangle rect = transparentPanel1.ClientRectangle; Rectangle rectInner = rect; using (Pen transpPen = new Pen(transparentPanel1.Parent.BackColor, 10)) using (Pen penOuter = new Pen(Color.SteelBlue, 8)) using (Pen penInner = new Pen(Color.Teal, 8)) using (Matrix m1 = new Matrix()) using (Matrix m2 = new Matrix()) { m1.RotateAt(-RotationAngle1, new PointF(rect.Width / 2, rect.Height / 2)); m2.RotateAt(RotationAngle1, new PointF(rect.Width / 2, rect.Height / 2)); rect.Inflate(-(int)penOuter.Width, -(int)penOuter.Width); rectInner.Inflate(-(int)penOuter.Width * 3, -(int)penOuter.Width * 3); e.Graphics.Transform = m1; e.Graphics.DrawArc(transpPen, rect, -4, 94); e.Graphics.DrawArc(penOuter, rect, -90, 90); e.Graphics.ResetTransform(); e.Graphics.Transform = m2; e.Graphics.DrawArc(transpPen, rectInner, 190, 100); e.Graphics.DrawArc(penInner, rectInner, 180, 90); } } private void transparentPanel2_Paint(object sender, PaintEventArgs e) { if (!RotateFigures) return; e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; e.Graphics.CompositingQuality = CompositingQuality.HighQuality; e.Graphics.CompositingMode = CompositingMode.SourceOver; Rectangle rect = transparentPanel2.ClientRectangle; Rectangle rectInner = rect; using (Pen transpPen = new Pen(transparentPanel2.Parent.BackColor, 10)) using (Pen penOuter = new Pen(Color.Orange, 8)) using (Pen penInner = new Pen(Color.DarkRed, 8)) using (Matrix m1 = new Matrix()) using (Matrix m2 = new Matrix()) { m1.RotateAt(RotationAngle2, new PointF(rect.Width / 2, rect.Height / 2)); m2.RotateAt(-RotationAngle2, new PointF(rect.Width / 2, rect.Height / 2)); rect.Inflate(-(int)penOuter.Width, -(int)penOuter.Width); rectInner.Inflate(-(int)penOuter.Width * 3, -(int)penOuter.Width * 3); e.Graphics.Transform = m1; e.Graphics.DrawArc(transpPen, rect, -4, 94); e.Graphics.DrawArc(penOuter, rect, 0, 90); e.Graphics.ResetTransform(); e.Graphics.Transform = m2; e.Graphics.DrawArc(transpPen, rectInner, 190, 100); e.Graphics.DrawArc(penInner, rectInner, 180, 90); } } 处理程序即可)

curlopt_custom_request