fro*_*yte 6 c# user-controls transparency gdi+ winforms
我在使用自定义圆形进度条控件时遇到了一些问题。我试图在右下角重叠它们两个。它有一个透明的背景,这在 WinForms 中显然是显示背景,但对彼此没有影响。
这是我所看到的:
我一直在研究 stackoverflow,并找到了一些解决自定义图片框控件出现此问题的人的答案。大多数解决方案,似乎对圆形进度条控件没有影响。我尝试过的一些解决方案是。
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20;
return cp;
}
}
Run Code Online (Sandbox Code Playgroud)
我还有自定义控件上的代码,用于允许透明背景。显然,正如我所说,这不会影响重叠控件。
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
Run Code Online (Sandbox Code Playgroud)
我看到人们使用的 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);
}
}
Run Code Online (Sandbox Code Playgroud)
任何援助将不胜感激。这让我发疯了好几个小时。谢谢 :)
更新 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));
Run Code Online (Sandbox Code Playgroud)
还是难住了。:(
更新 2:我尝试将前面的 circleprogressbar 设置为使用后面的 circleprogressbar 作为它在 FormLoad 中的父项。那也没有用。它使它们彼此透明,但切断了顶部圆形进度条不在背面边界内的任何部分。
var pts = this.PointToScreen(circularprogressbar1.Location);
pts = circularprogressbar2.PointToClient(pts);
circularprogressbar1.Parent = circularprogressbar2;
circularprogressbar1.Location = pts;
Run Code Online (Sandbox Code Playgroud)
我将就如何继续向您提供一些建议。
从这个简单的透明控件 ( TransparentPanel) 开始。
这个类派生自Panel. 这是首先要做的选择:是否Panel适合从/扩展此任务的控件?也许是,也许不是。
例如,aPanel是一个容器。你需要容器的特性吗?容器意味着很多。它继承了ScrollableControl并在其 Window 样式中具有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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意:
这里,ControlStyles.SupportsTransparentBackColor是明确设置的。该Panel班已经支持这一点。无论如何指定它是因为它给出了这个自定义控件是什么的想法,只是在它的构造函数中读取。
此外,ControlStyles.OptimizedDoubleBuffer设置为false。
这可以防止系统以任何方式干扰控件的绘制。没有缓存,自定义控件在失效时被重新绘制。容器 Form 最好将其DoubleBuffer属性设置为true,但您可能希望不对其进行测试,以查看是否存在差异。
这个自定义控件(不要与 a 混淆UserControl)是完全透明的。它不绘制它的背景。但是你可以在它的表面上画任何东西。
拿之前贴的链接:
DoubleDuffering)Opacity以不同的方式使用)Color.Transparent和DoubleBuffer)获得相同结果的 4 种不同方法。选择哪一个取决于上下文/目的地。
设计时建议:当您测试自定义控件功能时,请记住始终重建项目。当项目运行时,可能会发生从CustomControl, 中删除的 a没有使用新更改进行更新。
此外,如果添加或删除属性,则需要删除控件、重建并在窗体上放置一个新控件。
如果您不这样做,您的修改/添加很有可能会被完全忽略,并且您会继续测试从未发挥作用的功能。FormToolbox
一个例子,使用 2 个重叠的自定义控件。
(使用准系统 custom TransparentPanel)
这是用于生成这些图纸的测试代码:
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;
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);
}
}
Run Code Online (Sandbox Code Playgroud)
注意:要使用此代码创建旋转效果,您需要TransparentPanel上面显示的控件,它与在标准控件表面绘制的方式不同。
| 归档时间: |
|
| 查看次数: |
1152 次 |
| 最近记录: |