- ベストアンサー
エクセルVBAで入力規則の列数を取得
- エクセル2013でワークシートのB列、C列、E列に入力規則が設定されています。しかし、マクロを実行するとColumns.Countが正しく返らない問題が発生します。
- B、C、D列に入力規則を設定した場合はColumns.Countが正しく返りますが、B、D、E列に入力規則を設定した場合はColumns.Countが1を返します。
- なぜこのような問題が発生するのでしょうか?
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
#1です。 お礼欄拝見しました。 > ただ、ではなぜ.Cells.Countは複数のセル領域のセル数を返すのかいまいちわかりませんが、セルが取得できるので > Rows(3).SpecialCells(xlCellTypeAllValidation).Cells.Count でも同じことですよね? 実際には、range.Cells プロパティを使う必要がないことはお解りなのですよね? Rows(3).SpecialCells(xlCellTypeAllValidation).Count ですので、range.Cells プロパティを使う意図次第で説明の仕方も変わります。 VBAのヘルプ他、適当な解説ドキュメンントが見当たりませんから、私の言葉ですが、 指定したセル範囲(range)のすべてのセル範囲を返すのが range.Cells プロパティ (但し、indexを指定せずにコレクションとして扱う場合のこと) なのです。 対して、 以下、VBAヘルプより引用(改行は筆者) |Range.Columns プロパティ | 指定されたセル範囲の列を表す Range オブジェクトを返します。 |備考 <中略> | 複数のセル範囲を含む Range オブジェクトに対してこのプロパティを使用すると、 | 選択範囲の中で最初に選択した領域の列が返されます。 | たとえば、Range オブジェクトに A1:B2 および C3:D4 の 2 つのセル範囲が含まれているとき、 | Selection.Columns.Count プロパティは 4 ではなく 2 を返します。 | 複数のセル範囲を選択している可能性があるときは、 | このプロパティを使用する前に Areas.Count を実行し、 | 範囲に複数の領域が含まれているかどうかを確認します。 | 複数の領域が含まれている場合は、セル範囲の領域ごとにループします。 (引用、以上。) 私の感覚では、「列の数」を問うのは、 単矩形範囲(ひとつの連続した四角いセル範囲)を対象にする場合、 に<通常は>限られていると思います。 私の感覚というよりも、そこは開発者の考え方であって、 ◆各々プロパティ毎に、 単矩形範囲を扱う(.Columns)か、 複数セル範囲のすべてを扱う(.Cells)か、 複数セル範囲に対してはエラーを返すか に分かれているいるのが現実で、 ユーザー側は、それらをひとつひとつ確認しながら、 使い分けていくしかないのでは、と、あくまでも受け身な感覚な訳です。◆ 足りないものがあれば自分で作ればいいですし、、、。 少し、考えておきたいのは、、、。 セルの数、は「(重複を含めた)セルの総数」という簡単な定義で済みますが、 列の数、というのは、定義するの難しいですね。 重複を含めるべきか?否か? 例えば、Range("B2:C2,C4:E4")の列数は、5なのか?4なのか? <もしも>開発者の立場で作るとしたら、という<仮想の話>として、 range.ColumnsCountGross プロパティ 重複を含む range.ColumnsCountNet プロパティ 重複を含まない みたいに、rangeクラスのプロパティとして、2種類作るなら、 作ってみようかな?とか思い至っても、 いや却ってユーザーは混乱するだろうな、とか、 考えた末に、結局やめちゃうでしょうね。 必要ならユーザー定義関数でも作ればいいし、とか。 Columns クラスのCount プロパティは、 これは、他に考えようもなく、そもそもColumns自体が必ず単矩形範囲な訳ですから、 列の数を返すのは単純な定義で済みます。 答えになっているかどうか解りませんが、 今の処、#1での質問にお応え出来るのは、これぐらいです。 あとは、なぜ列の数なのか、なぜCellsを挟むのか、 ご自分の中の実際のニーズに照らして、必要かどうか取捨して整理してみてください、
その他の回答 (1)
- real beatin(@realbeatin)
- ベストアンサー率82% (174/211)
こんにちは。 ご提示の記述で実行されている内容を、 現象から捉え直して簡単に書くと、 以下のようになります。 Sub test01_0() MsgBox Range("B3,D3:E3").Columns.Count End Sub これでは、 Range("B3,D3:E3") の .Areas(1) すなわち Range("B3") の 列数を問い合わせていることになりますから、 戻り値は、1で正解です。 複数領域を持つセル範囲については、 .Areas プロパティでAreas コレクションのArea オブジェクトを 総当たりしてあげないとなりません。 上を書換えるなら、以下のような感じ。 Sub Re8915560_0() Dim a As Range Dim cnCol As Long With Range("B3,D3:E3") For Each a In .Areas cnCol = cnCol + a.Count Next MsgBox .Cells.Count MsgBox cnCol End With End Sub 今回の例では、偶々、1行に限定された範囲ですから、 要点を明確にする為、重複する列が無い前提の記述です。 以上の説明を踏まえて、ご提示の記述を書き直すと、 以下のようになります。 Sub Re8915560() Dim Target As Range On Error Resume Next Set Target = Rows(3).Cells.SpecialCells(xlCellTypeAllValidation) On Error GoTo 0 If Target Is Nothing Then Exit Sub Dim a As Range Dim cnCol As Long With Target For Each a In .Areas cnCol = cnCol + a.Count Next MsgBox .Cells.Count MsgBox cnCol End With End Sub 実際の必要に合わせて、工夫は必要でしょうけれど、 .Areas プロパティに目が向けば、今回の疑問は解消されるでしょう。 以上です。
お礼
ありがとうございます。 複数のセル領域の場合、最初の領域だけしか行や列を取得できないということですね。 ご教示の「Areas プロパティ」を検索したら http://www.moug.net/tech/exvba/0050055.html がヒットしてよく分かりました。 ただ、ではなぜ.Cells.Countは複数のセル領域のセル数を返すのかいまいちわかりませんが、セルが取得できるので Rows(3).SpecialCells(xlCellTypeAllValidation).Cells.Count でも同じことですよね? ありがとうございました。
お礼
> Rows(3).SpecialCells(xlCellTypeAllValidation).Count > ですので、 あれまあ.Cells.Countしなくとも直接、Rows(3)に入力規則がある列がこれで取得できたのですね。知りませんでした。 ありがとうございます。