ようこそ、クリエイティブなエンジニアリングの世界へ。
標準のWindows Formsボタンを配置して、「なんだか古臭いデザインだな……」と溜息をついたことはありませんか? 業務システムだから見た目は二の次――そんな時代はもう終わりました。
私はこれまで、数多くのミッションクリティカルなシステムを構築してきましたが、優れたUI(ユーザーインターフェース)は、ユーザーのミスを減らし、システムの価値を直感的に伝える「最高の機能」であると断言できます。
今日は、Visual Basic (VB.NET) の真髄である「OnPaint」を使いこなし、標準コントロールの枠を超えた「モダンな角丸グラデーションボタン」をゼロから自作する方法を伝授しましょう。ここをマスターすれば、あなたのVB.NETスキルは「マクロの延長」から「プロフェッショナルなアプリケーション開発」へと一気に昇華します。
それでは、至高のボタン作りを始めましょう。
—
1. 「描画」を制する者はUIを制する
Windows Formsのコントロールは、実はすべて「GDI+」というグラフィックスライブラリを使って画面に描かれています。標準のボタンも、内部では四角形を描き、色を塗り、文字を載せているに過ぎません。
私たちがやるべきことは、ボタンの継承(Inheritance)を行い、システムが用意した描画処理を「ちょっと待った、私が描くよ」と書き換える(オーバーライドする)ことです。
核心となる3つの概念
1. OnPaint イベント: 画面が書き換わるたびに呼ばれる「キャンバス」です。
2. GraphicsPath: 角丸などの「複雑な図形の設計図」です。
3. LinearGradientBrush: 質感を生む「グラデーションの筆」です。
—
2. 実践:モダンカスタムボタンのコード
まずは、新しいクラスファイルをプロジェクトに追加し、以下のコードを貼り付けてみてください。このコードには、メモリ管理の鉄則である「リソースの解放」や、プロの描画テクニックが凝縮されています。
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Imports System.ComponentModel
”’
”’
Public Class ModernButton
Inherits Button
‘ — プロパティ:デザイナーから変更可能にする —
Public Property StartColor As Color = Color.FromArgb(52, 152, 219) ‘ 美しい青
Public Property EndColor As Color = Color.FromArgb(41, 128, 185)
Public Property CornerRadius As Integer = 15
Public Property HoverColor As Color = Color.FromArgb(46, 204, 113) ‘ マウスホバー時は緑に
‘ 現在のボタンの状態を管理
Private Enum ControlState
Normal
Hover
Pressed
End Enum
Private CurrentState As ControlState = ControlState.Normal
Public Sub New()
‘ 描画のチラつきを抑えるための魔法の1行(ダブルバッファリング)
Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or
ControlStyles.UserPaint Or
ControlStyles.DoubleBuffer Or
ControlStyles.ResizeRedraw Or
ControlStyles.SupportsTransparentBackColor, True)
Me.BackColor = Color.Transparent
Me.FlatStyle = FlatStyle.Flat
Me.FlatAppearance.BorderSize = 0
End Sub
‘ — マウスイベントで状態を更新 —
Protected Overrides Sub OnMouseEnter(e As EventArgs)
MyBase.OnMouseEnter(e)
CurrentState = ControlState.Hover
Me.Invalidate() ‘ 再描画を依頼
End Sub
Protected Overrides Sub OnMouseLeave(e As EventArgs)
MyBase.OnMouseLeave(e)
CurrentState = ControlState.Normal
Me.Invalidate()
End Sub
Protected Overrides Sub OnMouseDown(mevent As MouseEventArgs)
MyBase.OnMouseDown(mevent)
CurrentState = ControlState.Pressed
Me.Invalidate()
End Sub
Protected Overrides Sub OnMouseUp(mevent As MouseEventArgs)
MyBase.OnMouseUp(mevent)
CurrentState = ControlState.Hover
Me.Invalidate()
End Sub
‘ — 描画の核心部 —
Protected Overrides Sub OnPaint(e As PaintEventArgs)
‘ 不要な基本クラスの描画を呼ばず、完全に上書きする
Dim g = e.Graphics
g.SmoothingMode = SmoothingMode.AntiAlias ‘ これが重要!境界線を滑らかにする
‘ 描画領域の計算(ペン先の太さ分、わずかに内側を計算)
Dim rect As New Rectangle(0, 0, Me.Width – 1, Me.Height – 1)
‘ 1. 角丸のパスを作成
Using path As GraphicsPath = GetRoundedPath(rect, CornerRadius)
‘ 2. 状態に応じた色を決定
Dim color1 = StartColor
Dim color2 = EndColor
If CurrentState = ControlState.Hover Then
color1 = HoverColor
color2 = HoverColor
ElseIf CurrentState = ControlState.Pressed Then
color1 = EndColor ‘ 色を反転させて押し込み感を演出
color2 = StartColor
End If
‘ 3. グラデーションで塗りつぶし
Using brush As New LinearGradientBrush(rect, color1, color2, LinearGradientMode.Vertical)
g.FillPath(brush, path)
End Using
‘ 4. テキストの描画
Dim textAttr = TextFormatFlags.HorizontalCenter Or TextFormatFlags.VerticalCenter
TextRenderer.DrawText(g, Me.Text, Me.Font, rect, Me.ForeColor, textAttr)
End Using
End Sub
‘ 角丸パスを生成するヘルパーメソッド
Private Function GetRoundedPath(rect As Rectangle, radius As Integer) As GraphicsPath
Dim path As New GraphicsPath()
Dim d = radius 2
‘ 左上、右上、右下、左下の順に弧を描く
path.AddArc(rect.X, rect.Y, d, d, 180, 90)
path.AddArc(rect.Right – d, rect.Y, d, d, 270, 90)
path.AddArc(rect.Right – d, rect.Bottom – d, d, d, 0, 90)
path.AddArc(rect.X, rect.Bottom – d, d, d, 90, 90)
path.CloseFigure()
Return path
End Function
End Class
—
3. このコードに込められた「プロの知恵」
ただ動くだくだけのコードなら、リファレンスを見れば誰でも書けます。しかし、上記のコードには「実戦で勝つための工夫」が3つ組み込まれています。
① SmoothingMode.AntiAlias(アンチエイリアス)
これがないと、角丸の境界線がジャギー(ギザギザ)になってしまいます。「なんか素人っぽいな」と感じる原因の多くは、この1行が抜けていることです。
② Usingブロックの徹底
`GraphicsPath` や `LinearGradientBrush` は、Windowsの貴重なリソース(GDIオブジェクト)を消費します。これらを使い終わった後に放置すると、アプリが長時間起動した際に動作が不安定になる「リソースリーク」を引き起こします。`Using` を使うことで、使い終わったら即座に破棄する――これがエンジニアの作法です。
③ Invalidate() による状態変化
マウスが乗った瞬間に `Me.Invalidate()` を呼んでいます。これは「このコントロールは汚れたから、次のタイミングで描き直してね」とWindowsに通知する命令です。これによって、ボタンが生きているかのように色が変わるレスポンスが生まれます。
—
4. 陥りやすいエラーと回避策
実装中に「あれ?」と思ったら、ここを確認してください。
- 角が欠ける・描画がズレる:
`Rectangle` のサイズを `Me.Width, Me.Height` にすると、右端と下端の線が1ピクセルはみ出して消えてしまいます。コード内で `Me.Width – 1` としているのは、その「1ピクセルの余裕」を作るためです。
- ボタンがチカチカする(フリッカー):
コントロールを描画する際、背景を消してから前面を描くというステップを踏むと、一瞬白く光って見えます。コンストラクタで `DoubleBuffer` を有効にしているのは、裏側で描画を完成させてから一気に画面に転送するためです。
—
5. 最後に:ここからがスタートです
いかがでしたか?
「難しそう」と思っていた独自コントロールの世界も、一歩踏み込んでみれば 「パスを描いて、筆で塗る」 という非常にシンプルな理屈で動いていることが分かったはずです。
この `OnPaint` をマスターすれば、円形のボタン、ネオンのように光るインジケーター、あるいはアニメーションするグラフまで、あなたの想像力次第でどんなUIも生み出すことができます。
Visual Basicは、開発者の意図を素直に形にしてくれる素晴らしい言語です。このカスタムボタンを土台にして、ぜひあなただけの「究極のツール」を作り上げてください。
「ここをクリアすれば、Visual Basicの基本はバッチリですよ。応援しています!」
