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

C# class for creating cool looking boxes using Windows Forms

0.00/5 (No votes)
25 Jan 2012 1  
Windows Forms don't have to look boring!

Introduction

In Visual Studio, you can choose between the "old fashioned" Windows Forms and the better looking WPF. If you prefer to work with Windows Forms however, you can still make your application look very fancy. In this article, I will show a tool to create some graphical parts programmatically. It is limited to a box that can show text or a picture, but it might give you some inspiration to create your own graphical objects.

I think this code is not very difficult if you have ever used GDI+. To freshen up: if an Image is a painting, then a Bitmap is the canvas with the paint, and Graphics are your brushes (and the artist is you, of course).

The class GraphicTools is able to create boxes like the one on the left in this picture:

Using the Code

Parameters include the image where you would like to draw the box, the text inside the box, the location and size of the box, the width of the border (here 16), and finally the four colors you want to use. (This function is overloaded with a very similar one that puts an image in the box.)

public static Image DrawBox(this Image image, string text, Point p, Size size, int border,
       Color foreColor, Color backColor, Color fillColor, Color textColor)
{
    // Draw the borders
    image.CreateBorders(p, size, border, foreColor, backColor);

    // Fill the inside and add the text
    using (var g = Graphics.FromImage(image))
    {
        g.FillRectangle(new SolidBrush(fillColor),
            new Rectangle(p.X + border, p.Y + border, size.Width 
                - (2 * border), size.Height - (2 * border)));

        StringFormat stringFormat = new StringFormat();

        // Horizontal alignment
        stringFormat.Alignment = StringAlignment.Center;

        // Vertical alignment
        stringFormat.LineAlignment = StringAlignment.Center;    
        g.DrawString(text, new Font("Arial", 10, FontStyle.Bold),
            new SolidBrush(textColor), p.X + (size.Width / 2), 
            p.Y + (size.Height / 2), stringFormat);
    }

    return image;
}

The most important part is the creation of the borders. The four corner pieces are created using a gradient filled circle (foreColor in the middle, backColor on the outside).

private static Image CornerBox(int border, Color foreColor, Color backColor)
{
    Image cornerImage = CreateImage(new Size(border * 2, border * 2), backColor);
    using (var g = Graphics.FromImage(cornerImage))
    {
        var p = new GraphicsPath();
        p.AddEllipse(0, 0, border * 2, border * 2);
        var pgb = new PathGradientBrush(p);
        pgb.SurroundColors = new Color[] { backColor };
        pgb.CenterColor = foreColor;
        g.FillRectangle(pgb, 0, 0, border * 2, border * 2);
    }
    return cornerImage;
}

Each quadrant of this circle forms one of the corners of the box, so in the CreateBorders function, we can use:

private static Image CreateBorders(this Image image, Point p, Size size, 
        int border, Color foreColor, Color backColor)
{
    // Draw the corners
    Image cornerBox = CornerBox(border, foreColor, backColor);
    image.Merge(p, cornerBox,
        new Rectangle(0, 0, border, border));            // Left Top
    image.Merge(new Point(p.X + size.Width - border, p.Y), cornerBox,
        new Rectangle(border, 0, border, border));       // Right Top
    image.Merge(new Point(p.X, p.Y + size.Height - border), cornerBox,
        new Rectangle(0, border, border, border));       // Left Bottom
    image.Merge(new Point(p.X + size.Width - border, 
        p.Y + size.Height - border), cornerBox,
        new Rectangle(border, border, border, border));  // Right Bottom

The box also contains four rectangular pieces, so this function continues:

// Draw the horizontal bars
if (size.Width > (2 * border))
{
    // Else the width of the horizontal bars is equal to or less than zero
    var rectangle = new Rectangle(0, 0, size.Width - (2 * border), border);
    using (var img = CreateImage(
        new Size(rectangle.Width, rectangle.Height), backColor))
    {
        using (var g = Graphics.FromImage(img))
        {
            // Top
            g.FillRegion(new LinearGradientBrush(rectangle, 
                backColor, foreColor, 90f), new Region(rectangle));
            image.Merge(new Point(p.X + border, p.Y), img, rectangle);
            // Bottom
            g.FillRegion(new LinearGradientBrush(rectangle, 
                foreColor, backColor, 90f), new Region(rectangle));
            image.Merge(new Point(p.X + border, p.Y + size.Height - border)
                , img, rectangle);
        }
    }
}

// Draw the vertical bars
// Very similar...

The way the different parts of the box are created might seem a little bit strange: instead of immediately drawing on the image of the box, smaller images are created, drawn upon, and then merged with the image of the box. This is because of the behavior of the LinearGradientBrush: it does not start with the first color on the place where you start drawing, but at the beginning of the image on which you draw. This seemed the most practical solution, but I admit it might not be the most elegant one.

There are two rather technical functions used: CreateImage, which creates an image of a certain size by creating a bitmap of that size (as Image is in fact an abstract class), and Merge, which puts the smaller image parts on the box. You can find them in the download of course.

Can the result indeed be as fancy as the title of this article predicts? Well, let's make a little application that creates a visual representation of a spider graph. I made a class of animal (how original), with the name of the animal and a picture as fields. Let's fill up a list of animals:

private void FillAnimalList()
{
    string fileLoc = Application.StartupPath;

    Animals.Add(new Animal("Tiger", 
        Image.FromFile(fileLoc + "\\tiger.bmp")));
    Animals.Add(new Animal("Black panther", 
        Image.FromFile(fileLoc + "\\black panther.bmp")));
    Animals.Add(new Animal("Lion", 
        Image.FromFile(fileLoc + "\\lion.bmp")));
    Animals.Add(new Animal("Leopard", 
        Image.FromFile(fileLoc + "\\leopard.bmp")));            
    Animals.Add(new Animal("Bobcat", 
        Image.FromFile(fileLoc + "\\bobcat.bmp")));
    Animals.Add(new Animal("Jaguar", 
        Image.FromFile(fileLoc + "\\jaguar.bmp")));
}

"Tiger" is my main actor here, the others are his friends. I want each animal to be represented by a box containing its picture and a smaller box with its name.

private static Image DrawAnimal(Image imageToDrawOn, Image imageOfAnimal, 
        string name, Point location, Color color)
{
    // Box with picture
    imageToDrawOn.DrawBox(imageOfAnimal, 
        new Point(location.X-80, location.Y-96), 
        new Size(160, 160), 16, color, Color.Black);

    // Box with name
    imageToDrawOn.DrawBox(name, 
        new Point(location.X-80, location.Y + 64), 
        new Size(160, 32), 16, color, Color.Black, color, Color.Black);
    return imageToDrawOn;
}

"Tiger" has to be in the middle, with a connection to each friend. We draw this on a PictureBox:

private void frmMain_Load(object sender, EventArgs e)
{
    FillAnimalList();

    // Fill the picturebox with a solid color
    pictureBox.Image = GraphicTools.CreateImage(pictureBox.Size, Color.Black);

    int mX = pictureBox.Width/2;
    int mY = pictureBox.Height/2;            

    List<Point> pointList = new List<Point>();

    // This is the location where tiger is going to be
    pointList.Add(new Point(mX, mY)); 

    int distance = pictureBox.Height / 3;
    double cornerBetweenAnimals = (2 * Math.PI) / (Animals.Count - 1);

    // Draw connections between the animals
    using(var g = Graphics.FromImage(pictureBox.Image))
    {
        g.SmoothingMode = SmoothingMode.AntiAlias;
        for (int i = 0; i < 5; i++)
        {
            // Location of the other animals
            Point p = new Point(
                (int)(mX - (distance * Math.Cos((Math.PI/4) 
                + (cornerBetweenAnimals * i)))), 
                (int)(mY - (distance * Math.Sin((Math.PI/4) 
                + (cornerBetweenAnimals * i)))));
            pointList.Add(p);
            var pen = new Pen(new LinearGradientBrush(
                pointList[0],p, Color.Blue, Color.Black));
            pen.Width = 10;
            // Draw a connection from tiger to a friend
            g.DrawLine(pen, pointList[0], p); 
        }

    }
    // Draw the animals
    for (int i = 0; i < 6; i++)
    {
        pictureBox.Image = DrawAnimal(pictureBox.Image, 
            Animals[i].image, Animals[i].name,
            pointList[i], Color.Blue);
    }                       
}

And that results in this beautiful friendship:

friendsoftiger.jpg

Points of Interest

I did learn something about big cats while making the example.

History

First version.

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