こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

エクセルVBAで無限ループ

教えてください。
以下の2つのエクセルマクロはまったく同じことをさせようとしているのですが、test02の方は.Offset(1).Activateが働かないのか、無限ループに陥ってしまいます。
単にActiveCell.という記述をWith~End Withでまとめただけなのになぜこうなるのでしょうか?

Sub test01()
ActiveSheet.Cells(1, 1).Activate
Do While ActiveCell.Value <> ""
If Not IsNumeric(ActiveCell.Value) Then
ActiveCell.Offset(0, 1).Value = "文字"
ElseIf ActiveCell.Value > 0 Then
ActiveCell.Offset(0, 1).Value = "正数"
ElseIf ActiveCell.Value < 0 Then
ActiveCell.Offset(0, 1).Value = "負数"
Else
ActiveCell.Offset(0, 1).Value = "その他"
End If
ActiveCell.Offset(1).Activate
i = i + 1
Application.StatusBar = i
Loop
End Sub

Sub test02()
ActiveSheet.Cells(1, 1).Activate
With ActiveCell
Do While .Value <> ""
If Not IsNumeric(.Value) Then
.Offset(0, 1).Value = "文字"
ElseIf .Value > 0 Then
.Offset(0, 1).Value = "正数"
ElseIf ActiveCell.Value < 0 Then
.Offset(0, 1).Value = "負数"
Else
.Offset(0, 1).Value = "その他"
End If
.Offset(1).Activate
i = i + 1
Application.StatusBar = i
Loop
End With
End Sub

投稿日時 - 2009-02-13 16:54:33

QNo.4714192

暇なときに回答ください

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

With ActiveCellの判断が、システムが行っていることと、質問者様が思っていることとで違いがあることが原因かと思われます。
(多分、With分実行時に決めている。)

以下の2例を実行してみると、ActiveCellがどのように判断されているかわかるのでは?

Sub test2()
For i = 1 To 5
 MsgBox (ActiveCell.Address)
 With ActiveCell
  .Offset(1).Activate
 End With
Next i
End Sub

Sub test1()
With ActiveCell
 For i = 1 To 5
  MsgBox (ActiveCell.Address)
  .Offset(1).Activate
 Next i
End With
End Sub

投稿日時 - 2009-02-13 17:13:42

お礼

ありがとうございました。
こうやってみるとよくわかりました。
本当のActiveCellは変わっていくのにWith ActiveCellの対象は変わりませんでした。

Sub test3()
With ActiveCell
For i = 1 To 5
MsgBox (ActiveCell.Address & "/" & .Address)
ActiveCell.Offset(1).Activate
Next i
End With
End Sub

投稿日時 - 2009-02-13 18:26:42

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(4)

ANo.4

「Sub test02()」 の場合、「With ActiveCell」 の後に、 Do ループを入れていて、そのループの中で 「Offset(1)」 を使って、 次の行を Active にしようとしていますが、頭の 「With ActiveCell」 は最初の 「Cells(1, 1).Activate」 を受けていますので、ループ内で何度 「.Offset(1).Activate」 を実施しても、Cells(1, 1) にたいして Offset(1) を行いますので、結局は、Cells(2, 1) を Active にするだけでそれ以下の行を Active にすることはできません。 それゆえに Cells(2, 1) が空セルでない限りループから脱出できません。 これが無限ループの原因です。

Sub test02() を F8 を使ってステップインしながら、セルの Active 状態を見てください。 Cells(2, 1) が Active になったままになっているのが分かります。

どうしても、With を使うのであれば、With と Do の行を入れ替えれば、正常に動きます。

Sub test02()
 Dim i As Integer

 ActiveSheet.Cells(1, 1).Activate

 Do While ActiveCell.Value <> ""
  With ActiveCell
   If Not IsNumeric(.Value) Then
    .Offset(0, 1).Value = "文字"

   ElseIf .Value > 0 Then
    .Offset(0, 1).Value = "正数"
   ElseIf ActiveCell.Value < 0 Then
    .Offset(0, 1).Value = "負数"
   Else
    .Offset(0, 1).Value = "その他"
   End If

   .Offset(1).Activate

   i = i + 1
   Application.StatusBar = i
  End With
 Loop
End Sub

投稿日時 - 2009-02-13 18:57:59

お礼

あるがとうございます。
仰せの通りでございます。

投稿日時 - 2009-02-14 17:27:17

これは初めて知った。

Option Explicit

'==========クラスモジュールClass1=============
'Option Explicit
'Public a As Integer
'============================================

'Once you have entered a With...End With,
'you cannot reassign object until you have passed the End With.
'ってそういう意味なんだ…

Sub fuga()

Dim x As Class1
Dim y As Class1

Set x = New Class1
Set y = New Class1

x.a = 5
y.a = 4

With x

MsgBox (.a) '5
Set x = y
MsgBox (.a) '5
MsgBox (x.a) '4

End With

End Sub

投稿日時 - 2009-02-13 17:09:20

お礼

ありがとうございます。
クラスモジュールってまったくわからないのでご教示のコードをはしらせることはできませんでしたが、

'Once you have entered a With...End With,
'you cannot reassign object until you have passed the End With.

って、要はWith...End With間でオブジェクトを再定義できないってことなんでしょうね。
勉強になりました。

投稿日時 - 2009-02-13 17:29:52

ANo.1

詳しいことは解りませんが、
With ActiveCell
にすると、その時点でのActiveCellだけが With ~ End With の対象になるんでしょうね。
つまり、動的には対応していないということですね。

だから、最初のループで
.Offset(1).Activate
の処理をして、実際のActiveCellは変わっても、With の対象は変わらない、ということじゃないでしょうか。

投稿日時 - 2009-02-13 17:04:51

お礼

ありがとうございます。
きっとそういうことなんでしょうね。
不思議です。

投稿日時 - 2009-02-13 17:26:37

あなたにオススメの質問