言語フィルタ:
概要
ボタンを独自の形状で描画する方法を紹介します。
ボタンを独自の形状で描画すると次のようになります。
対象コントロール
- System.Windows.Forms.Button
解説
「コントロールの詳細を描画する」で紹介している方法でボタンを好きな形状で描画することが出来ます。しかし、角を丸くしようとした場合に角の隅の部分を透明に描画することが出来ません。
OnPaint メソッドで基本クラスの OnPaint メソッドを呼び出している場合は、基本クラスによってボタンが描画されてしまうため、それが見えてしまいます。基本クラスの OnPaint メソッドを呼ばないようにすると、今度は透明に描画した部分が黒く塗りつぶされてしまいます。これはボタンの背景に何も描画されていないためです。つまり背景を描画出来れば、ボタンを好きな形状で描画出来るようになります。
ボタンは ControlStyles.Opaque スタイルが適用されているため、背景は描画されません。ControlStyles.Opaque スタイルを未適用状態にするには、コンストラクタで SetStyle メソッドを使用して ControlStyles.Opaque スタイルを False に設定します。これで背景が描画されるようになり OnPaintBackground メソッドが呼び出されるようになります。
Public Sub New()
Me.SetStyle(ControlStyles.Opaque, False)
End Sub
public OwnerDrawButton() // コンストラクタ
{
this.SetStyle(ControlStyles.Opaque, false);
}
これで OnPaint メソッドで透明に描画した部分に背景が表示されるようになります。楕円形でも角丸の長方形でも、後は好きな形状でボタンを描画するだけです。
ソースコード
楕円の形状をした Button コントロールを作成するサンプルを紹介します。
ボタンの上にマウスがある時や、ボタンが押されている時にボタンの色を変化させるために、マウスの状態を示す MouseState 列挙体を追加しています。ボタンのテキストは必ずコントロールの中央に表示されるようにしてあります。
ボタンの形状の外の部分を透明に描画したいため、コンストラクタで基本クラスの BackColor プロパティに透明色を設定しています。ボタンの色を変更するには、基本クラスの BackColor プロパティを隠蔽し再定義した BackColor プロパティで設定出来るようにしています。
Imports System
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Namespace Extentions
Public Class OwnerDrawButton
Inherits System.Windows.Forms.Button
Private Enum MouseState As Integer
Leave = 0
Enter = 1
Down = 2
End Enum
Private drawMouseState As MouseState
Public Sub New()
Me.SetStyle(ControlStyles.Opaque, False)
MyBase.BackColor = Color.Transparent
End Sub
Protected Overrides Sub OnPaint(ByVal pevent As System.Windows.Forms.PaintEventArgs)
pevent.Graphics.SmoothingMode = SmoothingMode.AntiAlias
Dim rect As New Rectangle(0, 0, Me.ClientRectangle.Width - 1, Me.ClientRectangle.Height - 1)
' ボタンの形状を描画
Using sb As New SolidBrush(Me.BackColor)
pevent.Graphics.FillEllipse(sb, rect)
End Using
' マウスの状態によりボタンの前景色を変更
Select Case Me.drawMouseState
Case MouseState.Enter
Using sb As New SolidBrush(Color.FromArgb(30, 255, 255, 255))
pevent.Graphics.FillEllipse(sb, rect)
End Using
Case MouseState.Down
Using sb As New SolidBrush(Color.FromArgb(30, 0, 0, 0))
pevent.Graphics.FillEllipse(sb, rect)
End Using
End Select
' フォーカス枠を描画
If Me.Focused Then
Using p As New Pen(Color.Black)
p.DashStyle = DashStyle.Dot
Dim r As Rectangle = rect
r.Inflate(-2, -2)
pevent.Graphics.DrawEllipse(p, r)
End Using
End If
' 文字列を描画
Using sf As New StringFormat
sf.Alignment = StringAlignment.Center
sf.LineAlignment = StringAlignment.Center
Using sb As New SolidBrush(Me.ForeColor)
pevent.Graphics.DrawString(Me.Text, Me.Font, sb, Me.ClientRectangle, sf)
End Using
End Using
End Sub
Protected Overrides Sub OnEnter(ByVal e As System.EventArgs)
MyBase.OnEnter(e)
Me.Invalidate()
End Sub
Protected Overrides Sub OnLeave(ByVal e As System.EventArgs)
MyBase.OnLeave(e)
Me.Invalidate()
End Sub
Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
MyBase.OnMouseEnter(e)
Me.drawMouseState = MouseState.Enter
Me.Invalidate()
End Sub
Protected Overrides Sub OnMouseLeave(ByVal e As System.EventArgs)
MyBase.OnMouseLeave(e)
Me.drawMouseState = MouseState.Leave
Me.Invalidate()
End Sub
Protected Overrides Sub OnMouseDown(ByVal mevent As System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseDown(mevent)
Me.drawMouseState = MouseState.Down
Me.Invalidate()
End Sub
Protected Overrides Sub OnMouseUp(ByVal mevent As System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseUp(mevent)
If Me.ClientRectangle.Contains(mevent.Location) Then
Me.drawMouseState = MouseState.Enter
Else
Me.drawMouseState = MouseState.Leave
End If
Me.Invalidate()
End Sub
#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
End Class
End Namespace
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Extentions
{
class OwnerDrawButton : System.Windows.Forms.Button
{
private enum MouseState : int
{
Leave = 0,
Enter = 1,
Down = 2,
}
private MouseState drawMouseState;
public OwnerDrawButton()
{
this.SetStyle(ControlStyles.Opaque, false);
base.BackColor = Color.Transparent;
}
protected override void OnPaint(PaintEventArgs pevent)
{
pevent.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle rect = new Rectangle(0, 0, this.ClientRectangle.Width - 1, this.ClientRectangle.Height - 1);
// ボタンの形状を描画
using (SolidBrush sb = new SolidBrush(this.BackColor))
{
pevent.Graphics.FillEllipse(sb, rect);
}
// マウスの状態によりボタンの前景色を変更
switch (this.drawMouseState)
{
case MouseState.Enter:
using (SolidBrush sb = new SolidBrush(Color.FromArgb(30, 255, 255, 255)))
{
pevent.Graphics.FillEllipse(sb, rect);
}
break;
case MouseState.Down:
using (SolidBrush sb = new SolidBrush(Color.FromArgb(30, 0, 0, 0)))
{
pevent.Graphics.FillEllipse(sb, rect);
}
break;
}
// フォーカス枠を描画
if (this.Focused)
{
using (Pen p = new Pen(Color.Black))
{
p.DashStyle = DashStyle.Dot;
Rectangle r = rect;
r.Inflate(-2, -2);
pevent.Graphics.DrawEllipse(p, r);
}
}
// 文字列を描画
using (StringFormat sf = new StringFormat())
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
using (SolidBrush sb = new SolidBrush(this.ForeColor))
{
pevent.Graphics.DrawString(this.Text, this.Font, sb, this.ClientRectangle, sf);
}
}
}
protected override void OnEnter(EventArgs e)
{
base.OnEnter(e);
this.Invalidate();
}
protected override void OnLeave(EventArgs e)
{
base.OnLeave(e);
this.Invalidate();
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
this.drawMouseState = MouseState.Enter;
this.Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
this.drawMouseState = MouseState.Leave;
this.Invalidate();
}
protected override void OnMouseDown(MouseEventArgs mevent)
{
base.OnMouseDown(mevent);
this.drawMouseState = MouseState.Down;
this.Invalidate();
}
protected override void OnMouseUp(MouseEventArgs mevent)
{
base.OnMouseUp(mevent);
if (this.ClientRectangle.Contains(mevent.Location))
{
this.drawMouseState = MouseState.Enter;
}
else
{
this.drawMouseState = MouseState.Leave;
}
this.Invalidate();
}
#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
}
}