Transparent Overlapping Circular Progress Bars (Custom Control)
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;
c# winforms user-interface user-controls transparency
add a comment |
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;
c# winforms user-interface user-controls transparency
You may find these post useful: • Show Transparent Loading Spinner above other Control • Show a Label with semi-transparent BackColor above other controls? • Any trick to use opacity on a panel in Visual Studio Window Form?
– Reza Aghaei
Nov 18 '18 at 22:42
Another translucent control: Translucent circle with text. Derived from a Label control. It could be Panel as well. That's a complete custom control. You can drop it on a Form from the Toolbox and see how it works.
– Jimi
Nov 18 '18 at 22:49
Hello @RezaAghaei , I reviewed your examples and tried to implement the Parent.Controls code into my control. Now, neither one seems to be on top, and still we have that spacing problem where the transparent background erases part of the other control. (see picture above)
– frostbyte
Nov 18 '18 at 22:59
add a comment |
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;
c# winforms user-interface user-controls transparency
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;
c# winforms user-interface user-controls transparency
c# winforms user-interface user-controls transparency
edited Nov 19 '18 at 14:39
frostbyte
asked Nov 18 '18 at 22:04
frostbytefrostbyte
325412
325412
You may find these post useful: • Show Transparent Loading Spinner above other Control • Show a Label with semi-transparent BackColor above other controls? • Any trick to use opacity on a panel in Visual Studio Window Form?
– Reza Aghaei
Nov 18 '18 at 22:42
Another translucent control: Translucent circle with text. Derived from a Label control. It could be Panel as well. That's a complete custom control. You can drop it on a Form from the Toolbox and see how it works.
– Jimi
Nov 18 '18 at 22:49
Hello @RezaAghaei , I reviewed your examples and tried to implement the Parent.Controls code into my control. Now, neither one seems to be on top, and still we have that spacing problem where the transparent background erases part of the other control. (see picture above)
– frostbyte
Nov 18 '18 at 22:59
add a comment |
You may find these post useful: • Show Transparent Loading Spinner above other Control • Show a Label with semi-transparent BackColor above other controls? • Any trick to use opacity on a panel in Visual Studio Window Form?
– Reza Aghaei
Nov 18 '18 at 22:42
Another translucent control: Translucent circle with text. Derived from a Label control. It could be Panel as well. That's a complete custom control. You can drop it on a Form from the Toolbox and see how it works.
– Jimi
Nov 18 '18 at 22:49
Hello @RezaAghaei , I reviewed your examples and tried to implement the Parent.Controls code into my control. Now, neither one seems to be on top, and still we have that spacing problem where the transparent background erases part of the other control. (see picture above)
– frostbyte
Nov 18 '18 at 22:59
You may find these post useful: • Show Transparent Loading Spinner above other Control • Show a Label with semi-transparent BackColor above other controls? • Any trick to use opacity on a panel in Visual Studio Window Form?
– Reza Aghaei
Nov 18 '18 at 22:42
You may find these post useful: • Show Transparent Loading Spinner above other Control • Show a Label with semi-transparent BackColor above other controls? • Any trick to use opacity on a panel in Visual Studio Window Form?
– Reza Aghaei
Nov 18 '18 at 22:42
Another translucent control: Translucent circle with text. Derived from a Label control. It could be Panel as well. That's a complete custom control. You can drop it on a Form from the Toolbox and see how it works.
– Jimi
Nov 18 '18 at 22:49
Another translucent control: Translucent circle with text. Derived from a Label control. It could be Panel as well. That's a complete custom control. You can drop it on a Form from the Toolbox and see how it works.
– Jimi
Nov 18 '18 at 22:49
Hello @RezaAghaei , I reviewed your examples and tried to implement the Parent.Controls code into my control. Now, neither one seems to be on top, and still we have that spacing problem where the transparent background erases part of the other control. (see picture above)
– frostbyte
Nov 18 '18 at 22:59
Hello @RezaAghaei , I reviewed your examples and tried to implement the Parent.Controls code into my control. Now, neither one seems to be on top, and still we have that spacing problem where the transparent background erases part of the other control. (see picture above)
– frostbyte
Nov 18 '18 at 22:59
add a comment |
1 Answer
1
active
oldest
votes
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);
}
}
Thanks @Jimi. Your explanation was very detailed, so I awarded you the answer.
– frostbyte
Nov 19 '18 at 17:11
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53365918%2ftransparent-overlapping-circular-progress-bars-custom-control%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
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);
}
}
Thanks @Jimi. Your explanation was very detailed, so I awarded you the answer.
– frostbyte
Nov 19 '18 at 17:11
add a comment |
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);
}
}
Thanks @Jimi. Your explanation was very detailed, so I awarded you the answer.
– frostbyte
Nov 19 '18 at 17:11
add a comment |
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);
}
}
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);
}
}
edited Dec 10 '18 at 10:53
answered Nov 19 '18 at 17:01
JimiJimi
7,24741733
7,24741733
Thanks @Jimi. Your explanation was very detailed, so I awarded you the answer.
– frostbyte
Nov 19 '18 at 17:11
add a comment |
Thanks @Jimi. Your explanation was very detailed, so I awarded you the answer.
– frostbyte
Nov 19 '18 at 17:11
Thanks @Jimi. Your explanation was very detailed, so I awarded you the answer.
– frostbyte
Nov 19 '18 at 17:11
Thanks @Jimi. Your explanation was very detailed, so I awarded you the answer.
– frostbyte
Nov 19 '18 at 17:11
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53365918%2ftransparent-overlapping-circular-progress-bars-custom-control%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
You may find these post useful: • Show Transparent Loading Spinner above other Control • Show a Label with semi-transparent BackColor above other controls? • Any trick to use opacity on a panel in Visual Studio Window Form?
– Reza Aghaei
Nov 18 '18 at 22:42
Another translucent control: Translucent circle with text. Derived from a Label control. It could be Panel as well. That's a complete custom control. You can drop it on a Form from the Toolbox and see how it works.
– Jimi
Nov 18 '18 at 22:49
Hello @RezaAghaei , I reviewed your examples and tried to implement the Parent.Controls code into my control. Now, neither one seems to be on top, and still we have that spacing problem where the transparent background erases part of the other control. (see picture above)
– frostbyte
Nov 18 '18 at 22:59