[[20121018085534]] 『VBAでRange( )の中でCellsを使う場合』(tora)  ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『VBAでRange( )の中でCellsを使う場合』(tora)

 例を挙げたほうが早いのでいきなりコードを書きます。

 Sub test()
    Dim n As Integer
    Dim m As Integer    
    n = 1
    m = 5

    Sheets("Sheet1").Range("A1:D5").ClearContents
    Sheets("Sheet1").Range("A" & n & ":D" & m).ClearContents
    Sheets("Sheet1").Cells(n, m).ClearContents
    Sheets("Sheet1").Range(Cells(1, n), Cells(5, m)).ClearContents           'A
    Sheets("Sheet1").Select
    Range(Cells(1, n), Cells(5, m)).ClearContents

 End Sub

 これは単純にシートのある範囲のデータを消去するマクロですが、
 Sheet1がアクティブになっていないときに実行すると'Aのところでエラーとなります。
 同じようでもそのほかの書き方ではエラーにはなりません。

 ということは、Aの書き方は間違いであり、

 Range("A" & n & ":D" & m)            と 
 Range(Cells(1, n), Cells(5, m))       は同じように使えない場合がある

 という事になるようですが、そのあたりの原理を教えていただけないでしょうか。

 VBAに詳しい方には常識かもしれませんが、なぜそうなるのか私にはわかりません。
 過去にも同じコードがエラーになったりならなかったりしたことがあり不思議に思った事がありますが、、
 これと同じ事だったのかもしれません。

 この際、範囲の指定方法について正しい知識を得たいと思い質問しました。

 このテーマはつきつめていくと、奥が深いので、どんどん難しくなるんだけど、それはパスして。

 Range(・・・) の ・・・には
 1.文字列が入るケース
   Range("A1") とか Range("Sheet2!A5") とか。
   この場合、VBAは文字列を解釈して場所を特定する。
   Range("A1") というように「シート情報」が、どこにも記述されていない場合は、
   標準モジュールならアクティブシート、シートモジュールなら、そのシートと理解しておけば(90%ぐらいは)OK。
 2.Sheet("Sheet1").Range という書き方をすると、このRangeは"Sheet1"の領域を規定するんだと宣言されたことになる。
   で、Range( ) の中がRange("A1") といった文字列の場合、この文字列はRangeの前に修飾されていた"Sheet1"だと見なす。
   ただし、Sheets("Sheet1").Range("Sheet2!A5") といった書き方だと、Sheet1だといっているのに、その場所の指定として
   Sheet2はないだろ!! ということでVBAからしかられてしまう。

 ★わかりにくいかもしれないけど、Rangeだから、Cellsだからということではなく
  シート.Range(セルオブジェクトによる規定)の場合は、「セルオブジェクトの規定」部分は、シート.で宣言したシートであることが必要。
  Sheets("Sheet1").Range(Cells(1, n), Cells(5, m)) の場合、( ) の中の Cellsに、どのシートのセルなのかの 規定がないので、
 1.でコメントしたように、VBAがどのシートのセルのことなのかを「勝手に」解釈してしまう。
 だから、記述されたコードのモジュールがどこなのかによって解釈されたシートが"Sheet1"ではなかった場合、エラーになる。
 ★繰り返しになるけど、これは( ) の中が Rangeであっても同様。
 くだんのコードをこの形で書くなら
 Sheets("Sheet1").Range(Sheets("Sheet1").Cells(1, n), Sheets("Sheet1").Cells(5, m))

 (ぶらっと)

 > Sheet1がアクティブになっていないときに実行すると'Aのところでエラーとなります。

 Range/Cells Objectは、その親Objectを指定しない限りActiveSheetが指定されます。(Default)
 又、Sheet Moduleに書かれた場合は書かれたmoduleのSheetが親Objectになります。
 なので、Sheets("Sheet1").Range(Cells(1, n), Cells(5, m)).ClearContents
 はSheet1がActiveではない時、Sheetを跨いで範囲指定できないのでエラーになります。
 (seiya)

 ぶらっとさん、seiyaさん、どうもありがとうございました。
 8割くらいはわかったような気がします。

 あと一つお聞きしたいのは、ぶらっとさんが最後に書いてくださった
 Sheets("Sheet1").Range(Sheets("Sheet1").Cells(1, n), Sheets("Sheet1").Cells(5, m))

 は、最初のSheets("Sheet1").を省略して

 Range(Sheets("Sheet1").Cells(1, n), Sheets("Sheet1").Cells(5, m))

 としてもよいのでしょうか。(テストしてみると正常に動くようですが)
 (tora)


 >(テストしてみると正常に動くようですが)

 ちょっと前、他所の掲示板で同じようなことが話題に上っています。

 【2列を1つの列にめとめて、変更】
http://excelfactory.net/excelboard/excelvba/excel.cgi?mode=all&namber=154746&rev=0

 ※トピックから少し離れたところで議論されています。
  回答者にも勘違いが入っていたりで、カレンダーさんが必死に軌道修正しています。

 (半平太) 2012/10/18 12:06

 半平太さんのご紹介のトピで、私の存じ寄りの人間も勘違いレスをアップしているけど、カレンダーさんがおっしゃっていることが正解。

 これを受けて、また別の板だけど、
http://www.moug.net/faq/viewtopic.php?t=64202
 ここでも、かなりつっこんだ解説がなされているので興味があればどうぞ。

 結論から言えば

 >Range(Sheets("Sheet1").Cells(1, n), Sheets("Sheet1").Cells(5, m))

 これはOK。
 ( ) の中にシート規定があって、( ) の外にシート規定がない場合は、 ( ) の外の意味は
 ( ) の中で規定されたシートの領域 という意味に(結果的に)なる。

 ただ、自分としては、 ( ) の外のRange にもシートを明示する方が、「気持ちが落ち着く」ような気がする。

 (ぶらっと)

 半平太さん、ぶらっとさん、どうもありがとうございます。

 Range(Sheets("Sheet1").Cells(1, n), Sheets("Sheet1").Cells(5, m))

 はOKだが、ぶらっとさんとしては

 Sheets("Sheet1").Range(Sheets("Sheet1").Cells(1, n), Sheets("Sheet1").Cells(5, m))

 のほうが、「気持ちが落ち着く」ということですね。
 では、半平太さんが紹介しているサイトにありました、

 Application.Range(Sheets("Sheet1").Cells(1, n), Sheets("Sheet1").Cells(5, m))

 という書き方についてはどのように思いますか。

 初心者としては、Range(  ) の外にSheets("Sheet1")をつけるのもなんとなく冗長なような気もしますし
 かといって省略するのも「気持ちが落ち着」かないとか、美しくないというのもわかります。

 Application. をつけて問題なければ何とかの一つ覚えではないですけど
 いつでも使えて便利なようにも思いますが、いかがでしょうか。
 (tora)


 >初心者としては、Range(  ) の外にSheets("Sheet1")をつけるのもなんとなく冗長なような気もしますし
 >かといって省略するのも「気持ちが落ち着」かないとか、美しくないというのもわかります。

 こういう時は、皆さんWithステートメントを使うのではないでしょうか。

 With Sheets("Sheet1")
    .Range(.Cells(1, n), .Cells(5, m)).ClearContents  
 End With
 
(純丸)(o^-')b

 Withを使う方法、とてもすっきりしますね。
 純丸さん、どうもありがとうございました。
 (tota)


 >こういう時は、皆さんWithステートメントを使うのではないでしょうか。

 自分自身のコードを書くときは、私もWith派。時々、短い変数名(sh とか)を用意して sh. と修飾させることもあるけど。

 >Application.Range・・・・・ という書き方についてはどのように思いますか

 私の誤解でなければ、シート修飾なしのRange(シート修飾したRangeやCellsによる複数の領域規定) は
 Application.Range(シート修飾したRangeやCellsによる複数の領域規定) と、同値なのでこれは好み。
 当方が言ったのは、個人の好みとして、シート修飾なしのRange( ) というのは自分としては「すわりがわるい気持ち」で
 「なんだか頼りないというか、心細い印象」といった程度。

 Application.Range について興味があれば、私が紹介した、
http://www.moug.net/faq/viewtopic.php?t=64202

 この中の 投稿日時: 12/09/12 00:25:48 投稿者: ろひ あたりからのレスを皮切りにしてディスカッションがある。
 なんだか、わかるようでわからないという論調でもあるけど・・・・。

 (ぶらっと)

 ぶらっとさん、ありがとうございます。
 ご紹介いただいたリンクの議論は、私にはちょっと難しすぎるようです。

 純丸さんのWhihを使う方法も非常にすっきりしているのですが、
 うっかり屋の私としては、.Range( の次の .Cell の「.」をうっかり忘れそうです。

 今回は、Application.Range・・・・を使って作業を進める事とします。
 (とはいいながらもWith案も捨てがたい・・・と悩みつつ)

 ご回答いただきました皆様に、改めて感謝申し上げます。
 (sato)

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.