Creating Arbitrarily Shaped Controls

Introduction

When implementing a project, I needed to create controls of an arbitrary (convex) shape. The shape should not only influence the appearance, but also determine what region of the control should respond to mouse activity. There should be some restrictions concerning the region: It should have no cavities and should be convex. The significance of the restrictions will be described in detail later.

For the control to be conveniently used, I decided to specify its shape with the help of an image (a 32-bit bitmap). The control's boundary is presented in the picture as a closed line. The control is extracted from the image during the analysis as a sequence of points defining the curve. The region restricted by the curve is a client's resulting region of the control.

The control's functionality is implemented in the convenient SkinControlbase class. By inheriting a control from it, you may create your own controls that have a non-standard shape.

Using the Controls Inherited from the SkinControl Class

The project available for download presents three controls implemented by the KB_Soft Group company for its internal needs. These controls are based on the SkinControl common base class and are described below:

KBSoft.Components.SkinButton: The button whose appearance is defined by four images (one for each state—pressed, disabled, hot, and normal).

KBSoft.Components.SkinTextbox: The text box whose appearance and boundaries are specified by an image.

KBSoft.Components.Skintooltip: The pop-up window supporting the first two controls placed on it. It has a number of animations.

The SkinControl base class has the following properties and methods:

Property or Method

Description

PatternBitmap

Sets the image, whose boundaries will be a source of information for forming the region that restricts the control

TransparentColor

The color defining the region of the image. It is specified by the PatternBitmap property that is not included in the control

UseCashing

Being set, the property indicates that the control's region is calculated only once during the first creation. After that, it is stored to the static collection that allows the time for the repeated control's initialization to be considerably shortened

The SkinControl class is inherited from the UserControl class and implements the ISupportInitialize interface. The EndInit method calculates the control's region if the UseCashing flag is not set. The method is added automatically to the code of the control's initialization when it is created with the help of the Visual Studio 2003 designer. Below is an example of manually creating the SkinButton button without using the shape designer.

First, create a new Windows application and add a new variable to the main window class (Form1, by default):

Creating Arbitrarily Shaped Controls

The Description of the Bitmap Scan Algorithm

To reach the effect shown in the screenshots, a rather simple approach is used. This approach is shown in the following figure:

Shown in the figure is the initial image. Let the white color be set as a color for cutting off. Scanning the image is performed pixel by pixel, line by line. The pixels' enumeration stops when the pixel with the color that does not coincide with the color set for cutting off is found. The pixel's coordinates are kept. First, scanning from left to right, the pass from up to down is performed; as a result, the left boundary of the image is obtained. After that, it goes from down to up, scanning the pixels from left to right; as a result, the right boundary is obtained.

Reading pixels is performed with the help of the GetPixel(int i, int j) function of the Color class. When all boundary pixels are found, the closed outline is built based on them with the help of the GraphicsPath class. Then, the resulting control's region is built formed by the intersection of the interior of the region and the initial rectangular region of the control with the help of the Intersect() function of the Region class. It is important to note that the control's shape should imply that the line drawn along the line of pixels should intersect the boundary only in two places. That is why, for example, the button with cavities can't be created with the help of the algorithm. The choice of the simplified algorithm may be explained by the functionality being enough for KB_Soft Group. Besides, the algorithm of line scan of the bitmap is the fastest. You may modify the UpdateRegion() function to extend the functionality of the controls described above.

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.

Top White Papers and Webcasts

When individual departments procure cloud service for their own use, they usually don't consider the hazardous organization-wide implications. Read this paper to learn best practices for setting up an internal, IT-based cloud brokerage function that service the entire organization. Find out how this approach enables you to retain top-down visibility and control of network security and manage the impact of cloud traffic on your WAN.

U.S. companies are desperately trying to recruit and hire skilled software engineers and developers, but there is simply not enough quality talent to go around. Tiempo Development is a nearshore software development company. Our headquarters are in AZ, but we are a pioneer and leader in outsourcing to Mexico, based on our three software development centers there. We have a proven process and we are experts at providing our customers with powerful solutions. We transform ideas into reality.