こんにちは! 業務システム開発の現場で、日々泥臭くも美しいコードを書いているチーフアーキテクトの私です。
さて、Windows Forms(Windowsフォームアプリケーション)を使っていて、こんな風に思ったことはありませんか?
「この標準の `TabControl`、なんだかWindows 95の香りがして、今の時代にはちょっと野暮ったい……!」
そうなんです。デフォルトのタブコントロールは、フラットデザインが主流の現代において、どうしても浮いてしまいがちです。かといって、サードパーティ製の高価なUIライブラリを入れるほどでもない……。
そんなあなたのために、今回はVB.NETのオーナー描画(OwnerDraw)という強力な仕組みを使って、タブコントロールをモダンに生まれ変わらせる手法を伝授します。ここをクリアすれば、Windows FormsのUIコントロールを自在に操る「ワンランク上のエンジニア」の仲間入りですよ!
—
なぜ標準の TabControl は「野暮ったい」のか?
Windows Formsの `TabControl` は、OS(Windows)の描画エンジンに依存しています。そのため、フォントを変えようにも限界があり、背景色やタブの形状をちょっとモダンにしようとしただけで、途端に壁にぶつかります。
そこで登場するのが、`DrawMode` プロパティです。
これを通常の `Normal` から `OwnerDrawFixed`(または `OwnerDraw`)に変更すると、「Windowsさん、描画は私(プログラマ)が自分でやります!」という宣言になります。キャンバスを完全に自分色に染め上げることができるようになるわけですね。
—
今回実装するモダンタブの仕様
今回は、以下の要件を満たすカスタムタブをVB.NETで実装します。
1. フラットデザイン: 余計な立体感を排除し、すっきりとしたモダンな配色にする。
2. アクティブタブの強調: 選択されているタブは背景色を変え、視認性を高める。
3. アイコン表示: タブの文字の横に小さなアイコン(絵文字や画像)を配置して視覚的な分かりやすさを向上させる。
—
実装ステップ:コードの全貌
それでは、Visual Studioを開いて、実際のコードを見ていきましょう。
今回は、フォームに配置した `TabControl1` に対して、コードビハインド(Formクラス)で描画処理を乗っ取ります。
以下のコードを、対象のフォーム(例: `Form1.vb`)にそのまま貼り付けてみてください。
Public Class Form1
‘ フォームがロードされたときの初期設定
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
‘ 1. タブの描画モードを「オーナー描画(固定サイズ)」に変更する
TabControl1.DrawMode = TabControlDrawMode.OwnerDrawFixed
‘ 2. タブのサイズを少し大きくして、現代的な余白を持たせる
TabControl1.ItemSize = New Size(120, 35)
End Sub
‘ 3. 各タブを描画するタイミングで発生するイベント
Private Sub TabControl1_DrawItem(sender As Object, e As DrawItemEventArgs) Handles TabControl1.DrawItem
‘ グラフィックオブジェクト(描画ペンやブラシの持ち主)を取得
Dim g As Graphics = e.Graphics
‘ 対象となるタブの矩形(位置とサイズ)を取得
Dim tabRect As Rectangle = TabControl1.GetTabRect(e.Index)
‘ タブが現在選択されているかどうかを判定
Dim isSelected As Boolean = (e.Index = TabControl1.SelectedIndex)
‘ — 背景色の決定と塗りつぶし —
Dim backColor As Color
Dim foreColor As Color
If isSelected Then
‘ 選択中のタブ:明るいブルー系で目立たせる
backColor = Color.FromArgb(0, 122, 204) ‘ モダンなブルー
foreColor = Color.White ‘ 文字色は白
Else
‘ 非選択のタブ:落ち着いたライトグレー
backColor = Color.FromArgb(240, 240, 240)
foreColor = Color.FromArgb(60, 60, 60) ‘ 文字色はダークグレー
End If
‘ 背景をブラシで塗りつぶす
Using brush As New SolidBrush(backColor)
g.FillRectangle(brush, tabRect)
End Using
‘ — テキスト(およびアイコン)の描画 —
‘ タブのテキストを取得
Dim tabText As String = TabControl1.TabPages(e.Index).Text
‘ アイコンっぽい絵文字をタブ名に付与してみる(例としてインデックス毎に分岐)
Dim iconText As String = “”
Select Case e.Index
Case 0 : iconText = “🏠 ” ‘ ホーム
Case 1 : iconText = “⚙️ ” ‘ 設定
Case Else : iconText = “📁 ” ‘ その他
End Select
Dim displayText As String = iconText & tabText
‘ フォントの設定
Using font As New Font(“Meiryo UI”, 9, FontStyle.Regular)
Using textBrush As New SolidBrush(foreColor)
‘ 文字を描画するための位置を計算(中央寄せっぽく調整)
Dim sf As New StringFormat()
sf.Alignment = StringAlignment.Center
sf.LineAlignment = StringAlignment.Center
‘ 描画実行
g.DrawString(displayText, font, textBrush, CType(tabRect, RectangleF), sf)
End Using
End Using
‘ 選択されているタブには、上部にアクセントラインを描画する(さらに今風に!)
If isSelected Then
Using accentBrush As New SolidBrush(Color.FromArgb(0, 200, 255))
g.FillRectangle(accentBrush, tabRect.X, tabRect.Y, tabRect.Width, 3)
End Using
End If
End Sub
End Class
—
コードの重要ポイント解説
初心者の方やマクロからステップアップした方に向けて、このコードのキモとなる部分を噛み砕いて解説します。
1. `TabControl1.DrawMode = TabControlDrawMode.OwnerDrawFixed`
これがオーナー描画のスイッチです。これを行わないと、後述の `DrawItem` イベントが発火しません。`Fixed` は「すべてのタブが同じサイズ」であることを意味します。
2. `DrawItemEventArgs` がすべてを握っている
`TabControl1_DrawItem` の中で受け取る `e`(DrawItemEventArgs)には、「今から何番目のタブを、どこに描こうとしているか」という情報がすべて詰まっています。
- `e.Index`: 何番目のタブか
- `e.Graphics`: お絵描きをするためのキャンバス(筆)
このキャンバスに対して、「ここに四角形を塗れ」「ここに文字を書け」と命令していくのがオーナー描画の正体です。
3. `Using` ステートメントの重要性
グラフィックを扱う際、`SolidBrush` や `Font` などのオブジェクトは、メモリを大量に消費します。使い終わったら即座にメモリから解放(Dispose)しないと、メモリリーク(動作が重くなる原因)を引き起こします。
VB.NETの `Using … End Using` ブロックを使うことで、ブロックを抜けた瞬間に自動的にきれいに片付けてくれます。これはプロのエンジニアの必須テクニックです。
—
陥りやすい罠とエラー回避の知見
実際にこのコードを組み込む際、初心者がハマりがちなポイントを先回りして解説しておきます。
- タブの文字が消えてしまった!?
- 原因: `DrawMode` を `OwnerDrawFixed` にした瞬間、VB.NETの標準機能による文字描画がすべて無効化されます。そのため、自分で `g.DrawString` を呼ばないと、文字が一切表示されない真っ白なタブになってしまいます。「文字が出ない!」と思ったら、描画処理を書き忘れていないか確認してください。
- 画面サイズを変えるとチラつく(Flicker)
- 対策: ウィンドウのサイズ変更時などに画面がチラつく場合は、フォームのコンストラクタ(または `Form_Load`)で、以下のコードを仕込んでダブルバッファリングを有効にしてください。
‘ チラつき防止(リフレクションを使用)
Me.GetType().GetProperty(“DoubleBuffered”, System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance).SetValue(Me, True, Nothing)
—
おわりに
いかがでしたでしょうか?
「オーナー描画」と聞くと何やら難しそうな魔法のように感じますが、やっていることは「キャンバスに自分で色を塗り、文字を配置しているだけ」です。
この手法をマスターすれば、TabControlだけでなく、ListBoxやComboBox、さらにはButtonに至るまで、あなたのアプリケーションのUIを完全にコントロールできるようになります。「古いWindows Formsだからダサい」なんて言わせない、洗練されたモダンアプリケーションをぜひ自分の手で作り上げてください。
ここをクリアしたあなたなら、VB.NETのUI開発はもう怖くありません。
明日からの開発ライフを、さらに楽しくしていきましょう! チーフアーキテクトの私でした。
