Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Making Transparent Controls - No Flickering

0.00/5 (No votes)
16 Aug 2012 1  
This article provides an approach to a Transparent Control that draws an ellipse with real transparent background and a brush that supports transparent colors.

Introduction   

When I wrote the article "Making Transparent Control" in 2005, the feature that I knew back then to get transparency was using the CreateParams class. Unfortunately this solution is not perfect and did the control get flickering. This let me sad.

Later, I tried to work on a new solution that could eliminate all the issues presented with the version made with CreateParams. The basic idea was to capture the image behind of the Control and use it as background. Finally, after exploring thoroughly the MSDN library I came across the DrawToBitmap method and finally arrived at the solution that I so wanted.

Since then, I've been using this new control and now would like to share that solution with the CodeProject community. The TranspControl and the DemoProgram were created under Windows 7 X64 platform and no problems were noted during the tests.

The following will describe the most important features of TranspControl:

Transparency Modes

The background of TranspControl is designed to have two modes of transparency. This will allow the control to be used in the most diverse application situations. In both modes, the non-background part can be semi-transparent, opaque or even transparent.

Glass Mode

In Glass mode, the background is like a glass. It can be translucent, semi-transparent or opaque. The level of transparency must be adjusted in the Opacity property. The Opacity property ranges from 0 to 100 where the value 0 makes the Control translucent and the value 100 makes the Control fully opaque. The Opacity affects also the fill color of drawn objects, such as shapes, for example. The fill color is determined in the FillColor property and the background color is determined in the GlassColor property. Setting the GlassColor property to color Transparent you get a translucent background.

True Transparent Background

In this mode, the Control region does not contain a background and only the drawn object is rendered. There, you can also set the level of transparency through the Opacity property.

In the figure shown above, the color of the shape border line was set to transparent color.

Setting the FillColor property to color Transparent, the inner part of the shape will not be rendered and you get an effect like a holed shape.  

Semitransparent Image

Additionally, TranspControl has support for semitransparent image. The effect of the image transparency is also adjusted in the Opacity property. A transparency key is provided in order you can determine the transparent color for the image background.

The picture shown above has a white color background. So, the key color was set to the color white. As you can see, the background of the image became transparent.

Getting the Background

The trick to get an effect of transparent background is to grab the image behind the Control to the Control itself. The method DrawToBitmap is very appropriate for this purpose.

For reasons of discipline, this is done in the OnPaintBackgroud method. See the code.

protected override void
OnPaintBackground(PaintEventArgs e)
{
    base.OnPaintBackground(e);
    Graphics g = e.Graphics;
 
    if (Parent != null && !drag)
    {                    
        int index = Parent.Controls.GetChildIndex(this);
 
        for (int i = Parent.Controls.Count - 1; i > index; i--)
        {
            Control c = Parent.Controls[i];
            if (c.Bounds.IntersectsWith(Bounds) && c.Visible)
            {
                Bitmap bmp = new Bitmap(c.Width,
                c.Height, g);
                c.DrawToBitmap(bmp, c.ClientRectangle);
                g.TranslateTransform(c.Left - Left, c.Top - Top);
                g.DrawImageUnscaled(bmp, Point.Empty);
                g.TranslateTransform(Left - c.Left, Top - c.Top);
                bmp.Dispose();
            }
        }
    }
 
    if (BackImage != null && GlassMode && !drag)
    {
        Bitmap image = new Bitmap(BackImage);
            image.MakeTransparent(TranspKey);
            float a = (float)opacity / 100.0f;
 
        float[][] mtxItens = {
        new float[] 
            {1,0,0,0,0},
        new float[]
            {0,1,0,0,0},
        new float[]
            {0,0,1,0,0},
        new float[]
            {0,0,0,a,0},
        new float[]
            {0,0,0,0,1}};
        ColorMatrix colorMatrix = new ColorMatrix(mtxItens);
 
        ImageAttributes imgAtb = new ImageAttributes();
       
imgAtb.SetColorMatrix(
        colorMatrix,
        ColorMatrixFlag.Default,
        ColorAdjustType.Bitmap);
 
        g.DrawImage(
                image,
               
ClientRectangle,
                0.0f,
                0.0f,
                image.Width,
                image.Height,
                GraphicsUnit.Pixel,
                imgAtb);
    }
}

Drawing the Control

Here you draw your code. Just for a sample I drew a simple ellipse. See the code.

protected override void
OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
     
    ///////////////////////////////
    // SETTINGS          //
    ///////////////////////////////
 
    Graphics g = e.Graphics;
    g.SmoothingMode = SmoothingMode.AntiAlias;
    g.PixelOffsetMode = PixelOffsetMode.HighQuality;
   
    g.CompositingQuality = CompositingQuality.GammaCorrected;
 
    RectangleF bounds = this.ClientRectangle;
    alpha = (opacity * 255) / 100;
         
    float penWidth = (float)LineWidth;
    Pen pen = new Pen(Color.FromArgb(alpha, ForeColor), penWidth);
    pen.Alignment = PenAlignment.Center;
 
    Brush brushColor = new SolidBrush(Color.FromArgb(alpha,
        FillColor));
    Brush bckColor = new SolidBrush(Color.FromArgb(alpha,
        GlassColor));
 
    ///////////////////////////////
    //    DRAW YOUR SHAPE HERE   //
    ///////////////////////////////
 
    GraphicsPath shape = new GraphicsPath();
    GraphicsPath regionShape = new GraphicsPath();
    GraphicsPath innerShape = new GraphicsPath();
            
    // Create a shape region for non glass mode
   
    regionShape.AddEllipse(bounds);
    Region region = new Region(regionShape);
 
    // Create the inner region for non glass mode
    RectangleF inner = bounds;
   
    inner.Inflate(-penWidth, -penWidth);
   
    inner.Inflate(-2.0f, -2.0f);
   
    innerShape.AddEllipse(inner);
    Region innerRegion = new Region(innerShape);
         
    // Fill the region background
    if (GlassMode)
    {
        Region = new Region();
        if (GlassColor != Color.Transparent && Opacity > 0)
        {
            g.FillRegion(bckColor, Region);
        }
    }
    else
    {             
        // Make a hole inside the shape if FillColor is transparent
        if (FillColor == Color.Transparent || Opacity == 0)
        {
            region.Exclude(innerRegion);      

        }
        Region = region;
    }
    // Add a shape to the path
   
    bounds.Inflate(-1.0f, -1.0f); //fit the
    ellipse inside the region
   
    shape.AddEllipse(bounds);
 
    // Fill the shape with a color
    if (FillColor != Color.Transparent && Opacity > 0)
    {
        g.FillPath(brushColor, shape);
    }
 
    // Draw the shape outline
    bounds.Inflate(-penWidth / 2.0f, -penWidth / 2.0f);
    if (ForeColor != Color.Transparent && Opacity > 0)
    {
        g.DrawEllipse(pen, bounds);
    }
 
    ///////////////////////////////
    //       FREES MEMORY        //
    ///////////////////////////////
 
    brushColor.Dispose();
    bckColor.Dispose();
    pen.Dispose();
    regionShape.Dispose();
    innerShape.Dispose();
    shape.Dispose();
   
    innerRegion.Dispose();
    region.Dispose();
    }

}

Examples

Below you can see some examples I have used to test the TranspControl component. The following Form properties were changed:

BackColor:         Color.White
BackgroundImage:   TechPaper.png
DoubleBuffered:    True

On the right side of the Form there are picture boxes behind the TranspControl. The picture boxes contain animated gif images and you can watch the animation even they are behind the Control.

As another point of interest is the circle over the button. There you can press the button with the mouse even in the inner part of the circle.

Cheers. Hope this article can be helpful.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here