在其他控件上方显示透明加载微调器

时间:2016-05-13 22:38:25

标签: c# .net winforms custom-controls gdi+

我在旋转控件中工作。我希望控件支持透明背景色。绘制弧线时,中间有一个空白区域,我希望该空间真正透明,这样我就可以在其后面放置另一个控件,它不会被旋转器覆盖。

我尝试重写CreateParams void 我还设置了支持TransparentColor的样式 尝试重写OnPaintBackground void,但我无法实现真正​​透明的背景色。

那么,你能建议我做什么?

2 个答案:

答案 0 :(得分:10)

要制作透明图层,您应该覆盖控件的绘制并按此顺序绘制控件,首先在您控制的同一容器中绘制所有控件(基于z-index) )在位图上。 然后在控件的图形上绘制该位图。 最后绘制控件的内容。 此外您的控件的BackColor应为Color.Transparent

另外,作为制作透明图层的另一个选项,您可以在绘图时从控件中排除某些区域。

在以下示例中,我使用了第一种技术并创建了2个控件。一个spinning circles透明控件。和transparent picturebox控件。

在两个样本中,我在加载行之间使用延迟来显示一个有意义的微调器。

示例1 - 使用SpinningCircles控件

SpinningCircles控件绘制圆圈并支持透明度。控件在设计时没有动画,但在运行时动画。当它不可见时它也不消耗资源。

enter image description here

示例2 - 使用TransparentPictureBox控件和透明动画gif TransparentPictureBox控件支持透明度,因此我使用动画gif作为其图像,正如您所看到的,gif正确显示。

enter image description here

示例1代码 - 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);
    }
}

示例2代码 - TransparentPictureBox代码

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

答案 1 :(得分:0)

我略微更改了Reza的代码(SpinningCircles)以添加半透明背景。我想和你分享。 (注意:旋转器长度固定为100,应作为组件属性添加)

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
}