セルクリックでリストボックスを表示しユーザーが選択した値を取得するには

Question 30.1 Previous Next
データベースを作る際、ひとつの列にはたとえば10種類程度の決まった文字列しか入力しないとします。そのときに、リストボックスから選択することによって入力することはできますでしょうか?
マウスで右クリックして「リストから選択」とか[Alt]+[↓]を押さずに、入力するべきセルを選択したときに小さなウィンドウが現れるなど・・・。
テクニックを教えてください。よろしくお願いします。
Answer   Copyright (C) 2000.8.12 永井善王
質問の中に "[Alt]+[↓]を押さずに" と書かれていますので、これについて先に整理しておきます。
セルに入力中に、このショートカットキーを押すとオートコンプリートの一覧が表示されます。オートコンプリートとは、列にデータを数文字入力すると、先頭の数文字が同じ列にある既存のデータと一致する場合に、残りの文字列が自動的に入力される機能です。 この方法ではなくて解決したいのですね。
「入力するべきセルを選択したときに小さなウィンドウが現れる」ようにする方法を、考えてみましょう。

「10種類程度の決まった文字列しか入力しない」、「リストボックスから選択する」ということですので、ユーザーフォームにリストボックスを作ってみます。

右図のワークシートのデータを、リストに表示することにします。シート名は「リスト」です。

リストボックスのリストにデータを表示する方法は、いろいろあります。マクロで設定することも可能ですが、ここでは簡単でわかりやすいので、下図のようにリストボックスのプロパティに設定します。



これで下図のようなユーザーフォームを表示することができます。



データベース用のワークシートは、仮に下図のレイアウトにしておきます。


さあ、これでパーツは揃いました。
マクロを組み始める前に、全体の動きを描きます。

1.ユーザーは、「品名」を入力するために A列のセルをクリックする
2.マクロで自動的にユーザーフォームを表示する
3.ユーザーは、ユーザーフォームのリストに表示された品名を選択してクリックする
4.マクロで、クリックされた品名を A列のクリックされたセルに記入して、ユーザーフォームを非表示にする

それでは 1つ1つ順に、マクロを組んでみましょう。

1.と2.
セルがクリック(選択)されたらユーザーフォームを表示したいのですから、ワークシートで選択範囲を変更したときに発生する SelectionChange イベントを利用します。マクロは、そのワークシートのコード画面に記述します。注意点としては、このイベントは どのセルをクリックした場合にも発生するので、A列の場合だけ処理するように組むことです。
そして、A列であるならば、クリックされたセルの行番号を取得しておきます。この後 4.の処理で使うためです。
続いてユーザーフォームを表示するためのコードを記述します。
 ◆Worksheetのコード◆
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
                                                '選択範囲を変更したときに実行
    If Target.Column = 1 Then                   'A列なら
        行 = Target.Row                         '行番号を取得する
        UserForm1.Show                          'ユーザーフォームを表示する
    End If
End Sub
(注)Target は選択されたセル範囲
3.と4.
クリックされた品名を取得するために、リストボックスのリストがクリックされたときに発生する Clickイベントを利用します。このマクロはユーザーフォームのコード画面に記述します。
注意点が 3つあります。
(1)A1セルは見出しですから、たとえ選択されても品名をセットしない
(2)品名のセットが終わったら、次の選択に備えてユーザーフォームを非表示にする
(3)ユーザーフォームの「×」ボタンがクリックされたらメモリから削除する ことです。
 ◆UserForm1のコード◆
Private Sub ListBox1_Click()                    'クリックされたときに実行される
    If 行 <> 1 Then                             '1行目でなければ
        Cells(行, 1) = ListBox1.Value           'リストボックスの値をセルにセットする
    End If
    UserForm1.Hide                              'ユーザーフォームを非表示にする
End Sub

Private Sub UserForm_Deactivate()               '非アクティブになったときに実行される
    Unload Me                                   'ユーザーフォームをメモリから削除する
End Sub
お気付きかと思いますが、変数「行」がワークシートのコードと、ユーザーフォームのコードの両方にまたがって使われています。そのため標準モジュールへ次のように、宣言しておきます。
また、auto_openプロシージャでユーザーフォームをメモリに読み込んでいるのは、1回目のクリックで素早く表示するためです。必ずいる訳ではありません。
 ◆標準モジュールのコード◆
Option Explicit
Public 行 As Variant                            '行番号

Sub auto_open()
    Load UserForm1                              'ユーザーフォームをメモリに読み込む
End Sub
これで一通り作り終えました。名前を付けて保存します。そして一旦、閉じて、改めて開きます。

左図のように、ワークシートのA列でクリックすればユーザーフォームが表示され、リストから品名を選択すれば、クリックしたセルに品名がセットされるはずです。

B、C、D列は、それらしくデザインしただけで特に意味はありません。試しにクリックしてみましょう。ユーザーフォームは表示されないはずです。

出来上がってみると、こんなに簡単でいいの? と感じませんか。

Excelは多機能ですから、どの機能と、どの機能を組み合わせればよいかをしっかり押さえれば、一見複雑そうな処理でも比較的簡単なマクロで済ますことが可能になる場合があります。

ここをクリック すれば、Excel97以上用のサンプルブックをダウンロードできます。
Internet Explorerから直接開くと、うまく動作しない場合があります。ハードディスクに保存して、改めて開いてから試してください。
最後に "マウスで右クリックしてリストから選択" についてですが、SheetBeforeRightClickイベントを利用することになるでしょうが、この「すぐに役立つエクセルVBAマクロ集」に、 ショートカットキーと右クリックを無効にするには のページがあります。それを参考にして研究してみてください。
関連ページ
リストボックスで直前に選択された項目を再び選択可能にするには

Excel VBA Macro