Draw rounded rectangles in C#

[rounded rectangles]

The GDI+ library provides lots of methods for drawing shapes such as rectangles, ellipses, lines, and arcs. Unfortunately it doesn’t provide a method for drawing rectangles with rounded corners. You can use a pen with LineJoin property set to Rounded but that only rounds the corners slightly.

This example defines the following MakeRoundedRect method. It returns a GraphicsPath object representing the lines and arcs needed to draw a rectangle with rounded corners. Parameters let you determine which corners are rounded and by how much.

// Draw a rectangle in the indicated Rectangle
// rounding the indicated corners.
private GraphicsPath MakeRoundedRect(
    RectangleF rect, float xradius, float yradius,
    bool round_ul, bool round_ur, bool round_lr, bool round_ll)
{
    // Make a GraphicsPath to draw the rectangle.
    PointF point1, point2;
    GraphicsPath path = new GraphicsPath();

    // Upper left corner.
    if (round_ul)
    {
        RectangleF corner = new RectangleF(
            rect.X, rect.Y,
            2 * xradius, 2 * yradius);
        path.AddArc(corner, 180, 90);
        point1 = new PointF(rect.X + xradius, rect.Y);
    }
    else point1 = new PointF(rect.X, rect.Y);

    // Top side.
    if (round_ur)
        point2 = new PointF(rect.Right - xradius, rect.Y);
    else
        point2 = new PointF(rect.Right, rect.Y);
    path.AddLine(point1, point2);

    // Upper right corner.
    if (round_ur)
    {
        RectangleF corner = new RectangleF(
            rect.Right - 2 * xradius, rect.Y,
            2 * xradius, 2 * yradius);
        path.AddArc(corner, 270, 90);
        point1 = new PointF(rect.Right, rect.Y + yradius);
    }
    else point1 = new PointF(rect.Right, rect.Y);

    // Right side.
    if (round_lr)
        point2 = new PointF(rect.Right, rect.Bottom - yradius);
    else
        point2 = new PointF(rect.Right, rect.Bottom);
    path.AddLine(point1, point2);

    // Lower right corner.
    if (round_lr)
    {
        RectangleF corner = new RectangleF(
            rect.Right - 2 * xradius,
            rect.Bottom - 2 * yradius,
            2 * xradius, 2 * yradius);
        path.AddArc(corner, 0, 90);
        point1 = new PointF(rect.Right - xradius, rect.Bottom);
    }
    else point1 = new PointF(rect.Right, rect.Bottom);

    // Bottom side.
    if (round_ll)
        point2 = new PointF(rect.X + xradius, rect.Bottom);
    else
        point2 = new PointF(rect.X, rect.Bottom);
    path.AddLine(point1, point2);

    // Lower left corner.
    if (round_ll)
    {
        RectangleF corner = new RectangleF(
            rect.X, rect.Bottom - 2 * yradius,
            2 * xradius, 2 * yradius);
        path.AddArc(corner, 90, 90);
        point1 = new PointF(rect.X, rect.Bottom - yradius);
    }
    else point1 = new PointF(rect.X, rect.Bottom);

    // Left side.
    if (round_ul)
        point2 = new PointF(rect.X, rect.Y + yradius);
    else
        point2 = new PointF(rect.X, rect.Y);
    path.AddLine(point1, point2);

    // Join with the start point.
    path.CloseFigure();

    return path;
}

The method creates a GraphicsPath and then adds arcs and lines to it. The basic approach is to repeat two steps four times.

In step 1, the code draws the rectangle’s upper left corner. The method determines whether it should round the rectangle’s upper left corner. If it should do so, the code adds an arc representing that corner and sets point1 to the position where the arc ends. That point is where the top side of the rectangle should begin.

If the code should not round the upper left corner, the code sets point1 to the rectangle’s upper left corner. That’s the position where the rectangle’s top side should begin if the corner isn’t rounded.

In step 2, the code draws the rectangle’s top side. To do that, it determines whether the upper right corner should be rounded and sets point2 appropriately. It then adds a line connecting point1 and point2 to the GraphicsPath.

The method repeats those two steps for the rectangle’s other three corners and returns the GraphicsPath.

The following code shows how the PictureBox control’s Paint event handler uses the MakeRoundedRect method to draw the top rounded rectangle.

const float xradius = 20;
const float yradius = 20;

// Top rectangle.
const float margin = 10;
float hgt = (picSamples.ClientSize.Height - 3 * margin) / 2f;
RectangleF rect = new RectangleF(
    margin, margin,
    picSamples.ClientSize.Width - 2 * margin,
    hgt);
using (Pen pen = new Pen(Color.Green, 5))
{
    GraphicsPath path = MakeRoundedRect(
        rect, xradius, yradius, true, true, true, true);
    e.Graphics.FillPath(Brushes.LightGreen, path);
    e.Graphics.DrawPath(pen, path);
}

This code creates a destination Rectangle and passes it and some other parameters into the MakeRoundedRect method. It then fills and draws the returned GraphicsPath.


Download Example   Follow me on Twitter   RSS feed   Donate


About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in drawing, graphics and tagged , , , , , , , , . Bookmark the permalink.

2 Responses to Draw rounded rectangles in C#

  1. Pingback: Display battery status in a friendly way in C# - C# HelperC# Helper

  2. Mark Dresser says:

    This worked excellently. I changed the inputs to match my project and now have a clean working RRect.

Leave a Reply

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