言語フィルタ:
概要
コントロールの境界線の角を丸く描画をする方法を紹介します。
境界線の角を丸く描画すると次のようになります。
| 45 |
90 |
 |
 |
対象コントロール
- System.Windows.Forms.Control から派生しているクラス
解説
コントロールの境界線を描画する方法がわからない方は、まず「コントロールの境界線を描画する」を参照してください。
コントロールの境界線の角を丸くするためには GraphicsPath クラスを使用します。GraphicsPath クラスの AddArc メソッドを使用して四隅を描画することで、角が丸い図形を作成することが出来ます。それを Graphics.DrawPath メソッドで描画すれば、境界線の角を丸くすることが出来ます。
' 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()
// 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 プロパティを追加しています。
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
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();
}
}
}
}