Skip Navigation Linksホーム > ライブラリ > コントロール > コントロールの境界線の角を丸く描画をする

コントロールの境界線の角を丸く描画をする

言語フィルタ:

概要

コントロールの境界線の角を丸く描画をする方法を紹介します。

境界線の角を丸く描画すると次のようになります。

45 90
sample1 sample2

対象コントロール

  • System.Windows.Forms.Control から派生しているクラス

解説

コントロールの境界線を描画する方法がわからない方は、まず「コントロールの境界線を描画する」を参照してください。

コントロールの境界線の角を丸くするためには GraphicsPath クラスを使用します。GraphicsPath クラスの AddArc メソッドを使用して四隅を描画することで、角が丸い図形を作成することが出来ます。それを Graphics.DrawPath メソッドで描画すれば、境界線の角を丸くすることが出来ます。

展開されたイメージ 角が丸い図形の作成 - Visual Basic
コピーイメージ コードのコピー
' r は境界線の領域(Rectangle 型)
' w は角の円弧の描画元となる楕円の幅(Integer 型)
' h は角の円弧の描画元となる楕円の高さ(Integer 型)

Dim gp As New GraphicsPath
gp.StartFigure()
gp.AddArc(r.Right - w, r.Top, w, h, 270, 90) ' 右上隅
gp.AddArc(r.Right - w, r.Bottom - h, w, h, 0, 90) ' 右下隅
gp.AddArc(r.Left, r.Bottom - h, w, h, 90, 90) ' 左下隅
gp.AddArc(r.Left, r.Top, w, h, 180, 90) ' 左上隅
gp.CloseFigure()
展開されたイメージ 角が丸い図形の作成 - C#
コピーイメージ コードのコピー
// r は境界線の領域(Rectangle 型)
// w は角の円弧の描画元となる楕円の幅(Int 型)
// h は角の円弧の描画元となる楕円の高さ(Int 型)

GraphicsPath gp = new GraphicsPath();
gp.StartFigure();
gp.AddArc(r.Right - w, r.Top, w, h, 270, 90); // 右上隅
gp.AddArc(r.Right - w, r.Bottom - h, w, h, 0, 90); // 右上隅
gp.AddArc(r.Left, r.Bottom - h, w, h, 90, 90); // 右上隅
gp.AddArc(r.Left, r.Top, w, h, 180, 90); // 右上隅
gp.CloseFigure();

描画する前に Graphics.SmoothingMode プロパティに AntiAlias などを指定することで、角がより滑らかになります。

境界線の内側だけを塗りつぶしたい場合は、Graphics.FillPath メソッドで、作成した GraphicsPath クラスを描画します。

ソースコード

Panel コントロールに境界線の角を丸く描画するサンプルを紹介します。

Panel コントロールは既に境界線を表示できるため BorderStyle プロパティを隠蔽し、独自の境界線スタイルとして使用しています。境界線のスタイルとして Pen クラスの DashStyle プロパティで描画できる破線を、全て描画できるようにしています。

境界線の角の円弧の半径を示す Curvature プロパティを追加しています。Curvature プロパティの値を大きくすることで、角の丸みが大きくなっていきます。値が 0 の時は角が直角の境界線を描画するようにしています。背景色は境界線の内側のみを描画するようにしています。

境界線の色を示す BorderColor プロパティと境界線の幅を示す BorderWidth プロパティを追加しています。

展開されたイメージ Visual Basic
コピーイメージ コードのコピー
Imports System
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms

Namespace Extentions

    Public Enum BorderStyle As Integer
        None = 0
        Dash = 2
        DashDot = 4
        DashDotDot = 5
        Dot = 3
        Solid = 1
    End Enum

    Public Class CurveBorderDraw
        Inherits System.Windows.Forms.Panel

        Public Sub New()
            MyBase.BackColor = Color.Transparent
            MyBase.BorderStyle = System.Windows.Forms.BorderStyle.None
            Me._BorderColor = Color.Black
            Me._BorderStyle = Extentions.BorderStyle.None
            Me._BorderWidth = 1
            Me._Curvature = 0
        End Sub

        Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs)
            If Me.BorderStyle <> Extentions.BorderStyle.None AndAlso Me.Curvature > 0 Then
                MyBase.OnPaintBackground(e)
            End If
        End Sub

        Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
            If Me.BorderStyle = Extentions.BorderStyle.None Then
                ' 背景のみ描画
                Using sb As New SolidBrush(Me.BackColor)
                    e.Graphics.FillRectangle(sb, Me.ClientRectangle)
                End Using
            Else
                Using p As New Pen(Me.BorderColor, Me.BorderWidth)
                    p.DashStyle = Me.ConvertToDashStyle(Me.BorderStyle)
                    Dim r As Rectangle = Me.ClientRectangle
                    r.X += r.X + Convert.ToInt32(Decimal.Floor(Convert.ToDecimal(Me.BorderWidth / 2)))
                    r.Y += r.Y + Convert.ToInt32(Decimal.Floor(Convert.ToDecimal(Me.BorderWidth / 2)))
                    r.Width -= Me.BorderWidth
                    r.Height -= Me.BorderWidth

                    If Me.Curvature = 0 Then
                        ' 通常の境界線を描画
                        Using sb As New SolidBrush(Me.BackColor)
                            e.Graphics.FillRectangle(sb, Me.ClientRectangle)
                        End Using
                        e.Graphics.DrawRectangle(p, r)
                    Else
                        ' 角が丸い境界線を描画
                        Dim w As Integer = Me.Curvature
                        If Me.Curvature > r.Width Then
                            w = r.Width
                        End If
                        Dim h As Integer = Me.Curvature
                        If Me.Curvature > r.Height Then
                            h = r.Height
                        End If

                        Dim gp As New GraphicsPath
                        gp.StartFigure()
                        gp.AddArc(r.Right - w, r.Top, w, h, 270, 90)
                        gp.AddArc(r.Right - w, r.Bottom - h, w, h, 0, 90)
                        gp.AddArc(r.Left, r.Bottom - h, w, h, 90, 90)
                        gp.AddArc(r.Left, r.Top, w, h, 180, 90)
                        gp.CloseFigure()

                        Using sb As New SolidBrush(Me.BackColor)
                            e.Graphics.FillPath(sb, gp)
                        End Using

                        Dim sm As SmoothingMode = e.Graphics.SmoothingMode
                        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
                        e.Graphics.DrawPath(p, gp)
                        e.Graphics.SmoothingMode = sm
                    End If
                End Using
            End If
        End Sub

        Private Function ConvertToDashStyle(ByVal style As Extentions.BorderStyle) As DashStyle
            Return DirectCast(style - 1, DashStyle)
        End Function

#Region " BackColor "

        Private _BackColor As Color
        Public Shadows Property BackColor() As Color
            Get
                If Me._BackColor <> Color.Empty Then
                    Return Me._BackColor
                End If
                If Me.Parent IsNot Nothing Then
                    Return Me.Parent.BackColor
                End If

                Return Control.DefaultBackColor
            End Get
            Set(ByVal value As Color)
                Me._BackColor = value
                Me.Invalidate()
            End Set
        End Property

        Public Overrides Sub ResetBackColor()
            Me.BackColor = Color.Empty
        End Sub

        Private Function ShouldSerializeBackColor() As Boolean
            Return Me._BackColor <> Color.Empty
        End Function

#End Region

        Private _BorderColor As Color
        <Category("表示")> _
        <DefaultValue(GetType(Color), "Black")> _
        <Description("コントロールの境界線色を取得または設定します。")> _
        Public Property BorderColor() As Color
            Get
                Return Me._BorderColor
            End Get
            Set(ByVal value As Color)
                Me._BorderColor = value
                Me.Invalidate()
            End Set
        End Property

        Private _BorderStyle As BorderStyle
        <Category("表示")> _
        <DefaultValue(GetType(BorderStyle), "None")> _
        <Description("コントロールの境界線スタイルを取得または設定します。")> _
        Public Shadows Property BorderStyle() As BorderStyle
            Get
                Return Me._BorderStyle
            End Get
            Set(ByVal value As BorderStyle)
                Me._BorderStyle = value
                Me.Invalidate()
            End Set
        End Property

        Private _BorderWidth As Integer
        <Category("表示")> _
        <DefaultValue(1)> _
        <Description("コントロールの境界線の幅を取得または設定します。")> _
        Public Property BorderWidth() As Integer
            Get
                Return Me._BorderWidth
            End Get
            Set(ByVal value As Integer)
                Me._BorderWidth = value
                Me.Invalidate()
            End Set
        End Property

        Private _Curvature As Integer
        <Category("表示")> _
        <DefaultValue(0)> _
        <Description("コントロールの境界線の角の半径を取得または設定します。")> _
        Public Property Curvature() As Integer
            Get
                Return Me._Curvature
            End Get
            Set(ByVal value As Integer)
                Me._Curvature = value
                Me.Invalidate()
            End Set
        End Property

    End Class

End Namespace
展開されたイメージ C#
コピーイメージ コードのコピー
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace Extentions
{
    public enum BorderStyle : int
    {
        None = 0,
        Dash = 2,
        DashDot = 4,
        DashDotDot = 5,
        Dot = 3,
        Solid = 1,
    }

    class CurveBorderDraw : System.Windows.Forms.Panel
    {
        public CurveBorderDraw()
        {
            base.BackColor = Color.Transparent;
            base.BorderStyle = System.Windows.Forms.BorderStyle.None;
            this._BorderColor = Color.Black;
            this._BorderStyle = Extentions.BorderStyle.None;
            this._BorderWidth = 1;
            this._Curvature = 0;
        }

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            if ((this.BorderStyle != BorderStyle.None) && (this.Curvature > 0))
            {
                base.OnPaintBackground(pevent);
            }
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            if (this.BorderStyle == BorderStyle.None)
            {
                // 背景のみ描画
                using (SolidBrush sb = new SolidBrush(this.BackColor))
                {
                    pe.Graphics.FillRectangle(sb, this.ClientRectangle);
                }
            }
            else
            {
                using (Pen p = new Pen(this.BorderColor, this.BorderWidth))
                {
                    p.DashStyle = this.ConvertToDashStyle(this.BorderStyle);
                    Rectangle r = this.ClientRectangle;
                    r.X += r.X + Convert.ToInt32(decimal.Floor(Convert.ToDecimal(this.BorderWidth / 2)));
                    r.Y += r.Y + Convert.ToInt32(decimal.Floor(Convert.ToDecimal(this.BorderWidth / 2)));
                    r.Width -= this.BorderWidth;
                    r.Height -= this.BorderWidth;

                    if (this.Curvature == 0)
                    {
                        // 通常の境界線を描画
                        using (SolidBrush sb = new SolidBrush(this.BackColor))
                        {
                            pe.Graphics.FillRectangle(sb, this.ClientRectangle);
                        }
                        pe.Graphics.DrawRectangle(p, r);
                    }
                    else
                    {
                        // 角が丸い境界線を描画
                        int w = this.Curvature;
                        if (this.Curvature > r.Width)
                        {
                            w = r.Width;
                        }
                        int h = this.Curvature;
                        if (this.Curvature > r.Height)
                        {
                            h = r.Height;
                        }

                        GraphicsPath gp = new GraphicsPath();
                        gp.StartFigure();
                        gp.AddArc(r.Right - w, r.Top, w, h, 270, 90);
                        gp.AddArc(r.Right - w, r.Bottom - h, w, h, 0, 90);
                        gp.AddArc(r.Left, r.Bottom - h, w, h, 90, 90);
                        gp.AddArc(r.Left, r.Top, w, h, 180, 90);
                        gp.CloseFigure();

                        using (SolidBrush sb = new SolidBrush(this.BackColor))
                        {
                            pe.Graphics.FillPath(sb, gp);
                        }

                        SmoothingMode sm = pe.Graphics.SmoothingMode;
                        pe.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
                        pe.Graphics.DrawPath(p, gp);
                        pe.Graphics.SmoothingMode = sm;
                    }
                }
            }
        }

        private DashStyle ConvertToDashStyle(Extentions.BorderStyle style)
        {
            return (DashStyle)style - 1;
        }

        #region BackColor

        private Color _BackColor;
        public new Color BackColor
        {
            get
            {
                if (this._BackColor != Color.Empty)
                {
                    return this._BackColor;
                }

                if (this.Parent != null)
                {
                    return this.Parent.BackColor;
                }

                return Control.DefaultBackColor;
            }
            set
            {
                this._BackColor = value;
                this.Invalidate();
            }
        }

        public override void ResetBackColor()
        {
            this.BackColor = Color.Empty;
        }

        private Boolean ShouldSerializeBackColor()
        {
            return this._BackColor != Color.Empty;
        }

        #endregion

        private Color _BorderColor;
        [Category("表示")]
        [DefaultValue(typeof(Color), "Black")]
        [Description("コントロールの境界線色を取得または設定します。")]
        public Color BorderColor
        {
            get { return this._BorderColor; }
            set
            {
                this._BorderColor = value;
                this.Invalidate();
            }
        }

        private BorderStyle _BorderStyle;
        [Category("表示")]
        [DefaultValue(typeof(BorderStyle), "None")]
        [Description("コントロールの境界線スタイルを取得または設定します。")]
        public new BorderStyle BorderStyle
        {
            get { return this._BorderStyle; }
            set
            {
                this._BorderStyle = value;
                this.Invalidate();
            }
        }

        private int _BorderWidth;
        [Category("表示")]
        [DefaultValue(1)]
        [Description("コントロールの境界線の幅を取得または設定します。")]
        public int BorderWidth
        {
            get { return this._BorderWidth; }
            set
            {
                this._BorderWidth = value;
                this.Invalidate();
            }
        }

        private int _Curvature;
        [Category("表示")]
        [DefaultValue(0)]
        [Description("コントロールの境界線の角の半径を取得または設定します。")]
        public int Curvature
        {
            get { return this._Curvature; }
            set
            {
                this._Curvature = value;
                this.Invalidate();
            }
        }
    }
}