- ベストアンサー
Excel VBA ユーザフォームの検索について
- Excel VBAでユーザフォームを作成し、検索機能を実装したい場合に発生するエラーについて質問です。
- ユーザフォームの初期化時に、特定のシートからリストを取得し、ComboBoxに表示する処理にエラーが発生しています。
- エラーの内容が「実行時エラー9 インデックスが有効範囲にありません」と表示されています。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
もう1つ。 宣言文で Option Base 1 と書いてある所はありませんか? これがかいてある場合、配列の添え字は「1から」になります。 Private Sub UserForm_Initialize() の方では ReDim tbl(imax) For i = 1 To imax tbl(i) = Range("A" & i).Value Next i のように、配列の添え字は「1からimaxまで、imax個」になっています。 一方 Private Sub CommandButton1_Click() の方では j = -1 とやってから j = j + 1 tbl(j) = Range("A" & i).Value とやってますから、配列の添え字は「0からcntまで、cnt+1個」のツモリで動い ています。 Option Base 1 が宣言されている場合は、配列の添え字は「1から」ですから「jが0の状態で、tbl(j)に値を入れようとすると、添え字の値がエラーになる」のです。 実は、コレがエラーが出ている「直接の原因」です。 プログラム全体を見直しして「配列を、1番から使うか、0番から使うか、統一しないといけない」です。 現在は、UserForm_Initialize()の方は「1番から使うつもり」になっていて、CommandButton1_Click()の方は「0番から使うつもり」になっていて、整合性が取れていません。 とりあえずは「j = -1」と書いてあるのを「j = 0」に直して、プログラムの先頭行に「Option Base 1」と言う行を追加しましょう。これで「とりあえずはエラーが消える筈」です。 なお「色々なサイトから参考にした」という場合、これ以外にも「整合性がとれてない部分」が多く存在する筈なので、プログラム全体を見直しする必要があるでしょう。隠れたバグは、ここだけでは無い筈です。
その他の回答 (3)
- imogasi
- ベストアンサー率27% (4737/17069)
>Excel VBA ユーザフォームの検索について は表現が不適切。 「Excel VBA ユーザフォームを使っての検索について」 ぐらいならおかしくはないと思うが。 ーー どういう道具立てで、検索しようとしているのか、文章ではっきり説明せよ。 読者に、質問者の、十分でないコードをコピぺして読み解いてくれ、修正して回答してくれと言うのは、質問者として手抜きすぎる。 ーー もう一つの要求は、Sheet1-Sheet3の簡単な模擬実例でも挙げて説明すべきだ。 Sheet1、Sheet2、Sheet3があるらしいが、Sheet2から、Combobox1にリストするのはどういうものか。 Sheet2の役割は何か? 検索語はTextBox1の語とどういう関係にあるのか。 TextBoxとCombobxとの役割はどうなっているのか? ーー シートを検索するのは、普通はFindメソッドを使うが、INSTR関数を使っているのは知らないからか(Find、FindNextは確かにむつかしいが) ーー そういうやりたいこの「仕組み(検索語)と対象」の説明が不足しているとおもう。. ーー すでにご指摘があるが、シートが複数の場合は、神経質ぐらい、繰り返してシート部分から、記述したほうが良いと思う。AvtiveSheetに当たる考えは封印すべきと思う。 プロシの初めに Set Sh1 = Worksheets("Sheet1") Set Sh2 = Worksheets("Sheet2") Set Sh3 = Worksheets("Sheet3") と定義してSh1、Sh2,Sh3のどれかをRange表現の前につけて限定するとか。 ーー Imaxの値は、別モジュールに変数結果を渡すのは高等テクニックなので、注すること。質問のコードではその工夫が見られないようだが。 ーー 質問掲示コードを修正して上げるつもりだったが、やりたいことの仕組みが理解できず諦めた。上記で何かの参考になれば。
- chie65536(@chie65535)
- ベストアンサー率44% (8752/19860)
なお、UserForm_Initialize()の方も「呼び出した瞬間(ユーザーフォームを初期化した瞬間」のアクティブシートがsheet2じゃなかったら tbl(i) = Range("A" & i).Value の「Range()」は「Sheet2じゃないシート」を参照するので、やはり、誤動作します。 こっちも同様に Private Sub UserForm_Initialize() Dim i As Long, imax As Long Dim tbl() As Variant imax = ThisWorkbook.Worksheets("sheet2").Cells(ThisWorkbook.Worksheets("sheet2").Rows.Count, "A").End(xlUp).Row ReDim tbl(imax) For i = 1 To imax tbl(i) = ThisWorkbook.Worksheets("sheet2").Range("A" & i).Value Next i ComboBox1.List() = tbl() End Sub のようにしないといけません。 あと imax = ThisWorkbook.Worksheets("sheet2").Cells(ThisWorkbook.Worksheets("sheet2").Rows.Count, "A").End(xlUp).Row ではなく imax = ThisWorkbook.Worksheets("sheet2").Cells(Rows.Count, "A").End(xlUp).Row としてしまった場合、1つのブックしか開いてなければ問題ありませんが、旧バージョン(2007より古いバージョン)のEXCELのブックを開いている場合、問題が出る可能性があります。 Excel 2007以前のバージョンで作成したブックを開いていて、そのブックがアクティブになっていると「Rows.Count」の値は「65536」になってしまいます。 しかし、Excel 2007以降のブックは、行数の最大値は「1048576」ですから「入力されている最後の行」を求めるのに失敗してしまいます。 「Range」や「Cells」や「Rows.Count」など「現在アクティブになっているブックの、現在アクティブになっているシートに関連するプロパティやメソッド」を使用する場合は「今、どのブックの、どのシートがアクティブなのか?」を、きちんと把握していなければなりません。 さもないと「シート2をいじってるツモリで、全然ちがうシートをいじってた」なんて事が起きます(それでエラーが起きれば不具合に気付けますが、エラーが起きなければ「実行してる筈なのに、なにも起きない」とか「変な値がセットされる」とか、どうして良いか判らなくなります)
- chie65536(@chie65535)
- ベストアンサー率44% (8752/19860)
With ThisWorkbook.Worksheets("sheet2") から End With までの間は「Range()やCells()」と「.Range()や.Cells()」は、意味が異なります。 「.Range()」は「ThisWorkbook.Worksheets("sheet2").Range()」を意味します。 一方「Rnage()」は「ActiveSheet.Range()」を意味します。 「Cells()」や「Rows」など、他の物も同様です。 ですので「アクティブシートがsheet2じゃない状態」の場合「Range」や「Cells」は「sheet2じゃないシート」を参照してしまいます。 つまり「Rangeと.Range、Cellsと.Cellsなど、ピリオドがある物とない物が混在してしまっているので、アクティブシートがsheet2じゃないと正常に動作しない状態」になってしまっています。 「アクティブなシートがどこであっても、ちゃんと動くようにしたい」のであれば「With文を使わず、シートの指定をきちんと書く」ようにしましょう。 とりあえず Private Sub CommandButton1_Click() Dim i As Long, imax As Long Dim tbl() As Variant Dim cnt As Long, j As Long j = -1 imax = ThisWorkbook.Worksheets("sheet2").Cells(ThisWorkbook.Worksheets("sheet2").Rows.Count, "A").End(xlUp).Row cnt = Application.CountIf(ThisWorkbook.Worksheets("sheet2").Range("A1:A" & imax), "*" & TextBox1.Text & "*") ReDim tbl(cnt) For i = 1 To imax If InStr(ThisWorkbook.Worksheets("sheet2").Range("A" & i), TextBox1.Text) > 0 Then j = j + 1 tbl(j) = ThisWorkbook.Worksheets("sheet2").Range("A" & i).Value End If Next i ComboBox1.List() = tbl() End Sub のように、With文を一切使わないで、1つ1つ、こまめにシートを指定してみて下さい。