業務効率化に役立つVBA/マクロのさまざまなTipsをコード例を交えて紹介していきます。今回は、SetFocusメソッド、SelStartプロパティ、SelLengthプロパティを使ってExcel業務を速く正確に行うための大きな改善方法を解説する。
今回も、テキストボックスコントロールの使い方についてのTipsの解説だ。テキストボックス内の文字列を選択状態にする方法と、テキストボックス内を検索する方法の2つのTipsを紹介する。いずれも、SetFocusメソッド、SelStartプロパティ、SelLengthプロパティを使う。
テキストボックス内の文字列を選択状態にする方法では、フォーム上に配置されたテキストボックス内に、文字列が表示されており、その文字列を選択状態にする。文字列が選択状態になっていると、すぐにその上から別な文字列を上書き入力して変更することが可能で、文字列入力の際の手間が省ける。
また、テキストボックス内を検索する方法では、テキストボックス内に任意の文字列が含まれていた場合は、その文字列を選択できるようする。Excelシート上のセル内に、長い文章が表示されており、「フォームを開く」ボタンで「フォーム」を開くと、テキストボックス内に、Excelシートに表示させていた内容を表示させ、開いたフォーム上で文字列を検索して、検索に該当する文字列を選択状態にする。
では、こうしたTipsはどのような場合に役立つのだろうか。Excel上で直接検索する場合とフォーム上で検索する場合とでは、後者の方ががぜんアプリケーションらしく見える。この点で、「いかにもプログラムを書いた!」ということを周囲の人間に認識させる効果があるのでは、と筆者は思っている。
まず、Excelシート上に図1のようなデータと「フォームを表示」ボタンを作成しておく。
次に、ユーザーフォームを作成し、UserForm1のCaptionプロパティに「文字の選択フォーム」と指定しておく。
ユーザーフォーム上には、テキストボックスとリストボックスを配置しておく。テキストボックスの「オブジェクト名」には「氏名テキストボックス」、リストボックスの「オブジェクト名」には「一覧リストボックス」とプロパティから指定して、図2のように配置する。
テキストボックスやリストボックスの、「書体」や「文字サイズ」は、「Font」プロパティから指定している。読者の皆さんの好きな指定にしてもらって構わない。
テキストボックス内の文字列を選択状態にする書式は下記のようになる。
With {オブジェクト}
.SetFocus
.SelStart = 0
.SelLength = Len(.Text)
End With
{オブジェクト}には、対象となるテキストボックスオブジェクトを指定する。「SetFocus」で、テキストボックスオブジェクトにフォーカスを移す。「SelStart」で、カーソルを指定した文字位置に移動する。「SelLength」に、Len関数を使って、テキストボックス内で選択されている文字数を指定する。
この書式を基にコードを記述していこう。プロジェクト内のUserForm1を選択して、マウスの右クリックで表示される「コードの表示」を選択して、コードを記述していく。
まず、ユーザーフォームがアクティブになったときに、「一覧リストボックス」に氏名を表示させる(リスト1)。次に、「一覧リストボックス」から選択した氏名を、「氏名テキストボックス」に表示し、選択状態にする(リスト2)。その後、選択状態になった氏名を書き換えると、Excelシート上の氏名と、「一覧リストボックス」内の氏名も書き替わる。コードはリスト3になる。
Option Explicit Private Sub UserForm_Activate() Dim i As Integer For i = 2 To 10 一覧リストボックス.AddItem (Cells(i, 2)) Next End Sub
リスト1から説明しよう。これはユーザーフォームがアクティブになったときの処理で、UserForm_Activateイベント内に記述する。
3行目でInteger型変数「i」を宣言する。4行目で変数「i」を「2」〜「10」まで繰り返すFor文を記述している。この数値はセルの「行番号」に該当するものだ。繰り返す過程の5行目で、「一覧リストボックス」にAddItemメソッドで「Cells(行番号,列番号)」を使って、「B列」である「2」列目の、「2行目」〜「10行目」の内容を取得して追加していく。
リスト2は「氏名テキストボックス」内の文字列を選択状態にするコードだ。
Private Sub 一覧リストボックス_Change() 氏名テキストボックス.Text = 一覧リストボックス.Text With 氏名テキストボックス .SetFocus .SelStart = 0 .SelLength = Len(.Text) End With End Sub
「一覧リストボックス_Change」イベント内に記述する。まず2行目で「氏名テキストボックス」に、「一覧リストボックス」から選択された値を表示する。
3〜7行目で「氏名テキストボックス」に、フォーカスを移し、最初の文字から、Len関数を使って、表示されている文字列の、文字数分を選択状態にする。
リスト3は選択状態になった氏名を書き換えると、Excelシート上の氏名と、「一覧リストボックス」内の氏名も書き替わるコードだ。「氏名テキストボックス_Changeイベント」内に記述する。
Private Sub 氏名テキストボックス_Change() Cells(一覧リストボックス.ListIndex + 2, 2) = 氏名テキストボックス.Text 一覧リストボックス.List(一覧リストボックス.ListIndex) = 氏名テキストボックス.Text End Sub
まず、2行目で「一覧リストボックス」から選択された項目のインデックス番号と、「行番号」に対応するセルの値を、「氏名テキストボックス」の値に置き換える。ListIndexに「2」を加算しているのは、「一覧リストボックス」のListIndexが「0」から始まるので、Excelシート上の「行番号」に合わせるために必要だからだ。
次に、3行目で「一覧リストボックス」内に表示されている氏名で、「一覧リストボックス.ListIndex」に該当する氏名を、「氏名テキストボックス」の値に置き換える。
これで、Excelシート上の氏名と「一覧リストボックス」から選択された氏名が、「氏名テキストボックス」で書き換えられた「氏名」に置き換えられる。
次にVBE(Visual Basic Editor)のメニューから、[挿入]→[標準モジュール]を選択する。プロジェクト内にModule1が追加されるので、この中に「フォームを表示」するコードを記述する(リスト4)。
Option Explicit Sub フォームを表示() UserForm1.Show vbModeless End Sub
今回は、UserForm1にShowメソッドで用いて、フォームが表示されている状態でも、Excelの操作が可能な、モードレス表示でフォームを表示させる。
このリスト4のコードを、図1の「フォームを表示」ボタンに関連付けて実行した結果が図3だ。「一覧リストボックス」内の氏名を選択すると、「氏名テキストボックス」に表示されている氏名が、選択状態になる。氏名を上書きで変更すると、変更内容がExcelシート上の氏名と、「一覧リストボックス」で選択されていた氏名に反映される。
まず、「文字列検索」という名前の新しいシートを追加する。その「文字列検索」シート内のExcelシート上に、図4のようなデータと「フォームを表示」ボタンを作成しておく。
次に、ユーザーフォームを作成し、「UserForm2」の「Caption」プロパティに、「文字列の検索」と指定しておく。
ユーザーフォーム上には、テキストボックスを2個と「ボタン」を1個配置しておく。プロパティから、文字列を表示させるテキストボックスのオブジェクト名は、「文字テキストボックス」とし、プロパティから「MultiLine」にTrueを指定して、複数行の入力を可能にしておく。
もう一つのテキストボックスのオブジェクト名は、「検索テキストボックス」とし、プロパティから「IMEMode」に「fmIMEModeOn」を選択し、「かな入力」を可能にしておく。
「ボタン」のオブジェクト名は「実行ボタン」と指定しておく。コントロールを配置すると図5のようになる。
テキストボックス内を検索する書式は下記の通りだ。
With {オブジェクト}
If InStr(.Text, 検索テキストボックス.Text) > 0 Then
.SetFocus
.SelStart = InStr(.Text, 検索テキストボックス.Text) - 1
.SelLength = Len(検索テキストボックス.Text)
End If
End With
{オブジェクト}には、テキストボックスオブジェクトを指定する。InStr関数で、テキストボックス内に、「検索テキストボックス」で指定した文字が見つかった文字位置を取得する。
SetFocusメソッドで見つかった検索文字列にフォーカスを移す。SelStartで、Instr関数で見つかった文字位置に移動する。「-1」しているのは、Instr関数で返される文字位置は「1」から始まるためだ。SelStartで移動する位置は、先頭の場合は「0」を指定する必要があるため「-1」をしている。SelLengthに、Len関数で「検索テキストボックス」に指定した値の文字数を取得して指定する。
まず、ユーザーフォームがアクティブになったときの処理を記述するコードはリスト5になる。「UserForm_Activate」イベント内に記述する。
Option Explicit Private Sub UserForm_Activate() 文字テキストボックス.Text = Range("B2").Value End Sub
Excelシート上の「B2」のセルに入力されている値をテキストボックスに表示する簡単なコードだ。
次に、「実行」ボタンがクリックされたときのコードはリスト6になる。「実行ボタン_Click」イベント内に記述する。
Private Sub 実行ボタン_Click() If 検索テキストボックス.Text = "" Then MsgBox "検索文字を入力!" Exit Sub Else With 文字テキストボックス If InStr(.Text, 検索テキストボックス.Text) > 0 Then .SetFocus .SelStart = InStr(.Text, 検索テキストボックス.Text) - 1 .SelLength = Len(検索テキストボックス.Text) Else MsgBox "検索文字が見つかりません!" Exit Sub End If End With End If End Sub
2行目で「検索テキストボックス」に、検索対象文字が入力されていなかった場合は、メッセージを表示して処理を抜ける。それ以外は6行目以下の処理を行う。
7行目では、Instr関数で「文字テキストボックス」内に「検索テキストボックス」で指定した文字が含まれているかをチェックし、含まれている場合は8〜10行目でその文字位置を返す。よって文字位置が「0」より大きい場合は、検索対象が見つかったことになるため、「文字テキストボックス」内にフォーカスを移し、「検索テキストボックス」で指定された文字を選択状態にする。
もし、Instr関数での戻り値が「0」より小さい場合は、検索対象が見つからなかったことになるので、12〜13行目のようにメッセージを表示して処理を抜ける。
この検索では、検索対象が複数あった場合でも、最初に見つかった文字しか返さないことをご了承願いたい。
実行結果は図6だ。テキストボックス内で、「検索文字」に指定した文字を選択状態にしている。
今回はテキストボックス内の文字列を選択状態にする方法とテキストボックス内を検索する方法の、2つのTipsについて解説した。
テキストボックス内の文字列を選択状態にする方法では、「一覧リストボックス」から選択した氏名が、選択状態になって、テキストボックスに表示され、そのままの状態で上書きができる。ちょっとしたTipsだが、文字列を目視で探して選択し上書きするより、一手間が省けるのではないだろうか。一手間の改善が、業務を速く正確に行うための大きな改善につながっていくと思う。
テキストボックス内を検索する方法では、Excelのマクロを「いかにしたら独自のアプリケーションらしく見えるか」という意味で紹介した。文章を表示している「B2」のセルを非表示にして実行すれば、なおさらアプリケーションらしく見えると思うのだが、いかがだろうか。
次回はリストボックスコントロールのTipsについて解説する予定だ。お楽しみに。
薬師寺 国安(やくしじ くにやす) / 薬師寺国安事務所
薬師寺国安事務所代表。Visual Basicプログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。
1997年に薬師寺聖とコラボレーション・ユニット「PROJECT KySS」を結成。
2003年よりフリーになり、PROJECT KySSの活動に本格的に参加。.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。
Windows Phoneアプリ開発を経て、現在はWindowsストアアプリを多数公開中。
Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。
Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。
Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。
Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。
Copyright © ITmedia, Inc. All Rights Reserved.