gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 16:39:16 27 4
gpt4 key购买 nike

我在使用自定义圆形进度条控件时遇到了一些问题。我试图在右下角重叠它们两个。它有一个透明的背景,这在 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:我尝试将前面的 circleprogressbar 设置为使用后面的 circleprogressbar 作为它在 FormLoad 中的父级。那也没有用。它使它们彼此透明,但切断了顶部圆形进度条不在背面边界内的任何部分。
var pts = this.PointToScreen(circularprogressbar1.Location);
pts = circularprogressbar2.PointToClient(pts);
circularprogressbar1.Parent = circularprogressbar2;
circularprogressbar1.Location = pts;

最佳答案

我将就如何继续向您提供一些建议。
从这个简单的透明控件 ( TransparentPanel ) 开始。
这个类派生自 Panel .这是第一个选择:是 Panel继承/扩展此任务的正确控件?也许是,也许不是。
例如,Panel是一个容器。你需要容器​​的特性吗?容器意味着很多。它继承了ScrollableControl并有 ContainerControl在其窗口样式中。它已经带了一个行李。
您可以选择 Label相反,它是轻量级的。或者建立一个用户控件。
我认为没有绝对的最佳选择。这取决于此自定义控件的用途。你需要尝试一下。

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设置为假。
这可以防止系统以任何方式干扰控件的绘制。没有缓存,自定义控件在失效时被重新绘制。容器 Form 最好有它的 DoubleBuffer 属性设置为 true ,但您可能想在没有的情况下测试它,看看是否有区别。

自定义控件 (不要与 UserControl 混淆)是完全透明的。它不绘制它的背景。但是你可以在它的表面上画任何东西。
拿之前贴的链接:
  • Translucent Label (无背景绘画,禁用 DoubleDuffering)
  • Reza Aghaei transparent Panel (以不同的方式使用 Opacity)
  • TaW Grid Panel ( Color.TransparentDoubleBuffer )
  • 这些注释:Reasons for why a WinForms label does not want to be transparent?

  • 获得相同结果的 4 种不同方法。选择哪一个取决于上下文/目的地。
    设计时建议 :当您测试自定义控件功能时,请记住始终重建项目。可能会发生 CustomControl , 放在 Form 上来自 Toolbox , 不会在项目运行时使用新更改进行更新。
    另外,如果您 添加或删除属性 ,您需要删除控件,重建并在窗体上放置一个新控件。
    如果您不这样做,您的修改/添加很有可能会被完全忽略,并且您会继续测试从未发挥作用的功能。
    一个示例,使用 2 个重叠的自定义控件。
    (使用基本的自定义 TransparentPanel )
    Transparent Overlapped Controls Rotate
    这是用于生成这些图纸的测试代码:
  • 使用 TransparentPanel 创建一个新的自定义控件之前显示的类:
  • 掉落 两个 TransparentPanel测试表单上的对象
  • 分配给 TransparentPanel1TransparentPanel2 transparentPanel1_PainttransparentPanel2_Paint事件处理程序。
  • 重叠两个透明面板,确保您不会错误地嵌套它们 .
  • 调整其余的代码(你只需要一个按钮,这里命名为 btnRotate ,分配 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);
    }
    }
    注:要使用此代码创建旋转效果,您需要 TransparentPanel上面显示的控件,它的工作方式与在标准控件的表面上绘制的方式不同。

    关于c# - 透明重叠圆形进度条(自定义控件),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53365918/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com