How to Draw a Rounded Rectangle as the Border for a Rounded Form

How can I draw a rounded rectangle as the border for a rounded Form?

A base implementation of what is described in the comments.

The Form frmRoundCorners provides some properties that allow to draw its rounded area with a custom BackColor, a custom BorderColor and a custom inner border color, acting as a shadow for the internal side of the Form's border.

The Form itself is implemented using a base class, baseForm, derived from Form, so the Form's properties can be set in the Form designer.

The transparency is activated setting the Form's original BackColor equal to its TrasparencyKey, making its ClientArea completely transparent, but drawable.

The Form's original border is set to FormBorderStyle.None in the base class constructor.

I didn't set a specific BackColor/TransparencyKey Color (it must be set in the Form's designer) because I think it's something one need to experiment with. I'd suggest a medium gray color. Avoid red components.

The Form can be moved, clicking on any point of its ClientArea and dragging it.

The minimum/maximum curvature of the Form and its custom Border is set to 15 and 180 degrees. It cannot be changed to a different range using the PropertyGrid.

The rounded area of the Form and its border are drawn using the GraphicsPath.AddArc() method, then applying a Matrix transformation to the Graphics object, both in the Scale and the Transform (position) components. The Size component is untouched.

This is what it looks like:

Rounded draggable borderless Form

using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

[ToolboxItem(false)]
public partial class frmRoundCorners : baseForm
{
private GraphicsPath pathRegion = new GraphicsPath(FillMode.Winding);
private GraphicsPath pathBorder;
Point pMousePosition = Point.Empty;

public frmRoundCorners()
{
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw, true);
InitializeComponent();
}

protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) {
pMousePosition = e.Location;
}
base.OnMouseDown(e);
}

protected override void OnMouseMove(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) {
Point screenPos = PointToScreen(e.Location);
this.Location = new Point(screenPos.X - pMousePosition.X, screenPos.Y - pMousePosition.Y);
}
base.OnMouseMove(e);
}

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);

e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
RoundedCornerRectangle(ClientRectangle);
RectangleF rect = pathRegion.GetBounds();
float scaleX = 1 - (BorderSize / rect.Width);
float scaleY = 1 - (BorderSize / rect.Height);
using (Pen pen = new Pen(BorderColor, BorderSize))
using (Pen penBorder = new Pen(InternalBorderColor, 2))
using (var brush = new SolidBrush(FillColor))
using (var mx = new Matrix(scaleX, 0, 0, scaleY, (pen.Width / 2), (pen.Width / 2)))
{
e.Graphics.Transform = mx;
e.Graphics.FillPath(brush, pathRegion);
e.Graphics.DrawPath(penBorder, pathBorder);
e.Graphics.DrawPath(pen, pathRegion);
}
}

private void RoundedCornerRectangle(Rectangle r)
{
pathRegion = new GraphicsPath(FillMode.Alternate);
float innerCurve = CurveAngle - m_PenSizeOffset;

pathRegion.StartFigure();
pathRegion.AddArc(r.X, r.Y, CurveAngle, CurveAngle, 180, 90);
pathRegion.AddArc(r.Right - CurveAngle, r.Y, CurveAngle, CurveAngle, 270, 90);
pathRegion.AddArc(r.Right - CurveAngle, r.Bottom - CurveAngle, CurveAngle, CurveAngle, 0, 90);
pathRegion.AddArc(r.X, r.Bottom - CurveAngle, CurveAngle, CurveAngle, 90, 90);
pathRegion.CloseFigure();

pathBorder = new GraphicsPath();
pathBorder.StartFigure();
pathBorder.AddArc(r.X + m_PenSizeOffset, r.Y + m_PenSizeOffset, innerCurve, innerCurve, 180, 90);
pathBorder.AddArc(r.Right - innerCurve - m_PenSizeOffset, r.Y + m_PenSizeOffset, innerCurve, innerCurve, 270, 90);
pathBorder.AddArc(r.Right - innerCurve - m_PenSizeOffset, r.Bottom - innerCurve- m_PenSizeOffset, innerCurve, innerCurve, 0, 90);
pathBorder.AddArc(r.X + m_PenSizeOffset, r.Bottom - innerCurve - m_PenSizeOffset, innerCurve, innerCurve, 90, 90);
pathBorder.CloseFigure();
}
}

baseForm class:

public class baseForm : Form
{
private Color m_InternalBorderColor = Color.FromArgb(128, 128, 128);
private Color m_BorderColor = Color.Red;
private Color m_FillColor = Color.WhiteSmoke;
private float m_PenSize = 6f;
private float m_CurveAngle = 60.0f;
internal float m_PenSizeOffset = 3f;

public baseForm() => InitializeComponent();
private void InitializeComponent() => FormBorderStyle = FormBorderStyle.None;

[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), Category("Appearance")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[DefaultValue(60.0f)]
public virtual float CurveAngle
{
get => m_CurveAngle;
set {
m_CurveAngle = Math.Max(Math.Min(value, 180), 15);
Invalidate();
}
}
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), Category("Appearance")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[DefaultValue(6.0f)]
public virtual float BorderSize
{
get => m_PenSize;
set {
m_PenSize = value;
m_PenSizeOffset = value / 2.0f;
Invalidate();
}
}

[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), Category("Appearance")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public virtual Color BorderColor
{
get => m_BorderColor;
set {
m_BorderColor = value;
Invalidate();
}
}

[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), Category("Appearance")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public virtual Color FillColor
{
get => m_FillColor;
set {
m_FillColor = value;
Invalidate();
}
}

[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), Category("Appearance")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Description("Get or Set the Color of the internal border")]
public virtual Color InternalBorderColor
{
get => m_InternalBorderColor;
set {
m_InternalBorderColor = value;
Invalidate();
}
}

[EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[DefaultValue(FormBorderStyle.None)]
public new FormBorderStyle FormBorderStyle
{
get => base.FormBorderStyle;
set => base.FormBorderStyle = FormBorderStyle.None;
}
}

How to draw a rounded rectangle using HTML Canvas?

The HTML5 canvas doesn't provide a method to draw a rectangle with rounded corners.

How about using the lineTo() and arc() methods?

You can also use the quadraticCurveTo() method instead of the arc() method.

How to draw a rounded rectangle in c#

    public static GraphicsPath RoundedRect(Rectangle bounds, int radius)
{
int diameter = radius * 2;
Size size = new Size(diameter, diameter);
Rectangle arc = new Rectangle(bounds.Location, size);
GraphicsPath path = new GraphicsPath();

if (radius == 0)
{
path.AddRectangle(bounds);
return path;
}

// top left arc
path.AddArc(arc, 180, 90);

// top right arc
arc.X = bounds.Right - diameter;
path.AddArc(arc, 270, 90);

// bottom right arc
arc.Y = bounds.Bottom - diameter;
path.AddArc(arc, 0, 90);

// bottom left arc
arc.X = bounds.Left;
path.AddArc(arc, 90, 90);

path.CloseFigure();
return path;
}

And you can make two extension methods for the Graphics type so you can use them as the usual Draw... and Fill... shape-drawing methods.

    public static void DrawRoundedRectangle(this Graphics graphics, Pen pen, Rectangle bounds, int cornerRadius)
{
if (graphics == null)
throw new ArgumentNullException("graphics");
if (pen == null)
throw new ArgumentNullException("pen");

using (GraphicsPath path = RoundedRect(bounds, cornerRadius))
{
graphics.DrawPath(pen, path);
}
}

public static void FillRoundedRectangle(this Graphics graphics, Brush brush, Rectangle bounds, int cornerRadius)
{
if (graphics == null)
throw new ArgumentNullException("graphics");
if (brush == null)
throw new ArgumentNullException("brush");

using (GraphicsPath path = RoundedRect(bounds, cornerRadius))
{
graphics.FillPath(brush, path);
}
}

Update 2020:

Recently I made my drawing libraries publicly available (NuGet). Feel free to explore the GraphicsExtensions class for more overloads (custom corner radius for each corners), and for other goodies.

How to Draw a Rounded Rectangle with WinForms (.NET)?

The graphics class in C# does not have a built-in method to draw rounded rectangles, however there are several ways that you can accomplish this affect. The links in the answer by Jay Riggs offer good suggestions on where to start, additionally I would suggest that you check out this article:

C# - Creating Rounded Rectangles Using A Graphics Path

So first, we create a GraphicsPath,
and then we call StartFigure so that
we can start adding edges to the path.
The rest of this code is for the top
left corner and the top line of the
rounded rectangle. If we are supposed
to make this corner rounded, we add an
arc - otherwise...

How to draw rounded rectangle with variable width border inside of specific bounds

Alright guys, I figured it out! Just need to shrink the bounds to take into account the width of the pen. I kind of knew this was the answer I was just wondering if there was a way to draw a line on the inside of a path. This works good though.

private void DrawRoundedRectangle(Graphics gfx, Rectangle Bounds, int CornerRadius, Pen DrawPen, Color FillColor)
{
int strokeOffset = Convert.ToInt32(Math.Ceiling(DrawPen.Width));
Bounds = Rectangle.Inflate(Bounds, -strokeOffset, -strokeOffset);

DrawPen.EndCap = DrawPen.StartCap = LineCap.Round;

GraphicsPath gfxPath = new GraphicsPath();
gfxPath.AddArc(Bounds.X, Bounds.Y, CornerRadius, CornerRadius, 180, 90);
gfxPath.AddArc(Bounds.X + Bounds.Width - CornerRadius, Bounds.Y, CornerRadius, CornerRadius, 270, 90);
gfxPath.AddArc(Bounds.X + Bounds.Width - CornerRadius, Bounds.Y + Bounds.Height - CornerRadius, CornerRadius, CornerRadius, 0, 90);
gfxPath.AddArc(Bounds.X, Bounds.Y + Bounds.Height - CornerRadius, CornerRadius, CornerRadius, 90, 90);
gfxPath.CloseAllFigures();

gfx.FillPath(new SolidBrush(FillColor), gfxPath);
gfx.DrawPath(DrawPen, gfxPath);
}

Qt drawing a filled rounded rectangle with border

You can create a QPainterPath, add the rounded rect to it, and then fill and stroke it:

QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
QPainterPath path;
path.addRoundedRect(QRectF(10, 10, 100, 50), 10, 10);
QPen pen(Qt::black, 10);
p.setPen(pen);
p.fillPath(path, Qt::red);
p.drawPath(path);

Note that even with antialiasing, 1 px border will probably never really look good, especially on a low DPI desktop monitor, on a high DPI mobile device it will be almost invisible.

Sample Image

If you create the rectangle as QRectF(9.5, 9.5, 100, 50) it will look better with 1 px antialiased border, because it will "snap" on the right pixel:

Sample Image

C# Form with custom border and rounded edges

The Region propery simply cuts off the corners. To have a true rounded corner you will have to draw the rounded rectangles.

Drawing rounded rectangles

It might be easier to draw an image of the shape you want and put that on the transparent form. Easier to draw but cannot be resized.



Related Topics



Leave a reply



Submit