I am working in a spinner control. I want the control to support transparent backcolor. When the arc is drawn, there is a blank space in the middle, I want that space to be
To make a transparent layer, you should override painting of the control and draw the control in this order, First draw all controls in the same container which are under your control (based on z-index) on a bitmap.
Then draw that bitmap on graphics of your control.
At last draw content of your control.
Also the BackColor of your control should be Color.Transparent
.
Also as another option to make transparent layer, you can exclude some regions from your control when drawing.
In the following samples I used the first technique and created 2 controls. A spinning circles transparent control. and a transparent picturebox control.
In both samples I used a delay between loading rows to showing a spinner make sense.
Sample 1 - Using a SpinningCircles Control
SpinningCircles
control draws circles and supports transparency. The control doesn't animate at design-time, but it animates at run-time. Also it doesn't consume resources when it is not visible.
Sample 2 - Using a TransparentPictureBox Control and a transparent animated gif
TransparentPictureBox
control supports transparency, so I used an animated gif as its image and as you can see, the gif is showing correctly.
Sample 1 Code - SpinningCircles
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;
public class SpinningCircles : Control
{
int increment = 1;
int radius = 4;
int n = 8;
int next = 0;
Timer timer;
public SpinningCircles()
{
timer = new Timer();
this.Size = new Size(100, 100);
timer.Tick += (s, e) => this.Invalidate();
if (!DesignMode)
timer.Enabled = true;
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw | ControlStyles.UserPaint |
ControlStyles.SupportsTransparentBackColor, true);
BackColor = Color.Transparent;
}
protected override void OnPaint(PaintEventArgs e)
{
if (Parent != null && this.BackColor == Color.Transparent)
{
using (var bmp = new Bitmap(Parent.Width, Parent.Height))
{
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));
e.Graphics.DrawImage(bmp, -Left, -Top);
}
}
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
int length = Math.Min(Width, Height);
PointF center = new PointF(length / 2, length / 2);
int bigRadius = length / 2 - radius - (n - 1) * increment;
float unitAngle = 360 / n;
if (!DesignMode)
next++;
next = next >= n ? 0 : next;
int a = 0;
for (int i = next; i < next + n; i++)
{
int factor = i % n;
float c1X = center.X + (float)(bigRadius * Math.Cos(unitAngle * factor * Math.PI / 180));
float c1Y = center.Y + (float)(bigRadius * Math.Sin(unitAngle * factor * Math.PI / 180));
int currRad = radius + a * increment;
PointF c1 = new PointF(c1X - currRad, c1Y - currRad);
e.Graphics.FillEllipse(Brushes.Black, c1.X, c1.Y, 2 * currRad, 2 * currRad);
using (Pen pen = new Pen(Color.White, 2))
e.Graphics.DrawEllipse(pen, c1.X, c1.Y, 2 * currRad, 2 * currRad);
a++;
}
}
protected override void OnVisibleChanged(EventArgs e)
{
timer.Enabled = Visible;
base.OnVisibleChanged(e);
}
}
Sample 2 Code - TransparentPictureBox Code
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;
class TransparentPictureBox : PictureBox
{
public TransparentPictureBox()
{
this.BackColor = Color.Transparent;
}
protected override void OnPaint(PaintEventArgs e)
{
if (Parent != null && this.BackColor == Color.Transparent)
{
using (var bmp = new Bitmap(Parent.Width, Parent.Height))
{
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));
e.Graphics.DrawImage(bmp, -Left, -Top);
}
}
base.OnPaint(e);
}
}
I slightly changed Reza's code (SpinningCircles) to add a semi-transparent background. I wanted to share it with you. (NOTE: The spinner length was fixed to 100 and should be added as a component property)
public partial class WorkingPanel : UserControl
{
#region Constants
private static readonly Int32 kSpinnerLength = 100;
#endregion
#region Fields
private Int32 increment = 1;
private Int32 radius = 4;
private Int32 n = 8;
private Int32 next = 0;
private Timer timer = null;
#endregion
#region Constructor
public WorkingPanel()
{
this.Size = new Size(100, 100);
timer = new Timer();
timer.Tick += (s, e) => this.Invalidate();
if (!DesignMode)
timer.Enabled = true;
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw | ControlStyles.UserPaint |
ControlStyles.SupportsTransparentBackColor, true);
BackColor = Color.Transparent;
}
#endregion
#region Methods (Protected - Override)
protected override void OnPaint(PaintEventArgs e)
{
if (null != Parent && (this.BackColor.A != 255 || this.BackColor == Color.Transparent))
{
using (var bmp = new Bitmap(Parent.Width, Parent.Height))
{
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));
e.Graphics.DrawImage(bmp, -Left, -Top);
if (this.BackColor != Color.Transparent)
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), new Rectangle(0, 0, Width, Height));
}
}
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
Int32 length = kSpinnerLength;
PointF center = new PointF(Width / 2, Height / 2);
Int32 bigRadius = length / 2 - radius - (n - 1) * increment;
float unitAngle = 360 / n;
if (!DesignMode)
next++;
next = next >= n ? 0 : next;
Int32 a = 0;
for (Int32 i = next; i < next + n; i++)
{
Int32 factor = i % n;
float c1X = center.X + (float)(bigRadius * Math.Cos(unitAngle * factor * Math.PI / 180));
float c1Y = center.Y + (float)(bigRadius * Math.Sin(unitAngle * factor * Math.PI / 180));
Int32 currRad = radius + a * increment;
PointF c1 = new PointF(c1X - currRad, c1Y - currRad);
e.Graphics.FillEllipse(Brushes.White, c1.X, c1.Y, 2 * currRad, 2 * currRad);
using (Pen pen = new Pen(Color.White, 2))
e.Graphics.DrawEllipse(pen, c1.X, c1.Y, 2 * currRad, 2 * currRad);
a++;
}
}
protected override void OnVisibleChanged(EventArgs e)
{
timer.Enabled = Visible;
base.OnVisibleChanged(e);
}
#endregion
}