Creating Non-Transparent Controls on a Semi-Transparent Window

Introduction

You can set the transparency for windows in the Windows system, thus giving you an opportunity to improve the user's interface. In Windows versions beginning from 2000 it is implemented by setting the WS_EX_LAYERED style for the window. But here we are faced with a problem—the style can't be set for the child windows. The semi-transparent window looks showy but everything that is drawn on it (including controls) will also be semi-transparent. And it considerably worsen the ergonomics of the user's interface.

This article describes the SkinTooltip control developed by the KB_Soft Group company for its internal needs; it allows you to create the effect of non-transparent controls on a semi-transparent window. The approach described below also allows different animations to be implemented on the control when displaying it.

It is necessary to note that the control is not really semi-transparent; it only imitates the transparency. Because of this, some restrictions to its usage, described below, appear.

How the Control Works

The essence of my company's approach to the solution of the given problem follows. The control itself (and all the child controls on it) is not semi-transparent. The semi-transparency of the window is imitated. Two steps are performed for this.

In the first step, the screenshot of the parent window is made by using the following function:

public static void GetControlScreenshot( Control control,
                                         ref Bitmap bitmap )
{
   if (control == null || control.Handle == IntPtr.Zero)
   return;

   if (control.Width < 1 || control.Height < 1) return;

   if (bitmap != null)
      bitmap.Dispose();

      // preparing the bitmap.
      bitmap = new Bitmap(control.Width, control.Height);
      Graphics destGraphics = Graphics.FromImage(bitmap);

   // setting the flag indicating that we need to print both the
   // client's and the non-client's window rectangles.
   int printFlags = (int)( Win32API.PRF_NONCLIENT |
                           Win32API.PRF_CLIENT);

   System.IntPtr param = new System.IntPtr(printFlags);
      System.IntPtr hdc = destGraphics.GetHdc();

   // sending the WM_PRINT message to the control window.
      Win32API.SendMessage(control.Handle, Win32API.WM_PRINT,
                           hdc, param);
      destGraphics.ReleaseHdc(hdc);

      destGraphics.Dispose();
}

The function draws the control window to the "bitmap" bitmap. It is made with the help of the SendMessage Win32 function. It sends the WM_PRINT message to the window; its parameters specify the device context for output.

The controls of the parent window also are drawn at the obtained image. Then, the image is displayed on the control's surface and, as a result the control, becomes invisible on the parent window.

In the second step, the background of the semi-transparent window is set to another object of the Bitmap class. The background should present the image with the set semi-transparency (in other words, having the alpha-channel). All child controls are drawn on the image (it is needed to implement animation). The obtained image is drawn above the background already displayed and all the controls become visible. As a result, you have the effect of a semi-transparent window with non-transparent controls.

Animation is performed using the image obtained in the second step. To reach the effect of the control's smooth appearance on the parent window's background, the alpha value for each bitmap's pixel is multiplied according to the timer's message on a multiplier in the range from 0 to 1.0. As a result, the image varies from complete transparency to the value initially set in the image that is specified as a control's background in the second step. To perform it, the .NET Framework library has a standard mechanism based on the ColorMatrix class. You can use the class to specify the transformations to be done with the image's colors before it is displayed on the screen.

Some restrictions concerning the control's usage result from the algorithm described. Because the screenshot of the state of all the controls on the parent window is made only once before displaying, the changes in their appearance may break the illusion of semi-transparency. Any changes in the child controls on the semi-transparent window after its first initialization may also lead to the control's malfunction. The given restrictions were not critical for the task KB_Soft Group was faced with when developing the given controls, but the component's elaboration may be necessary for other cases.

How to Use the Control

The control was inherited from the SkinControl base class. The class usage was described in the "Creating Arbitrarily Shaped Controls" article.

The most important properties and functions of the class are described below.

Property Function
AlphaAnimation Determines whether to use the animation by using smooth transparency changing
AnimationInterval Sets the time interval between two animation steps
AnimationPosition Setts the position to start the control's animation
AnimationSteps Sets the number of animation steps
ExpandAnimation Sets the animation type by changing the control's sizes
ExpandType Sets the animation type by changing the control's sizes (moving, stretching, and so on)
FrontImage Sets the control's background image
Labels The collection of non-transparent labels on the semi-transparent window
Animate() Starts the control's animation

Creating Non-Transparent Controls on a Semi-Transparent Window

The simplest way to use the control is to add it to the Toolbox in the Visual Studio environment and set all its properties. But, for more deliberate usage of the control, its manual creation is given below:

  1. Create a new Windows application project in C#. Add a new resource—the result.png image. It will be your control's background and also a pattern to specify its shape. Don't forget to specify Build Action = Embedded Resource in the resource's properties.
  2. Add the application a link to the KBSoft.Components.dll library, and add the corresponding using directives to the beginning of the file containing the form:
  3. using KBSoft.Components;
  4. Now add the class to a new item:
  5. private SkinTooltip skinTooltip = new SkinTooltip();
    private Button btn = new Button();
    
  6. Add the following code to the constructor:
  7. //getting the assembly for extracting the resources.
    Assembly currentAssembly =
       Assembly.GetAssembly( this.GetType() );
    
    //setting the pop-up animation.
    skinTooltip.AlphaAnimation = true;
    
    //setting the time interval between animation steps.
    skinTooltip.AnimationInterval = 40;
    
    //the position to display the control.
    skinTooltip.AnimationPosition =
       new System.Drawing.Point(80, 24);
    
    //the number of animation steps.
    skinTooltip.AnimationSteps = 20;
    
    //setting to not use animation by changing the control's
    //sizes.
    skinTooltip.ExpandAnimation = false;
    
    //setting the image of the control's background.
    skinTooltip.FrontImage = (Bitmap)Bitmap.FromStream( 
    currentAssembly.GetManifestResourceStream(
       "TestControls.result.png") );
    
    //setting the control's shape.
    skinTooltip.PatternBitmap = (Bitmap)Bitmap.FromStream(
       currentAssembly.GetManifestResourceStream(
       "TestControls.result.png") );
    
    //setting the color of the image parts that are not
    //included in the control's region
    skinTooltip.TransparentColor =
       Color.FromArgb( 255, 255, 255 );
    
    //creating the button and adding it to the list of the
    //controls that are children for the skinTooltip control
    
    btn.Size      = new Size(50,30);
    btn.Location  = new Point(150,30);
    btn.Text      = "Demo";
    btn.FlatStyle = FlatStyle.System;
    skinTooltip.Controls.Add( btn );
    
    //the call needed for the control to function correctly.
    skinTooltip.EndInit();
    
    //necessarily set the control's parent window.
    skinTooltip.Parent = this;
    

The result is shown in the following screenshot.



About the Author

Alexander Golovanov

Alexandr Golovanov is a .NET developer at KB_Soft Group, an offshore software development company located in Russia, Novosibirsk. Here he has worked on various .NET projects.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Where the business performance of their mobile app portfolios are concerned, most companies are flying blind. While traditional application portfolios are held to all kinds of ROI measure, the investment plan for mobile apps -- increasingly the more crucial bet -- is made by guesswork and dart-throwing. This interactive e-book investigates how mobile is driving the need for app and portfolio measures unlike any we saw in the days of web. Good mobile analytics must deliver leading indicators of user experience …

  • Protecting business operations means shifting the priorities around availability from disaster recovery to business continuity. Enterprises are shifting their focus from recovery from a disaster to preventing the disaster in the first place. With this change in mindset, disaster recovery is no longer the first line of defense; the organizations with a smarter business continuity practice are less impacted when disasters strike. This SmartSelect will provide insight to help guide your enterprise toward better …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds