DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

TabControlのタブを自分で描画する

タブコントロールのタブをオーナードローする(自分で描画する)方法を紹介します。

DrawItemイベントによる方法

タブコントロールのDrawModeプロパティをTabDrawMode.OwnerDrawFixedとすると、DrawItemイベントハンドラでタブを描画できるようになります。

次の例では、フォームにタブコントロールTabControl1があり、そのTabControl1をオーナードローすることにより、テキストを中央表示し、さらに、選択されているタブのテキストが赤、背景が青、選択されていないタブのテキストが灰色、背景が白となるようにしています。

また、この例ではSizeModeプロパティをTabSizeMode.Fixedにすることで、タブのサイズを固定しています。このようにしなくても大丈夫ですが、タブの大きさが勝手に調整されてしまうと、文字列が思ったように表示できない場合があります。

オーナードローしたタブコントロール

VB.NET
コードを隠すコードを選択
'フォームのLoadイベントハンドラ
Private Sub Form1_Load(ByVal sender As Object, _
                       ByVal e As EventArgs) _
                       Handles MyBase.Load
    'タブのサイズを固定する
    TabControl1.SizeMode = TabSizeMode.Fixed
    TabControl1.ItemSize = New Size(60, 18)

    'TabControlをオーナードローする
    TabControl1.DrawMode = TabDrawMode.OwnerDrawFixed
End Sub

'TabControl1のDrawItemイベントハンドラ
Private Sub TabControl1_DrawItem(ByVal sender As Object, _
                                 ByVal e As DrawItemEventArgs) _
                                 Handles TabControl1.DrawItem
    '対象のTabControlを取得
    Dim tab As TabControl = CType(sender, TabControl)
    'タブページのテキストを取得
    Dim txt As String = tab.TabPages(e.Index).Text

    'タブのテキストと背景を描画するためのブラシを決定する
    Dim foreBrush, backBrush As Brush
    If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
        '選択されているタブのテキストを赤、背景を青とする
        foreBrush = Brushes.Red
        backBrush = Brushes.Blue
    Else
        '選択されていないタブのテキストは灰色、背景を白とする
        foreBrush = Brushes.Gray
        backBrush = Brushes.White
    End If

    'StringFormatを作成
    Dim sf As New StringFormat
    '中央に表示する
    sf.Alignment = StringAlignment.Center
    sf.LineAlignment = StringAlignment.Center

    '背景の描画
    e.Graphics.FillRectangle(backBrush, e.Bounds)
    'Textの描画
    e.Graphics.DrawString(txt, e.Font, foreBrush, RectangleF.op_Implicit(e.Bounds), sf)
End Sub
C#
コードを隠すコードを選択
//フォームのLoadイベントハンドラ
private void Form1_Load(object sender, System.EventArgs e)
{
    //タブのサイズを固定する
    TabControl1.SizeMode = TabSizeMode.Fixed;
    TabControl1.ItemSize = new Size(60, 18);

    //TabControlをオーナードローする
    TabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
    //DrawItemイベントハンドラを追加
    TabControl1.DrawItem += new DrawItemEventHandler(TabControl1_DrawItem);
}

//TabControl1のDrawItemイベントハンドラ
private void TabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
    //対象のTabControlを取得
    TabControl tab = (TabControl)sender;
    //タブページのテキストを取得
    string txt = tab.TabPages[e.Index].Text;

    //タブのテキストと背景を描画するためのブラシを決定する
    Brush foreBrush, backBrush;
    if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
    {
        //選択されているタブのテキストを赤、背景を青とする
        foreBrush = Brushes.Red;
        backBrush = Brushes.Blue;
    }
    else
    {
        //選択されていないタブのテキストは灰色、背景を白とする
        foreBrush = Brushes.Gray;
        backBrush = Brushes.White;
    }

    //StringFormatを作成
    StringFormat sf = new StringFormat();
    //中央に表示する
    sf.Alignment = StringAlignment.Center;
    sf.LineAlignment = StringAlignment.Center;

    //背景の描画
    e.Graphics.FillRectangle(backBrush, e.Bounds);
    //Textの描画
    e.Graphics.DrawString(txt, e.Font, foreBrush, e.Bounds, sf);
}
補足:ホットトラックについて補足します。TabControl.HotTrackプロパティをTrueにしてホットトラック(タブの上にマウスポインタがあるときに外観が変化する)を有効にしても、DrawItemイベントハンドラのDrawItemEventArgs.Stateでタブがホットトラッキング中かを知ることができません(DrawItemEventArgs.StateにDrawItemState.HotLightが含まれません)。DrawItemイベントハンドラ内で、TabControl.GetTabRectメソッドで取得できるタブの範囲内にマウスポインタがあるかを調べることで、タブがホットトラッキング中かを知ることができそうですが、うまくいきません。(私が試してみた限りでは、タブが上か左にある時はうまくいくのですが、タブが下か右にあるときはホットトラッキングが解除されないときがあります。)これは、TabControlのMouseMoveとMouseLeaveイベントハンドラ内でホットトラッキング中のタブを調べることで、改善されるようです。

Paintイベントによる方法

上記のDrawItemイベントによる方法では、TabControlの背景(上の図で言えば、「最後」のタブの右側の部分)や、タブの枠は自分で描画できません。これらすべてを描画するには、非常に面倒ですが、Paintイベントを発生させて描画する方法があります。この方法について詳しくは、「TabControlを自分でビジュアルスタイルで描画する」をご覧ください。

  • 履歴:
  • 2010/9/8 コードを改善。ホットトラックについての補足を追加。「Paintイベントによる方法」を追加。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。