• 締切済み

ForEach...文でRows(1)を指定エラー

For Each element In group ...Next ステート文で、group に Rows(1) を指定し、セルのValueプロパティを取得しようとするとエラー「型が一致しない」が出る。指定した範囲内の1行目のセルの値を確認しようと以下のマクロを作り、実行するとエラーが出る。その理由をどなたか教えてください。 Sub testA() Dim r0 As Range Dim r1 As Range Dim cr As Range Dim i As Integer Dim result as Boolean Set r0 = Worksheets("Sheet1”).Range("B4:D5") Set r1 = r0.Rows(1) For Each cr In r1 Debug.Print cr.Value ‘*** (0) エラー発生 Next cr ‘*** 以下はうまくいく。 For Each cr In r1 Debug.Print cr.row ‘*** (1) Debug.Print cr.Column ‘*** (2) Next cr result = TypeOf r1 Is Range  ‘*** (3) Debug.Print result ‘*** True ‘*** 確認したいことをFor Each … Next を使わないで, ‘*** セルを相対位置で指定すればうまくいく。 For i = 1 to r1.Columns.count Debug.Print r1.Cells(1, i).row Debug.Print r1.Cells(1, i).Column Debug.Print r1.Cells(1, i).Value ‘*** エラーなし Next i End Sub よく分からないのは(1)(2)(3) なのに なぜ Value プロパティ取得で(0)「型が一致しない(実行時エラー’13’)」になるところです。環境はExcel 2013, Windows 10です。 よろしくお願いします。

みんなの回答

回答No.2

こんにちは。 お望みの結果を得るには、 目的によって違うので、3例、 ' ///   Set r0 = Worksheets("Sheet1").Range("B4:D5")   Set r1 = r0.Rows(1)   For Each cr In r1.Cells ' ←★     Debug.Print cr.Row; "-"; cr.Column, cr.Value   Next cr ' /// または、 ' ///   Set r0 = Worksheets("Sheet1").Range("B4:D5")   Set r1 = r0.Rows(1).Cells ' ←★   For Each cr In r1     Debug.Print cr.Row; "-"; cr.Column, cr.Value   Next cr ' /// 場合によっては、 ' ///   Set r0 = Worksheets("Sheet1").Range("B4:D5")   Set r1 = Application.Intersect(r0, r0.Rows(1)) ' ←★   For Each cr In r1     Debug.Print cr.Row; "-"; cr.Column, cr.Value   Next cr ' /// などのように、 'Rows態'のRangeオブジェクトに含まれるすべての行   をループさせるのではなく、 'Rows態'のRangeオブジェクトに含まれるすべてのセル   をループさせます。 > Set r0 = Worksheets("Sheet1”).Range("B4:D5") > Set r1 = r0.Rows(1) > For Each cr In r1 > Debug.Print cr.Value‘*** (0) エラー発生 > Next cr r1 には セル範囲の行範囲を表す 'Rows態'のRangeオブジェクト が格納されています。 > For Each cr In r1 cr の意味は 'Rows態'のRangeオブジェクト を 1行ずつ(毎)ループした セル範囲の行を表す Rangeオブジェクト が渡されます。 > Debug.Print cr.Value‘*** (0) エラー発生 cr.Value 自体は正しいプロパティの使い方ですが、 戻り値がVariant型配列です。 Variant型配列をそのまま Debug.Print することは出来ませんから、 「型が一致しない(実行時エラー’13’)」を返します。 > For Each cr In r1 range.Rows プロパティは、 application.Rows プロパティ や worksheet.Rows プロパティ と、 同じように、 戻り値としては、Range型で、中身はrange.Rowsです。 以下、[VBAヘルプ(Excel 開発者用リファレンス)]より |Range.Rows プロパティ |指定されたセル範囲の行を表す Range オブジェクトを返します。 以上引用。 Range型オブジェクトには、Cells、Rows、Columns、 様々な形態のオブジェクトが格納されます。 ※本回答では、説明し易くする為の便宜的な用語として  「'Rows態'のRangeオブジェクト」という造語を使っています。 ひとつのオブジェクト型に複数の携帯のオブジェクトやコレクションが格納されることは、 よくあることですが、 Range クラスでは、.Type プロパティのようにオブジェクトを特定する為の情報は、 用意されていません。 r1 に格納されたのは、'Cells態'のRangeオブジェクト なのか?を調べる必要がある場合には、 ' ///   If r1.Count = r1.Cells.Count Then     For Each cr In r1       Debug.Print cr.Row; "-"; cr.Column, cr.Value     Next cr   Else     For Each cr In r1.Cells       Debug.Print cr.Row; "-"; cr.Column, cr.Value     Next cr   End If ' /// などのように.Count と .Cells.Count を比較するのが簡単です。 因みに、Rows とか Row という名のコレクション(オブジェクト)はありませんが、 'Rows態'のRangeオブジェクトをループやItemで扱っていると、 あたかもRowsコレクションを操作しているような挙動を得られるけれど、 実体はRange オブジェクトだからこそ、 .Valueを始めとしたプロパティやメソッドを、そのまま使えることが殆どです。 行や列単位など、臨機応変に塊りを扱えるクラスとして重宝するのがRangeなのですが、 ご質問のケースのように、その多機能さがアダとなり時に解り難くなることもあるということです。 シンプルなアドバイスとして、  Rows、Columns、に対して総当たりループをする場合、  行や列単位の処理なのか、単セル単位の処理なのか、まずは確認。  単セル単位ならば、.Cells プロパティのことを思い出して。 という纏めになります。 > Debug.Print cr.row‘*** (1) > Debug.Print cr.Column‘*** (2) range.Row プロパティ、range.Column プロパティは、 rangeオブジェクトの形態に係らず、 range.Cells(1) や range.Areas(1).Cells(1) の 行/列インデックスを返しますから、エラーにはなりません。 > result = TypeOf r1 Is Range  ‘*** (3) r1 はRange型で指定しています。、 range.Rows プロパティの戻り値もRange型ですからNothingにはなりません。 従って、result = True です。 この手の判別に TypeOf を使うのは初めて見ました。  result = TypeName(r1) = "Range" とか、個人的には、既定のオブジェクト型については、 TypeName関数を使うことが殆どですが、 私には、評価できる素養がありませんので、この点はスルーでお願いします。 以上です。

EulerKnowsNo
質問者

お礼

Realbeatin さん ありがとうございました。 例示いただいた3例のうち1例目と2例目は理解できましたので、利用させていただきます。3例目については調べてみます。 反省 (1)Range オブジェクト についての理解が全く浅はかであることがわかりました。 「>'Rows態'のRangeオブジェクト」「>'Cells態'のRangeオブジェクト」について、理解できるかわかりませんが、調べてみます。 (2)「For each… 」文についても、group が Range であれば Cell 単位でループすると思い込んでいました。 後悔 For Each cr In r1 Debug.Print cr.row ‘*** (1) Debug.Print cr.Column ‘*** (2) Next cr を実行すれば、1回しかループしないので行単位であることに気がついたかも? 実際は(2)の後に(0)を付けて実行したので無理でした。 Debug.Print cr.Value ‘*** (0) エラー発生 (3)「TypOf」について オブジェクトの型について知りたいとネットで検索すると例があったので使いました(対象がRange ではなかったかも)。「 TypeName 」関数をしりませんでした。調べてみます。 詳しい説明をいただき大変参考になりました。 いろいろ勉強になります。 本当にありがとうございました。

  • okormazd
  • ベストアンサー率50% (1224/2412)
回答No.1

Set r1 = r0.Rows(1) で、r1はr0の1行目の範囲をオブジェクトとするrowのコレクション(といってもこの場合は1つしかないが)になります。 For Each cr In r1 で、crはrowのオブジェクトを取り出すことになります。 Debug.Print cr.Value crはrowだからvalueプロパティはありません。ないものを表示させようとするから、エラーになるのです。 次のようにして確認してはいかがでしよう。 Set r1 = r0.Rows(1) For Each cr In r1 Debug.Print cr.row Next cr または、 Set r1 = r0.Rows For Each cr In r1 Debug.Print cr.row Next cr

EulerKnowsNo
質問者

お礼

Okormazd さん ありがとうございました。 「 For each item in group … Next」文について、誤解していました。 group が行タイプ(?)でも、その行内のセル単位でループすると思い込んでいました。 Rows, rowコレクション、For each … 文について調べてみます。 本当にありがとうございました。