VBAの修正箇所について

このQ&Aのポイント
  • 質問文章からVBAの修正箇所についてまとめました。
  • エラー名は「インデックスが有効範囲にありません」と表示されています。
  • 修正方法は、指定文字を含むシートを検索し、該当するシート名を返す関数を修正することです。
回答を見る
  • ベストアンサー

VBA 修正箇所について

(※)の行にエラーがでているのですが、何を指摘されているのか、どう直せば良いのかが分かりません。下記の情報だけで何かわかりますか?エラー名はインデックスが有効範囲にありませんです。 '******************************************************************************* '機能名  :指定文字を含むシートを検索し、指定文字を含んだシート名を返す '引数   :指定文字(String型) '戻り値  :指定文字を含んだシート名を返す(String型) '備考   :指定文字を含んだシート名が存在しない場合は"NotFound"が返される '******************************************************************************* Public Function gFnc_strSelectSheet(ByVal strTargetSheetName As String) As String Dim i As Integer, intChkFlg As Integer Dim strResult As String intChkFlg = 0 For i = 1 To Sheets.Count (※)If InStr(Worksheets(i).Name, strTargetSheetName) > 0 Then strResult = Worksheets(i).Name intChkFlg = 1 End If Next If intChkFlg = 0 Then strResult = gcnstrNotFound gFnc_strSelectSheet = strResult End Function

質問者が選んだベストアンサー

  • ベストアンサー
  • asciiz
  • ベストアンサー率70% (6636/9403)
回答No.1

「インデックスが有効範囲にありません」 というエラーは例えば、配列名(1)~(10) までしか用意していないのに、配列名(11)にアクセスしたようなときに出ます。 で、(※)の行のどこに配列アクセスがあるかというと、「Worksheets(i)」の部分です。 この場合、i がどのような値を取っているかデバッガで調べ、i が異常値になった原因を探ったりします。 ---- がしかし、今回の問題はそんな難しい話ではありません。 > For i = 1 To Sheets.Count これで1ワークシート内の全シート情報を読んだりしたいなら、 「Worksheets(i).Name」でなく「Sheets(i).Name」としたかったんじゃないでしょうか。 Worksheets オブジェクトと、Sheets オブジェクトは、まったく別のものですが、どちらも配列オブジェクトであり、.Nameプロパティも存在するため、「Worksheets(i).Name」という書き方は通ってしまいました(文法エラーになりません)。 しかし1ファイルだけを開いていれば「Worksheets(i)」は1つしかないため、「Worksheets(2)」にアクセスしようとした時点で、インデックス外エラーになったんです。 プログラミングとしては、「オブジェクト名の間違いにより、無関係のものにアクセスしてしまった」ということがエラー原因となります。

maron915
質問者

お礼

簡潔に分かりやすい回答を有難うございます。 初心者ゆえに、かみ砕いた説明がとても助かります。

その他の回答 (4)

  • kkkkkm
  • ベストアンサー率65% (1615/2454)
回答No.5

No.2の補足です 簡単な説明です。 何を指摘されているのかですが Worksheets(i) この場合は、その番号のシートはありませんということです。 Worksheets.Count は通常のシートの数で Sheets.Count は、グラフシートのように通常のシート以外も含めた数になります。 For i = 1 To Sheets.Count で、通常のシート以外も含めた数までループしていて (※)If InStr(Worksheets(i).Name, strTargetSheetName) > 0 Then で通常のシートの番号を指定しています。 「i」が通常のシートの数を超えた場合 その番号のシートはありませんとなります。 通常のシートしかない場合は、元のままでもエラーにはならないと思います。 Worksheets.CountとSheets.Countのどちらを使うかは、通常シート以外も探すかどうかで決めて下さい。

maron915
質問者

お礼

細かく教えて下さり有難うございます。 初心者故に、詳細の説明がとても助かります。

  • kkkkkm
  • ベストアンサー率65% (1615/2454)
回答No.4

No.2の追加です。 For i = 1 To Worksheets.Count とした方が一か所の訂正ですむのでいいかもしれません。

  • nda23
  • ベストアンサー率54% (777/1415)
回答No.3

オブジェクトの階層を理解しておられるでしょうか? Application→WorkBooks→Workbook→ WorkSheets→WorkSheet→Cells→Cell のようにコレクション(複数形)とオブジェクト(単数)は 階層構造になっています。 1.WorkSheetsですが、「どのブックに属するか」が不明です。  一度に複数のブックを開く可能性があるので、必ず親ブックを  指定しなければなりません。デフォルトはActiveWorkbookですが、  これが、どのブックを指すかという保証はありますか?  そういう意味で、このプロシージャには潜在バグがあります。  もし、自身のブックなら、ThisWorkbook.WorkSheetsとすべきです。  他のブックでしたら、Workbook型の変数を引数か大域変数に  指定したほうがよいでしょう。 2.変数の取り方  私は機械語が専門で、VBAを見ても内部の動作が透けて見えます。  偉そうな物言いで、恐縮ですが、以下のようにすべきと思います。  Dim 索引 As Long, 個数 As Long  Dim シート名 As String  Dim シート集合 As WorkSheets  Dim シート個別 As WorkSheet  Set シート集合 = ThisWorkbook.WorkSheets  個数 = シート集合.Count  For 索引 = 1 To 個数   Set シート個別 = シート集合(索引)   シート名 = シート個別.Name   Set シート個別 = Nothing   '★名前を検出したらForループを抜ける   If Instr(シート名, strTargetSheetName) > 0 Then Exit For  Next  Set シート集合 = Nothing  '★見つからないと、索引が個数を超える。  If 索引 > 個数 Then   strResult = gcnstrNotFound  Else  '★見つかれば途中で抜けたので、索引≦個数になる   strResult = シート名  End If 要点 A.変数型のIntegerは16ビット整数で、32/64ビットCPUで  使用すると、効率が悪いので、整数値は理由がない限り、  Long(32ビット)を使うべきです。  自動変数に16ビット値を使ってもメモリの節約にはなりません。 B.オブジェクトは必ず、階層構造の修飾をする。  既に述べたように、デフォルトに任せるのは「バグ」と言っても  過言ではありません。 C.コレクションやオブジェクトは使用済みになったら、  速やかに解放します。(Set xx = Nothing)  オブジェクトは内部に参照カウンタを持っており、解放により  デクリメントされる。参照カウンタが0になると、オブジェクトが  使用していたメモリが解放されます。  これを怠ってもガベジコレクタが、何とかしてくれるますが、  その間、メモリを浪費し、システムパフォーマンスに悪影響が  出ます。 D.プロパティの取得、メソッドの実行は極力回数を減らすべきです。  機械語でオブジェクト操作すると分かりますが、これらの動作は  相当な労力を必要とします。拝見すると、"WorkSheets(i)"を  多用していますが、デフォルトのItemプロパティの参照になり、  更に、目に見えないWorkSheetオブジェクトのNameプロパティを  参照しています。Nameプロパティの取得の度に、新しい文字列が  生成され、メモリ効率が悪化します。 まぁ、上記で言う悪影響とは1~2桁のマイクロ秒の話で、 神経質にならなくても、イイのですが、参考になれば幸いです。

  • kkkkkm
  • ベストアンサー率65% (1615/2454)
回答No.2

多分グラフシートのような通常のシートじゃないものとかがあるのではないでしょうか InStr(Sheets(i).Name, strTargetSheetName) > 0 とすればエラーは無くなると思います。

関連するQ&A

  • 全くの初心者ですVBA

    どこが悪いかわかりません。 教えてください。 Sub テスト() Dim kekka As String Dim i As Integer tokuten = Worksheets("Sheet1").Cells(i, 1).Value For i = 1 To Worksheets("Sheet1").Range("A1").End(xlDown).Row.Count If tokuten >= 80 Then kekka = "合格" Else kekka = "不合格" kekka = Cells(i, 2) End If Next i End Sub シート1の A列に数値で得点が入っています。

  • VBAでのシート選択について

    いつもお世話になります。 VBA初心者で、基本的な質問をしているかもしれませんが、 どうかお付き合いください;; たとえば、以下のようなコードがあったとします。 例) Function Sample() dim x As Integer dim y As Integer x=10 y=100 If x > sheets("シート2").Range("A1") AND y < sheets("シート2").Range("A1") Then 処理 End If End Function 例えば上記のコードのようなものがあったとして、 シート名を省いて文字数を減らす方法はあるでしょうか? 1つのFunction内では「このシート」しか参照しないというような指定が出来ると、 If x > Range("A1") AND y < Range("A1") Then というように簡単にできますよね? 他のFunctionでは、シートの指定はさせたくないので、 End Functionの手前で、「シート指定終了」というのを 記述できればベストなのですが…。 どうかよろしくお願いいたします。

  • 以下のコードですと、アクティブシート以外全て隠してしまいますが、

    以下のコードですと、アクティブシート以外全て隠してしまいますが、 選択(複数)されているシート以外を非表示にするにはどのように書き換えたら良いでしょうか。 Sub Test() Dim mstr as String Dim i as Integer mstr = ActiveSheet.Name For i = 1 To Worksheets.Count If Worksheets(i).Visible = True And Worksheets(i).Name <> str(0) Then Worksheets(i).Visible = xlVeryHidden End If Next i End Sub よろしくお願いします。

  • シート名をループに

    質問を簡単にする為に以下のマクロがあるとします。 シート名が1~31とあるのですが、これをfor loopで 使うにはinteger等の定義が違うのでしょうか。 Sub bbb() Dim ws As Worksheet Dim 曜日 As String Dim i As Integer For Each ws In Worksheets For i = 1 To 31 If ws.Name = i Then  <----------ここでエラー  (コマンド) End If Next i Next End Sub

  • VBAで教えて下さい。

    VBA初心者です。始めてから2,3週間です。 表を作りたいのですが、 顧客名のシートを100枚ほど作り、シート1(シート1は検索シートにしたいので顧客名は無)のA1にクライアント名を入力したら入力した顧客名シートが出てくる様にしたいです。 参考書、ネット等をみて作成しましたがエラーが出ます。作動するにはどの様にしたら宜しいでしょうか?どうかお助け下さい。宜しくお願い致します。コードは下記です。 Private Sub Worksheet_Change(ByVal Target As Range) Dim i As Integer Dim myWSname As String, myworksheet As Worksheet myWSname = "i" myWSname = Worksheets("sheet2").Range("A1").Value For Each myworksheet In Worksheets If myworksheet.Name = mayWSname Then Worksheets("myWSname").Activate Exit Sub End If Next myworksheet End Sub

  • エクセル、ワークシートが保護されているかどうかを判断するVBAは?

    以下のように書いてもダメでした。 どう直せばよいでしょうか? Sub TEST2() Dim n As Integer n = ThisWorkbook.Worksheets.Count For i = 1 To n If Worksheets(i).Protect = False Then MsgBox Worksheets(i).Name End If Next End Sub

  • VBA マクロについて

    自作のカレンダーに自動で日付を判定、入力してくれる ロジックを作っていたのですが、 2、4、6、9、11月以外は31日分表示されるはずが。。。 表示されませんでした。 恐らくロジックがおかしくて i=31 が通っていないものと 思われますが、ちょっとよく分かりません。 初心者で低レベルな質問ですけど、どなたかお願いします。 Sub AutoCarender() '自動でカレンダーの日付を入力するプログラム Dim month, i As Integer '表示させたい月 month = 3 If (month = 2) Then i = 28 ElseIf (month = 4 Or 6 Or 9 Or 11) Then i = 30 Else i = 31 End If Dim tate, yoko As Integer Dim week As Integer week = (Weekday(2009 / month / 1, 2)) yoko = Choose(week, 1, 3, 5, 7, 9, 11, 13) tate = 3 For j = 1 To i '"シートの名前"を指定 Worksheets("Sheet1").Cells(tate, yoko).Value = j yoko = yoko + 2 If (yoko > 13) Then yoko = 1 tate = tate + 2 End If Next End Sub

  • Excel VBAで検索する

    Excel VBAで、Sheet1に貼り付けたテキスト内から Sheet2に記載した(1列ごとの)キーワードを検索し キーワードが含まれている行をSheet3に貼り付ける処理をしているのですが、始めたばかりなので上手くいきません。 下記がソースです。 Dim moji As String Dim word As String Dim result As Integer For i = 3 To 103 For j = 2 To 21 moji = ThisWorkbook.Worksheets("Sheet1").Cells (i, 1).Value word = ThisWorkbook.Worksheets("Sheet2").Cells (j, 2).Value result = InStr(moji, word) If doResult <> 0 Then For k = 1 To 100 ThisWorkbook.Worksheets("Sheet3").Cells (k, 1).Value= moji Next k End If Next j Next i このソースでは上手くいかないのですが、どこがダメなのか分からないので、解決の糸口がつかめません。 アドバイスなどお願いします。

  • 【VBA】【複数ファイルの読み込み】

    23歳OLです。 会社でマクロを組むことになったのですが、 どうしてもわからないところがあったので質問させていただきます。 ご回答いただけると嬉しいです。。 ============================ ▼問題点 問題(1) Line input にしているのですが、 一行ずつ入力されず、読み込んだファイルが一つのセルの中にすべて入ってしまいます。 問題(2) 複数ファイルを1、2、3、と読み込んだ際A列,B列,C列と違う列に 入って行ってほしいのですが現在同じ列に入ってしまいます。 どうやったら改善できるのでしょうか? 以上です。 よろしくお願いします。 ※読み込みたいファイルはlogファイルとvファイルです。※ ==========該当マクロ============== ■VBAコード Sub ReadMultiFiles() ' [[ 変数定義 ]] Dim varFileName As Variant Dim VWorkSheet As Worksheet Dim NewWorkSheet As Worksheet Dim SheetName As String Dim Filename As Variant ' [[ ファイルパスからファイル名を取得 ]] SheetName = Dir(ThisWorkbook.FullName) ' [[ ファイル名で新しいシート作成 ]] Set NewWorkSheet = CreateWorkSheet(SheetName) ' [[ 複数ファイルパス名を取得 ]] varFileName = Application.GetOpenFilename(FileFilter:="(*.*),*.*", _ Title:="CSVファイルの選択", MultiSelect:=True) ' [[ ファイルパス取得できなかったら ]] If IsArray(varFileName) = False Then Exit Sub End If ' [[ ファイルパス取得できたら ]] For Each Filename In varFileName   ' [[ CSVファイルを開く ]]   Dim buf As String, n As Long   Open Filename For Input As #1   Do Until EOF(1)   Line Input #1, buf   n = n + 1   Cells(n, 1) = buf   Loop      ' [[ CSVファイルを閉じる(保存無し) ]]   Close #1 Next Filename End Sub ' [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] ' [[ ]] ' [[ ワークシート名を指定したワークシートの作成 ]] ' [[ ]] ' [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] Function CreateWorkSheet(WorkSheetName As String) As Worksheet ' 変数定義 Dim NewWorkSheet As Worksheet Dim iCheckSameName As Integer ' ワークシートの作成 ' ※一番最後に挿入 Set NewWorkSheet = Worksheets.Add(After:=Worksheets(Worksheets.Count)) ' 同じ名前ワークシートが無いか確認 iCheckSameName = 0 For Each WS In Sheets If WS.Name = WorkSheetName Then MsgBox "ワークシート名:" + WorkSheetName + " この名前は既に使われています。" iCheckSameName = 1 End If Next '同じ名前のワークシートがなければ If iCheckSameName = 0 Then NewWorkSheet.Name = WorkSheetName Set CreateWorkSheet = NewWorkSheet End If End Function ==========================

  • VBAにてリストボックスに表示された文字をエクセルのセルにコピペするには

    先日、ここで教えてもらった以下の内容で、幾つかのテキストボックスに表示された内容のうち、電話番号をエクセルのセルに転記する方法が、上手くいきません。”検索"名のシート上で実行します。 過去のログを参考にしましたが、解決できませんでした。 またお世話になりますが、だれか教えてください。 Private Sub CommandButton1_Click() Dim Namae As String Dim MeNamae As UserForm Dim ken As String Namae = TextBox1.Text Set MeNamae = UserForm1 Call 検索(Namae, MeNamae) End Sub Public Sub 検索(ByVal Namae As String, ByRef MeNamae As UserForm) Dim Nagasa As Integer Dim i As Long Dim MaxRows As Long Dim kensaku As Worksheet Dim KensakuChar As String Dim ListNamae As String Dim ListChar As String Dim KBanme As Integer Dim LBanme As Integer Set kensaku = Worksheets("顧客データ") MaxRows = kensaku.UsedRange.Rows.Count Nagasa = Len(Namae) MeNamae.ListBox1.Clear For i = 3 To MaxRows ListNamae = kensaku.Cells(i, 3) KBanme = 0 LBanme = 0 Do Do While Nagasa >= KBanme KBanme = KBanme + 1 KensakuChar = Mid(Namae, KBanme, 1) If KensakuChar <> " " Then Exit Do End If Loop Do While Nagasa >= LBanme LBanme = LBanme + 1 ListChar = Mid(ListNamae, LBanme, 1) If ListChar <> " " Then Exit Do End If Loop If KensakuChar = ListChar Then If Nagasa = KBanme Then With MeNamae .ListBox1.AddItem (ListNamae) .ListBox1.List(.ListBox1.ListCount - 1, 1) = i End With End If Else Exit Do End If Loop Until Nagasa <= KBanme Next End Sub Private Sub ListBox1_Click() Dim r As Long With ListBox1 If .ListIndex > -1 Then r = .List(.ListIndex, 1) '選択した名前の行 TextBox6.Value = Worksheets("顧客データ").Cells(r, 3) 'カタカナ名 TextBox2.Value = Worksheets("顧客データ").Cells(r, 5) '漢字名 TextBox3.Value = Worksheets("顧客データ").Cells(r, 7) '住所 TextBox4.Value = Worksheets("顧客データ").Cells(r, 1) '電話番号 TextBox5.Value = Worksheets("顧客データ").Cells(r, 2) '顧客番号 End If End With End Sub Private Sub CommandButton3_Click() 'クリックすると  Worksheets("検索").Cells(, 2) ’このシートの(G2)に上記の電話番号が入力される End Sub

専門家に質問してみよう