Export (0) Print
Expand All

Shaped Windows Forms and Controls in Visual Studio .NET

Visual Studio .NET 2003
 

Seth Grossman
Visual Studio Team
Microsoft Corporation

January 2002

Summary: It is easy to customize the shape of both Windows Forms and controls. All that is required for non-standard forms is an image file and a few property settings. Custom-shaped controls require merely a few lines of code. (7 printed pages)

Contents

Introduction
Methodology
Get In Shape
It's Not Hip To Be Square
Next Steps
Conclusion

Introduction

In previous versions of Microsoft® Visual Basic®, creating non-rectangular forms and controls was a time-consuming and labor-intensive process that involved API calls and extensive difficult programming efforts.

Not anymore - one of the niftiest aspects of Windows Forms is that you can craft them into non-rectangular shapes. Microsoft Windows Media™ Player 7 exhibits this feature, and, without doubt, many developers who see this want to incorporate it into their own applications.

Additionally, you can draw controls on a form in a variety of shapes. An application featuring non-rectangular forms and controls will have a distinctive, eye-catching look for those users accustomed to standard windows and controls.

Both Windows Forms and controls can be drawn in unconventional shapes. This article demonstrates how to create an irregularly shaped form and then create controls that are non-traditionally shaped to put on that form.

Note   Be aware that this process involves a great deal of graphics programming; as a result, computers will perform differently based on memory and graphics cards present. Always test any applications that involve custom drawing on a variety of video cards to ensure satisfactory performance before deploying to users.

Methodology

Briefly, creating non-rectangular forms works in the following manner. First, you create a bitmap, which, when we are finished, will act as your form. (Accordingly, you should make it large enough to accommodate all the controls you plan to put on it.) Second, you manipulate a few properties to make this bitmap become the form.

Also, you are going to set a property to remove the title bar (as your form would look weird if it had a fancy shape with the same old rectangular title bar above it). However, when you remove the title bar, you lose all the functionality that is associated with it, including moving the form and closing it. So, you will write code to replace these lost features, so that users can continue to interact with you forms in the way that they expect.

Thus, in order to customize the shape of the forms in your Windows-based application, you must:

  • Create a .bmp file that will be used to set the desired shape of the form.
  • Create a Windows Application project and set properties to use the .bmp as the background of the form and get rid of the title bar.
  • Enter code that recreates the functionality that the title bar provided, such as moving the form and closing it.

Get In Shape

This section demonstrates step-by-step how to create a form in a non-standard shape.

To create a bitmap with a non-rectangular shape

  1. Open a graphics program that allows you to draw bitmaps. For example, you can use the Microsoft Paint application, which is available through the Start menu (point to Programs, then point to Accessories, then click Paint).
  2. In the Paint program, create a non-rectangular shape of one color with a distinct background of another color. The shape you draw will ultimately be your form, so be sure to draw it large enough to be useful.

    Below is an example:

    Figure 1

    Note   Choose an easy-to-remember background color, such as blue, as this will be important later on.
  3. Save the .bmp file.

With a bitmap in hand to serve as an outline for the form, we are ready to create a project.

Create the Project

To set the background in order to establish the shape of the form

  1. In the Windows Forms Designer, click the form so that it has focus.
  2. In the Properties window:
    • Set the FormBorderStyle property to None.

      This property removes the title bar from the form (This also gets rid of all the functionality that is provided by a title bar, including the ability to close the form and move the form around the screen. However, this article includes code that will fix this problem).

    • Set the BackgroundImage property of the form to the .bmp you created above. There is no need to add the file to the project system; this will be done automatically when you specify it as the background image.

      This property sets the bitmap image to be the background of the form. (When used in tandem with the TransparencyKey property specified below, this defines the shape of the form.)

    • Set the TransparencyKey property to the background color of the .bmp file. In the case of the example above, you would set it to blue.

      This property tells the application which parts of the form you want to see through. (Effectively, we will "cut out" the desired shape of the form from a rectangle.)

      Note   Monitors set to a color depth of greater than 24-bit can display problems with certain parts of the form not being transparent, despite setting of the TransparencyKey property. To avoid this problem, ensure that the monitor's color depth is set to less than 24-bit in the Display control panel. When developing applications that feature this transparency, keep in mind that you will have to make your users aware of this issue.
  3. Save the application. Run it by pressing F5.

    Note that, at run time, your Windows Form now looks like your bitmap. Also, notice that there is no title bar available for easy moving or closing of the application. Press ALT+F4 to close your application and continue development.

Setting the FormBorderStyle to None disables the standard functionality provided by the title bar. Thus, you must add custom code to the project to allow the form to be moved. The following procedure adds a Button control to close the form and also details how to write code to move the form.

To write code to move the form

  1. From the Toolbox, drag a Button control to the form.
  2. In the Properties window, set the Text property to "Close Form".
  3. Double-click the button to add a Click event handler.

    The Code Editor opens, with the insertion point in the button's Click event handler.

  4. Enter code similar to the following to close the form when the button is clicked.
    ' Visual Basic
    Private Sub Button1_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles Button1.Click
       Me.Close()
    End Sub
    
    // C#
    private void button1_Click(object sender, System.EventArgs e)
    {
       this.Close();
    }
    
  5. Next, create a procedure to move the form when it is dragged. Enter code similar to the following to create a new Point object. This will act as a variable when you calculate how to move the form:
    ' Visual Basic
    Private mouse_offset As Point
    
    // C#
    private Point mouse_offset;
    
  6. Create an event handler for the form's MouseDown event. We will write code for it so that a user can click anywhere on the form to drag it somewhere.

    If you are using Visual Basic, create the event handler using the Class Name box at the top of the Code Editor and select (Form1 Events). In the Method Name box, select MouseDown.

    If you are using C#, create the event handler by right-clicking the form in Solution Explorer and choosing View Designer. In the Properties window, click the Events button (the button at the top in the shape of a lightning bolt.) Find the MouseDown event and, in the box to the right, click once. When the insertion point appears, press ENTER to create the event handler. It will be named Form1_MouseDown.

    Enter code similar to the following to assign coordinates to the mouse_offset variable based on the current position of the mouse.

    ' Visual Basic
    Private Sub Form1_MouseDown(sender As Object, _
    e As System.Windows.Forms.MouseEventArgs) _
    Handles MyBase.MouseDown
       mouse_offset = New Point(- e.X, - e.Y)
    End Sub 
    
    // C#
    private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
    {
          mouse_offset = new Point(-e.X, -e.Y);
    }
    
  7. Create an event handler for the form's MouseMove event.

    Enter code similar to the following. When the left mouse button is clicked and the mouse is dragged, the form's Location property is set to the new position.

    ' Visual Basic
    Private Sub Form1_MouseMove(sender As Object, _
    e As System.Windows.Forms.MouseEventArgs) _
    Handles MyBase.MouseMove
       If e.Button = MouseButtons.Left Then
          Dim mousePos As Point = Control.MousePosition
          mousePos.Offset(mouse_offset.X, mouse_offset.Y)
          Location = mousePos
       End If 
    End Sub 
    
    // C#
    private void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
    {
       if (e.Button == MouseButtons.Left) 
       {
          Point mousePos = Control.MousePosition;
          mousePos.Offset(mouse_offset.X, mouse_offset.Y);
          Location = mousePos;
       }
    }
    
  8. Save the application. Press F5 to run it. The form will be shaped like the image you drew at the beginning.

    Click anywhere on the form and drag it to see the move functionality. Click the Close Form button to close the form.

This is great! But we are only halfway there. Now, let's create controls with custom shapes.

It's Not Hip To Be Square

In this section, we will look at how to make controls have a custom shape. Controls do not have a TransparencyKey property, so we use a different approach to coerce them into painting themselves into fancy shapes.

In the previous section, we used an image and some transparent parts of the screen to "cut out" the shape of the form. Drawing a custom-shaped control is done differently. When drawing a custom-shaped control, you will be telling the form how to draw the control, specifying exactly how it should be drawn on what particular coordinates of the screen. If the prospect of doing this concerns you, do not worry; the .NET Framework includes classes and methods that enable this type of custom drawing to be easy to implement.

Non-rectangular Controls

You can think of the area on the screen where the control draws itself as a region. The classes of the .NET Framework supply a control with instructions on how to paint itself; by specifying different instructions, you can tell a control to paint itself the way you want.

The instructions you use will take advantage of the GraphicsPath class, which represents a series of connected lines and curves that you can use to draw shapes. First, you specify an instance of the GraphicsPath class and tell it what shapes you want it to draw. Next, you set the control's Region property to that instance of the GraphicsPath class. This is all that is required to create controls that have a unique interface.

To review, the steps required to customize the shape of the Windows Forms controls are:

  • Create an instance of the GraphicsPath class.
  • Specify the details of the GraphicsPath (size, shape, and so on) so that it will draw the shape you desire for the control.
  • Set the control's Region property to that instance of the GraphicsPath class.

Controls can be made into many shapes. This section demonstrates how to make a button shaped like the words "Click Me!".

To create a button shaped like text

  1. Drag a Button control to the form from the Toolbox.
  2. In the Properties window:
    • Set the (Name) property to CustomButton.
    • Set the BackColor property of CustomButton to a color that will contrast well with the background of your form.
    • Make the Text property of CustomButton to an empty string.
  3. Right-click the form and choose View Code.
  4. Create an event handler for the button's Paint event.

    In the Class Name box at the top of the Code Editor, select CustomButton. In the Method Name box, select Paint.

  5. Enter code similar to the following to paint the face of the button in a customized manner using an instance of the GraphicsPath class.

    The code below has the button paint itself as a string of text in the Arial font. Further, the code specifies the other attributes of the string (size, style, and so on). Then the string is added to an instance of the GraphicsPath class. Finally, the GraphicsPath is set to the button's Region property. A region, as was mentioned earlier, is the defined drawing area of a portion of the screen.

    ' Visual Basic
    Private Sub CustomButton_Paint(ByVal sender As Object, _
    ByVal e As System.Windows.Forms.PaintEventArgs) _
    Handles CustomButton.Paint
       'Instantiate a new instance of the GraphicsPath class.
       Dim myGraphicsPath As New System.Drawing.Drawing2D.GraphicsPath()
       'Specify a string. This will be as the shape of the control.
       Dim stringText As String = "Click Me!"
       'Specify the font family to be used with the string above.
       Dim family As FontFamily = New FontFamily("Arial")
       'Specify the font style to be used with the string above.
       Dim fontStyle As FontStyle = fontStyle.Bold
       'Here is where you specify the height of the string.
       'This integer represents one side of a square.
       'The string you specify will be drawn inside that square.
       'Make the integer larger to draw the string larger,
       'smaller to make the string appear smaller.
       Dim emSize As Integer = 35
       'This is the point that will represent where
       'the text starts. It is calculated from the
       'edge of the control, not the form.
       Dim origin As PointF = New PointF(0, 0)
       'A StringFormat object that specifies
       'text formatting information, such as 
       'line spacing and alignment.
       Dim format As StringFormat = StringFormat.GenericDefault
       'Use the AddString method to create the string whose
       'details you specified above.
       myGraphicsPath.AddString(stringText, family, fontStyle, emSize, origin, format)
       'Set the control's Region property to the instance
       'of the GraphicsPath class you created above.
       CustomButton.Region = New Region(myGraphicsPath)
    End Sub
    
    // C#
    private void CustomButton_Paint(object sender, 
    System.Windows.Forms.PaintEventArgs e)
    {
       //Instantiate a new instance of the GraphicsPath class.
       System.Drawing.Drawing2D.GraphicsPath myGraphicsPath  = new 
    System.Drawing.Drawing2D.GraphicsPath();
       //Specify a string. This will be as the shape of the control.
       string stringText = "Click Me!";
       //Specify the font family to be used with the string above.
       FontFamily family = new FontFamily("Arial");
       //Specify the font style to be used with the string above.
       //Cast FontStyle enum as an int, so that 
       //AddString method can take two
       //or more FontStyle members when creating the 
       //desired font. 
       int fontStyle = (int)FontStyle.Bold;
       //Here is where you specify the height of the string.
       //This integer represents one side of a square.
       //The string you specify will be drawn inside that square.
       //Make the integer larger to draw the string larger,
       //smaller to make the string appear smaller.
       int emSize = 35;
       //This is the point that will represent where
       //the text starts. It is calculated from the edge
       //of the control, not the form.
       PointF origin = new PointF(0, 0);
       //A StringFormat object that specifies
       //text formatting information, such as 
       //line spacing and alignment.
       StringFormat format = new StringFormat(StringFormat.GenericDefault);
       //Use the AddString method to create the string whose
       //details you specified above.
       myGraphicsPath.AddString(stringText, family, fontStyle, emSize, origin, format);
       //Set the control's Region property to the instance
       //of the GraphicsPath class you created above.
       CustomButton.Region = new Region(myGraphicsPath);
    }
    
    Note   Be aware that the GraphicsPath class draws relative to the control, not the form. Drawing a shape at location (0,0) places the shape at the upper-left corner of the control.
  6. Create an event handler for the button's Click event. Write code to change the back color of the button in the Click event handler to see for yourself that all of the standard button functionality is still there, despite the changes to appearance that we have made at run time.

    In the Class Name box at the top of the Code Editor, select CustomButton. In the Method Name drop-down, select Click.

  7. Enter code similar to the following to change the button's BackColor property.
    ' Visual Basic
    Private Sub CustomButton_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles CustomButton.Click
         CustomButton.BackColor = Color.BlanchedAlmond
    End Sub
    
    // C#
    private void CustomButton_Click(object sender, System.EventArgs e)
    {
       CustomButton.BackColor = Color.BlanchedAlmond;
    }
    
  8. Save and run the application.

    When you run the application, you will immediately notice that, in lieu of a rectangular button, your button is in the shape of the words "Click Me!" (If you cannot see the button, close the application and resize the form to be larger.) Additionally, clicking the button will change its color, proving that the original button functionality is still present.

Next Steps

In the example above that used an instance of the GraphicsPath class, you specified a string, which was then used to determine the primary shape of the control. However, you may wish to have controls that are not text-shaped, but rather geometrically shaped (such as a triangle or circle). The .NET Framework includes provisions for this as well.

Rather than specifying a string to render as the shape of the button, you can use shapes that have been predefined within the .NET Framework. Using these shapes in combination allows you a great degree of control over the look of your controls.

Note   The GraphicsPath class has methods that define shapes you can use, such as curves, arcs, pies, and rectangles. In the example below, the code defines four ellipses. When these are applied to a control, such as a button, they look like eyes. Feel free to experiment with combinations of the other shapes defined in the GraphicsPath class.
' Visual Basic
Private Sub Button1_Paint(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles Button1.Paint
   Dim myGraphicsPath As System.Drawing.Drawing2D.GraphicsPath = New _
System.Drawing.Drawing2D.GraphicsPath()
   myGraphicsPath.AddEllipse(New Rectangle(0, 0, 125, 125))
   myGraphicsPath.AddEllipse(New Rectangle(75, 75, 20, 20))
   myGraphicsPath.AddEllipse(New Rectangle(120, 0, 125, 125))
   myGraphicsPath.AddEllipse(New Rectangle(145, 75, 20, 20))
   'Change the button's background color so that it is easy
   'to see.
   Button1.BackColor = Color.Chartreuse
   Button1.Size = New System.Drawing.Size(256, 256)
   Button1.Region = New Region(myGraphicsPath)
End Sub

// C#
private void button1_Paint(object sender, 
System.Windows.Forms.PaintEventArgs e)
{
   System.Drawing.Drawing2D.GraphicsPath myGraphicsPath  = new
System.Drawing.Drawing2D.GraphicsPath();
   myGraphicsPath.AddEllipse(new Rectangle(0, 0, 125, 125));
   myGraphicsPath.AddEllipse(new Rectangle(75, 75, 20, 20));
   myGraphicsPath.AddEllipse(new Rectangle(120, 0, 125, 125));
   myGraphicsPath.AddEllipse(new Rectangle(145, 75, 20, 20));
   //Change the button's background color so that it is easy
   //to see.
   button1.BackColor = Color.Chartreuse;
   button1.Size = new System.Drawing.Size(256, 256);
   button1.Region = new Region(myGraphicsPath);

}
Note   This code takes advantage of the default setting of the FillMode enumeration, which determines how to fill and clip the interior of a closed figure. For more information, see FillMode Enumeration.

Another thing to keep in mind is that the Form class derives from the System.Windows.Forms.Control class. In other words, the instance of the form provided to you by the Windows Forms Designer is ultimately a control. Thus, while you used the "bitmap image" method above to quickly create a custom-shaped form, you could also use an instance of the GraphicsPath class to create a custom-shaped form. Try experimenting with instances of the GraphicsPath class to make your form into crazy shapes.

Conclusion

As we have seen, customizing the look of the forms and controls within your application is very straightforward. For forms, all you need is an image file containing the shape you desire your form to take. Controls require you to specify a GraphicsPath that defines the shape of the control. In the steps above, you have learned the basics of creating forms and controls with custom shapes; now, go forth and create your own customized user interfaces.

Show:
© 2014 Microsoft