透明的重叠圆形进度条(自定义控件) [英] Transparent Overlapping Circular Progress Bars (Custom Control)

查看:102
本文介绍了透明的重叠圆形进度条(自定义控件)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这里是我所看到的:





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

 受保护的覆盖CreateParams CreateParams 
{
get
{
CreateParams cp = base.CreateParams;

cp.ExStyle | = 0x20;

返回cp;
}
}

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

  SetStyle(ControlStyles.SupportsTransparentBackColor,true); 

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

 公共类TransparentControl:Panel 
{
public bool drag =假;
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不透明
{
如果(m_opacity> 100)
{
m_opacity = 100;
}
else if(m_opacity< 1)
{
m_opacity = 1;
}
返回this.m_opacity;
}
set
{
this.m_opacity = value;
if(this.Parent!= null)
{
Parent.Invalidate(this.Bounds,true);
}
}
}

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

受保护的覆盖无效OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle bounds = new Rectangle(0,0,this.Width-1,this.Height-1);

颜色frmColor = this.Parent.BackColor;
画笔bckColor =默认值(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);
}
其他
{
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);
}

受保护的覆盖无效OnBackColorChanged(EventArgs e)
{
if(this.Parent!= null)
{
父级。无效(this.Bounds,true);
}
base.OnBackColorChanged(e);
}

受保护的覆盖无效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设置为在FormLoad中使用后circularprogressbar,因为它是父级。使得它们彼此透明,但是切断了顶部圆形进度条中不在背部边界范围内的任何部分。

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


解决方案

我将给您几个有关如何进行操作的建议。



从这个简单的透明控件开始( TransparentPanel ) 。

此类是从 Panel 派生的,这是第一个选择: Panel 继承或扩展此任务的正确控件?也许是,也许不是。

例如, Panel 是一个容器。您是否需要容器的功能?容器意味着很多。它继承了



这是用于生成这些图形的测试代码:

-使用前面显示的 TransparentPanel 类创建新的自定义控件:

-将两个 TransparentPanel 对象放在测试表单上

-分配给 TransparentPanel1 TransparentPanel2 事件处理程序 transparentPanel1_Paint transparentPanel2_Paint 事件处理程序。

-覆盖两个透明面板,确保您不会误将其嵌套

-修改其余代码(您需要只是一个按钮,这里名为 btnRotate ,分配 btnRotate_Click 处理程序)

  private System.Windows.Forms.Timer RotateTimer = null; 
private float RotationAngle1 = 90F;
private float RotationAngle2 = 0F;
public bool RotateFigures = false;

公共表单1()
{
InitializeComponent();
RotateTimer = new Timer();
RotateTimer.Interval = 50;
RotateTimer.Enabled =假;
RotateTimer.Tick + =新的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;

使用(笔transpPen =新Pen(transparentPanel1.Parent.BackColor,10))
使用(笔penOuter =新Pen(Color.SteelBlue,8))
使用( Pen PenInner =新Pen(Color.Teal,8))
使用(矩阵m1 =新Matrix())
使用(矩阵m2 =新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;

使用(笔transpPen =新Pen(transparentPanel2.Parent.BackColor,10))
使用(笔penOuter =新Pen(Color.Orange,8))
使用( Pen PenInner =新Pen(Color.DarkRed,8))
使用(矩阵m1 =新Matrix())
使用(矩阵m2 =新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);
}
}


I am having some trouble with a custom circular progress bar control. I am trying to overlap the two of them at the lower right corner. It has a transparent background, which obviously in WinForms is showing the background, but has no effect on each other.

Here is what I am seeing:

I have been researching on stackoverflow, and have found a few answers to people having this issue with custom picturebox controls. Most of the solutions, seem to have no effect on the circular progress bar control. Some of the solutions I have tried is.

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

            cp.ExStyle |= 0x20;

            return cp;
        }
    }

I also have the code on the custom control for allowing transparent backgrounds. Obviously, as I stated, this does not effect overlapping controls.

SetStyle(ControlStyles.SupportsTransparentBackColor, true);

There is also a TransparentControl solution on stackoverflow which I saw people using. I have created the control, but either have no idea how to use it, or it doesn't work in my situation. Here is the code from that control.

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

Any assistance would be appreciated. This has been driving me nuts for hours. Thanks :)

UPDATE 1: I tried using the following code snippet from examples posted below. This yielded the same results. I still have that blank space between the circular progress bars (as seen in the picture).

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

Still stumped. :(

UPDATE 2: I tried setting the front circularprogressbar to use the back circularprogressbar as it's parent in the FormLoad. That didn't work out either. It made them transparent to each other, but cut off any part of the top circularprogressbar that wasn't within' the boundaries of the back.

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

解决方案

I'm going to give you just a couple of suggestions on how to proceed.

Start off with this bare-bones transparent control (TransparentPanel).
This class is derived from Panel. That's the first choice to make: is Panel the right control to inherit from/extend for this task? Maybe it is, maybe not.
For example, a Panel is a container. Do you need the features of a container, here? Container means a lot. It inherits ScrollableControl and has ContainerControl among its Window styles. It comes with a baggage already.

You could opt for a Label instead, it's light-weight. Or build a UserControl.
I don't think there's an absolute best choice. It depends of what this custom control is used for. You need to try it out.

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


Notes:
Here, ControlStyles.SupportsTransparentBackColor is set explicitly. The Panel class already supports this. It's specified anyway because it gives the idea of what this custom control is for just reading at its constructor.

Also, ControlStyles.OptimizedDoubleBuffer is set to false.
This prevents the System to interfere in any way with the painting of the control. There's not caching, the Custom Control is painted new when it's Invalidated. The container Form should preferably have its DoubleBuffer property set to true, but you might want test it without, to see if there's a difference.


This Custom Control (not to be confused with a UserControl) is completely transparent. It doesn't draw its background. But you can paint anything on its surface.

Take the links posted before:
- This Translucent Label (no BackGround painting, disabled DoubleDuffering)
- Reza Aghaei's transparent Panel (using Opacity in a different way)
- TaW's Grid Panel (Color.Transparent and DoubleBuffer)
- These notes: Reasons for why a WinForms label does not want to be transparent?

4 different ways to get to the same result. Which one to choose depends on the context/destination.

A design-time advice: when you are testing a custom control functionalities, remember to always rebuild the project. It can happen that a CustomControl, droppen on a Form from the Toolbox, is not updated with the new changes when the project is run.
Also, if you add or remove properties, you need to delete the control, rebuild and drop a new one on the Form.
If you don't, there's a really good chance that your modification/addition are completely ignored and you keep on testing features that never get into play.

An example, using 2 overlapping custom controls.
(using the bare-bones custom TransparentPanel)

This is the test code used to generate these drawings:
- Create a new Custom Control using the TransparentPanel class shown before:
- Drop two TransparentPanel objects on a test Form
- Assign to TransparentPanel1 and TransparentPanel2 the transparentPanel1_Paint and transparentPanel2_Paint event handlers.
- Overlap the two transparent Panels, making sure you don't nest them by mistake.
- Adapt the rest of the code (you need just a Button, here named btnRotate, assign the btnRotate_Click handler)

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

这篇关于透明的重叠圆形进度条(自定义控件)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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