Make a shaped button in C#

example

This example shows how to make a shaped button in a Windows Forms C# project. It uses the following Load event handler to confine a Button control to a region to give it a non-rectangular shape.

// Shape the button.
private void Form1_Load(object sender, EventArgs e)
{
    // Define the points in the polygonal path.
    Point[] pts = {
        new Point( 20,  60),
        new Point(140,  60),
        new Point(140,  20),
        new Point(220, 100),
        new Point(140, 180),
        new Point(140, 140),
        new Point( 20, 140)
    };

    // Make the GraphicsPath.
    GraphicsPath polygon_path = new GraphicsPath(FillMode.Winding);
    polygon_path.AddPolygon(pts);

    // Convert the GraphicsPath into a Region.
    Region polygon_region = new Region(polygon_path);

    // Constrain the button to the region.
    btnClickMe.Region = polygon_region;

    // Make the button big enough to hold the whole region.
    btnClickMe.SetBounds(
        btnClickMe.Location.X,
        btnClickMe.Location.Y,
        pts[3].X + 5, pts[4].Y + 5);
}

The code makes an array of Point objects that define a polygonal shape for the button. It creates a GraphicsPath object and adds the polygon to it. It then converts the GraphicsPath into a Region and sets the button’s Region property to the result.

Any parts of the Button that fall outside of the Region are clipped off so they are not drawn. They also don’t receive events such as mouse clicks.

(An alternative strategy is to draw a polygon or other shape on a PictureBox and catch Click events that fall inside the shape. That works but doesn’t give you the same features that a Button does. For example, it doesn’t show a pressed appearance unless you write code to do it. This example’s button automatically changes color when the user presses the mouse down on it.)


Download Example   Follow me on Twitter   RSS feed




This entry was posted in controls and tagged , , , , , , , , , , , . Bookmark the permalink.

12 Responses to Make a shaped button in C#

  1. Nick says:

    Hi, I am just wondering whether I can change the color of the click area or not.
    If it could, how could I do?

    Many thanks.

  2. Dave says:

    Thanks for the concise explanation. How would you add a border?

    • RodStephens says:

      That’s actually kind of tricky (although it would make the button look a lot better). You could make the button display an image and carefully line up the edges with the image’s edges, but probably the easiest thing to do is give up on using a normal button and use a PictureBox. Then you can create the up and down images and control every pixel. See this example:

  3. jacob says:

    Great little tutorial, wish I had found this sooner. I just have one question. How would you go about making the button movable while in the form editor? I am lazy and don’t want to figure out coordinates every time me or someone else uses the the button. I am designing a form and I need a octagon shaped button. I already created a custom control that lets me choose choose between the standard rectangle shape and an oval shape I defined but i would like to extend it include various shaped like the octagon or various other polygons.

    • RodStephens says:

      Well, because the button is shaped by code, you need that code in your program. Doing things at design time won’t add code to your project so this won’t work with a simple approach.

      What you could do is make a custom control to represent a polygonal button. Then you can create a design-time editor for the control. See these articles:

      It’s a bunch of work, but it is possible. You’d probably want to add tools to the editor to let you draw standard shapes such as regular polygons, arrows, ellipses, etc.

      It would be easier to make a simple drawing application that records a sequence of button clicks to make it easier to create code for the polygon.

      • jacob says:

        Thank you very much for a quick response.

        Before I scrap all the code I been playing with, I got something else that may work.

        In my custom control now I have an elliptical button that is created by grabbing the ClientRectangle and then passing that to the DrawEllipse() method.
        Doing that lets me put a custom elliptical button on the form and move it around in the form designer.

        So my last ditch attempt is going to be to override the DrawPolygon and FillPolygon methods to allow me to base the coordinates off the clientRectangle like with the ellipse. And if that doesn’t do it then I shall be making a simple drawing application.

        Thanks again!

  4. RodStephens says:

    [Jacob posted this reply. I’m reposting it to start a new comment thread so it isn’t indented as much.–Rod]

    In case anyone was curious about how to do what I was talking about I got it to work. Instead of overriding the draw and fill methods I wrote a method to calculate the octagon points based of the buttons height and center like this.

    public PointF[] GetOctagonPoints(float Height, float Width)
        {
            Height -= 10;
            Width -= 10;
            PointF[] OctagonPoints = new PointF[8];
            float edgeLength = Height * 0.4142f;
            float cLength = (Height - edgeLength) / 2.0f;
            PointF p1 = new PointF(10.0f, cLength);
            PointF p2 = new PointF(10.0f, (cLength + edgeLength));
            PointF p3 = new PointF(cLength, Height);
            PointF p4 = new PointF((Width - cLength), Height);
            PointF p5 = new PointF(Width, (cLength + edgeLength));
            PointF p6 = new PointF(Width, cLength);
            PointF p7 = new PointF((Width - cLength), 10.0f);
            PointF p8 = new PointF(cLength, 10.0f);
    
            OctagonPoints[0] = p1;
            OctagonPoints[1] = p2;
            OctagonPoints[2] = p3;
            OctagonPoints[3] = p4;
            OctagonPoints[4] = p5;
            OctagonPoints[5] = p6;
            OctagonPoints[6] = p7;
            OctagonPoints[7] = p8;
    
            return OctagonPoints;
        }

    Then in the control file it is used like this:

    gfx.FillPolygon(new SolidBrush(fill), GetOctagonPoints(
        this.Size.Height, this.Size.Width));
    
    gfx.DrawPolygon(new Pen(Color.Blue, 1.0f), GetOctagonPoints(
        this.Size.Height, this.Size.Width));

    It should also be noted that because a standard octagon has all sides of equal length, if you make the Length:Width ratio anything besides 1:1 you may get weird results.

Leave a Reply

Your email address will not be published. Required fields are marked *