t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

VBA Excelでフォームのタブオーダーを自動設定する方法

次のフォームをご覧いただきたい。
f:id:t-hom:20151217233824p:plain

普段からキーボードで入力されている方はご存じだと思うが、ひとつの項目を入力し終わったとき、Tabキーを押すと次のテキストボックスにカーソルが移動する。
実はテキストボックスのTabIndexプロパティには数値が入っており、数値の小さい順にカーソルが移動する仕組みになっている。
このTabでジャンプする順番のことを、タブオーダーという。

普通は、上から下へ順番に移動するのだが、これはフォームのデザイン画面でテキストボックスを張り付けた順番に依存しており、既存のテキストボックスの間に新しいテキストボックスを挿入したりするとタブオーダーが上から下の並びではなくなってしまう。

さて、度重なるデザインの変更で、タブオーダーが以下のようにバラバラになってしまったとしよう。
f:id:t-hom:20151217235132p:plain

これがAccessフォームなら、タブオーダーの自動設定機能を使って簡単に上から順にTabIndexを設定することができる。
しかしExcelにその機能はない。

仕方がないので、今回はその機能を自前で作ってみた。

まずは「Microsoft Visual Basic for Applications Extensibility X.X」を参照設定しておく。
f:id:t-hom:20151217235639p:plain

次に標準モジュールを用意し、次のコードを張り付ける。

Sub CollectionSwap(C As Collection, Index1 As Long, Index2 As Long)
    Dim Item1 As Variant, Item2 As Variant
    
    If IsObject(C.Item(Index1)) Then
        Set Item1 = C.Item(Index1)
    Else
        Let Item1 = C.Item(Index1)
    End If
    
    If IsObject(C.Item(Index2)) Then
        Set Item2 = C.Item(Index2)
    Else
        Let Item2 = C.Item(Index2)
    End If
    
    C.Add Item1, After:=Index2
    C.Remove Index2
    C.Add Item2, After:=Index1
    C.Remove Index1
End Sub

Sub CSort(C As Collection, SortKeyFunction As String)
    Dim i As Long, j As Long
    For i = 1 To C.Count
        For j = C.Count To i Step -1
            If Application.Run(SortKeyFunction, C(i)) _
                > Application.Run(SortKeyFunction, C(j)) Then
                    CollectionSwap C, i, j
            End If
        Next j
    Next i
End Sub

※こちらのコード解説は以下の過去記事を参照
thom.hateblo.jp

次に、もう一つ標準モジュールを用意し、次のコードを張り付ける。

Sub AutoTabOrder()
    Dim f As UserForm
    Set f = ThisWorkbook.VBProject _
        .VBComponents.Item("UserForm1").Designer
    
    Dim C As Control
    Dim ControlCollection As New Collection
    For Each C In f.Controls
        If TypeName(C) = "TextBox" Then
            ControlCollection.Add C
        End If
    Next
    
    CSort ControlCollection, "SortKey"
    For i = 1 To ControlCollection.Count
        ControlCollection(i).TabIndex = i - 1
    Next
End Sub

Function SortKey(C As Control) As Single
    SortKey = C.Top
End Function

これらのモジュールは修正したいフォームと同じファイルに作成する必要がある。

コードの実行前に、セキュリティセンターのマクロの設定から、VBA プロジェクト オブジェクト モデルへのアクセスを信頼するにチェックを入れておく必要がある。
※やり方が分からなければ以下の過去記事を参照。
thom.hateblo.jp

さて、このAutoTabOrderを実行すると、UserForm1にあるTextBoxが全てCollectionに格納され、CSortプロシージャによりTopプロパティの数値が小さい順にCollectionが並び替えされる。そして並び替えされた順にTabIndexが設定される。

フォームを実行してみるとこのとおりタブオーダーが上から順に綺麗に設定されている。
f:id:t-hom:20151218001643p:plain

応用編

このようなタブオーダーにしたいときはどうすれば良いだろうか。
f:id:t-hom:20151218002012p:plain
コードで対応しても良いけど面倒くさい。

簡単にやるならば、右側のテキストボックスを一時的にずらせばよい。
f:id:t-hom:20151218002203p:plain

この状態でAutoTabOrderを実行すると、上から順に綺麗に並ぶので、それからテキストボックスの位置をもとに戻す。

まとめ

フォームデザイナーは直感的で分かりやすい反面、ひとつずつ手で設定しなければならない面倒くささがある。今回のようにコードでコントロールのプロパティをいじる方法を覚えれば、手早くフォームを修正できるようになる。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。