Regions, Nonrectangular Forms, and Controls in GDI+


This article has been excerpted from book "Graphics Programming with GDI+".

When we're writing Windows applications with drawing functionality, it becomes important to understand the roles of regions, client areas, and nonclient areas. This section will describe an exciting and wonderful use of regions.

Figure 6.18 shows a typical rectangular form. As you can see, the title bar area usually contains the title of the form, as well as minimizes, maximize, and close buttons. This is the nonclient area; the rest of the form is the client area. Graphics object can be drawn only in the client area. The combination of both client and nonclient areas is the default region of a form.

What exactly is a region? A region is a collection of pixels that represents parts of a control. GDI+ is responsible only for drawing the region associated with a window (a form or control). The default region of a window includes both client and nonclient areas, so GDI+ draws the entire window.

Figure 6.18.gif

FIGURE 6.18: Client and nonclient areas of a form.

However, you can force the operating system to display only part of a window. This is where regions are useful.

The Application

This section will show you the importance of regions and how you can use them in real-world applications.

Have you ever thought about writing nonrectangular forms or controls? How about writing circular, triangular, or polygonal forms, buttons, labels, or text boxes? Our example is a Windows application in which the user can select the shape of the form. The user will have options to change the default rectangular form to a circular, triangular, or polygonal form. You will also learn how to create nonrectangular controls such as buttons.

How can we write nonrectangular forms and controls? GDI+ draws only the regions associated with a form or a control. But setting a nonrectangular region should do the trick. This is what we will do in our application. One of the nonrectangular forms of the final application might look like Figure 6.19. As you can see, this technique can be used to build cool looking Windows applications.

Figure 6.19.gif

FIGURE 6.19: A nonrectangular form and controls

Coding

In Windows Forms, every control, including a form, is derived from the Control class. The Region property of the control class represents the region of control. If you set the Region property of a control, only the area covered by that region will be visible to the user. Sections 6.5.2.1 through 6.5.2.6 describe the steps involved in writing code for nonrectangular shapes.

Step1: Create the Application

We create a Windows application, put the three controls on the form, and change the Text properties of the buttons. We also add a context menu and four menu items, as Figure 6.20 shows. In addition, we add menu and button click event handlers.

Step2: Add the Shape Class

Now we add a class to the project. Our class name is Shape, as Listing 6.15 shows. We add two methods to this class: GetPolyRegion and GetRectRegion. Both of these methods return a Region object. The GetPolyRegion method takes an array of Point objects as its only argument. We create a graphics path from the points by calling AddPolygon. After that we create a region from the path and return it. Similarly, we create a region from a rectangle in the GetRectRegion method.

Figure 6.20.gif

FIGURE 6.20: The nonrectangular forms application

LISTING 6.15: The Shape class

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //The Shape class contains the functionality of shaped controls
        public class Shape
        {
            public Shape()
            {
            }
            public Region GetPolyRegion(Point[] pts)
            {
                //Create a graphics path
                GraphicsPath path = new GraphicsPath(FillMode.Alternate);
                path.AddPolygon(pts);
                //Create a Region object from the path and set it as the form's region
                Region rgn = new Region(path);
                return rgn;
            }

            public Region GetRectRegion(Rectangle rct)
            {
                //Create a graphics path
                GraphicsPath path = new GraphicsPath(FillMode.Alternate);
                path.AddEllipse(rct);
                //Create a Region object from the path and set it as the form's region
                Region rgn = new Region(path);
                return rgn;
            }
        }
    }
}

Step 3: Load the Context Menu

Now we load the context menu on the right mouse click of the form. In Listing 6.16, we set the ContextMenu property of the form as the context menu control.

LISTING 6.16: The mouse-down click event handler

            private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Right)
                {
                    this.ContextMenu = this.contextMenu1;
                }
            }

Step 4: Call the Shape Class Methods

Now we call GetRectRegion and GetPolyRegion from the context menu click event handlers to get the region for a rectangle or a polygon. After getting a Region object corresponding to a rectangle or a polygon, we just need to set the Region property of the form. Listing 6.17 shows the code for the context menu click event handlers.

LISTING 6.17: Menu item click event handlers

        private void CircleMenu_click(object sender, Sytem.EventArgs e)
        {
            //Create a rectangle
            Rectangle rect = new Rectangle(50, 0, 300, 300);
            //Create a Shape object and call the GetRecRegion method
            Shape shp = new Shape();
            this.Region = shp.GetRectRegion(rect);
            this.Backcolor = Color.BurlyWood;
        }

private void RectMenu_Click(object sender System.EventArgs e)
        {
             //A Points array for a rectangle
            //Same points as the original form
            Point[] pts =
             new Point (0, 0),
             new Point (0, originalSize.Height),
             new Point (originalSize.Width, originalSize.Height),
            new Point (originalSize.Width, 0)
            };

             //Create a shape object and call the GetPolyRegion method
            Shape shp = new Shape();
             this.Region = shp.GetPolyRegion(pts);
             //Set background color
             this.BackColor = Color.DarkGoldenrod;
        }

private void TriangleMenu_Click(object sender, System.EventArgs e)
        {
            //Add three lines to the path representing three sides of a triangle
            Point[] pts =
        {
                new Point (50,0),
                new Point (0,300),
                new Point (300,300),
                new Point (50,0)
        };

            this.BackColor = Color.CornflowerBlue;
            //Create a Shape object and call the GetPolyRegion method
            Shape shp = new Shape();
            this.Region = shp.GetPolyRegion(pts);
        }

The code in Listing 6.18 for the Close menu item simply closes the form.

LISTING 6.18: The Close menu click event handler

        private void CloseMenu_click(object sender, System.EventArgs e)
        {
            this.Close();
        }

Step 5: Display Nonrectangular Shapes

Using similar methods, you can set the Region property of controls such as Button or TextBox to display nonrectangular shapes. If you don't want to use the Shape class, you can directly set the Region property of a control. Listing 6.19 sets the Region properties of three buttons. We write this code on the form's load event handler.

LISTING 6.19: Setting the Region properties of buttons

            originalSize = this.Size;
            //Create a REgsion object from the path
            GraphicsPath path1 = new GraphicsPath(FillMode.Alternate);
            path1.AddEllipse(new Rectangle(30, 30, AudioBtn.Width - 60, AudioBtn.Height - 60));
            AudioBtn.Region = new Region(path1);
            GraphicsPath path2 = new GraphicsPath(FillMode.Alternate);
            path2.AddEllipse(new Rectangle(30, 30, VideoBtn.Widht - 60, VideoBtn.Height - 60));
            VideoBtn.Region = new Region(path2);
            GraphicsPath path3 = new GraphicsPath(FillMode.Alternate);
            path3.AddEllipse(new Rectangle(20, 20, VideoBtn.Width - 40, VideoBtn.Height - 40));
            AnimationBtn.Region = new Region(path3);

Step 6: Build and Run

The last step is to run the application and right-click on the form. Figure 6.21 shows the result of selecting the Circle menu option.

Figure 6.22 shows the result of selecting the Triangle menu option.

Using this technique, you can build Windows forms and controls of virtually any shape.

Figure 6.21.gif

FIGURE 6.21: A Circular form

Figure 6.22.gif

FIGURE 6.22: A triangular form

Conclusion

Hope the article would have helped you in understanding the Regions, Nonrectangular Forms, and Controls in GDI+. Read other articles on GDI+ on the website.

bookGDI.jpg
This book teaches .NET developers how to work with GDI+ as they develop applications that include graphics, or that interact with monitors or printers. It begins by explaining the difference between GDI and GDI+, and covering the basic concepts of graphics programming in Windows.


Mindcracker
Founded in 2003, Mindcracker is the authority in custom software development and innovation. We put best practices into action. We deliver solutions based on consumer and industry analysis.