Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


1824 / 13645 ツリー ←次へ | 前へ→

【71700】なぜでしょうか 12/3/31(土) 11:26 質問[未読]
【71704】Re:なぜでしょうか UO3 12/3/31(土) 16:01 回答[未読]
【71708】Re:なぜでしょうか 12/4/1(日) 6:29 お礼[未読]
【71710】Re:なぜでしょうか UO3 12/4/1(日) 7:39 発言[未読]
【71711】Re:なぜでしょうか 12/4/1(日) 8:07 お礼[未読]

【71700】なぜでしょうか
質問    - 12/3/31(土) 11:26 -

引用なし
パスワード
   セル”A1”に値を入力したとき、セル”B1”が空なら
セル”B1”にセル”A1”の値を出力させるつもりで、
下記のステートメントを作成しました。
実行すると、”B1”と”A2”の2箇所に出力されてしまいます。
なぜでしょうか、また、どのように訂正すれば宜しいのでしょうか。

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
  Target = Range("A1")
    If IsEmpty(Range("B1")) Then
    Range("B1") = Target

   End If
End Sub

【71704】Re:なぜでしょうか
回答  UO3  - 12/3/31(土) 16:01 -

引用なし
パスワード
   ▼隼 さん:

こんにちは

アップされたコードを解説しますね。
(隼さんのエクセルの設定が標準設定のまま、エンターキーの
 後カーソルが下に行くようになっているという前提で)

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

まず、、これは、「入力されたとき」ではなく「選択されたセルの場所が変わったとき」に発生します。
つまり、A1に入力してエンター。するとカーソルはA2にきますね。この時に動きます。
ですから、この時の Target は A2 になっています。

  Target = Range("A1")

このコードは、省略しないで書くと
Target.Value = Range("A1").Value ということなんです。
で、TargetはA2になっていますので、
Range("A2").Value = Range("A1").Value と同じことになります。
これで、A1の値がA2に記入されるわけがおわかりですね?

で、その後
If IsEmpty(Range("B1")) Then
  Range("B1") = Target
End If

がありますので、B1が空白の場合、B1にも書かれるというわけです。

SelectionChange のコードをすべて削除して以下にしてください。

Private Sub Worksheet_Change(ByVal Target As Range)
  'A1に入力された場合のみ対応
  If Not Intersect(Target, Range("A1")) Is Nothing Then
    '以降の処理でシートに値が書き込まれたときにChangeイベントが
    '発生すると、また、このルーティンに連鎖して入ってくるので
    'それを抑止
    Application.EnableEvents = False
    If IsEmpty(Range("B1").Value) Then Range("B1").Value = Range("A1").Value
    'このプロシジャ内でのシートへの書き込みが終わったので
    'イベントの発生を再開する。
    Application.EnableEvents = True
  End If
End Sub

【71708】Re:なぜでしょうか
お礼    - 12/4/1(日) 6:29 -

引用なし
パスワード
   ▼UO3 さん:
解説、回答をありがとうございます。

'以降の処理でシートに値が書き込まれたときにChangeイベントが
'発生すると、また、このルーティンに連鎖して入ってくるので
'それを抑止

というのは
Range("B1").Value = Range("A1").Value
が実行されたとき、Changeイベントが起きた→
Range("A1")に戻る→Range("A1")は既に入力済み→
Range("B1")は空ではないので何もしない
ということを抑止する、ということですか。


>▼隼 さん:
>
>こんにちは
>
>アップされたコードを解説しますね。
>(隼さんのエクセルの設定が標準設定のまま、エンターキーの
> 後カーソルが下に行くようになっているという前提で)
>
>Private Sub Worksheet_SelectionChange(ByVal Target As Range)
>
>まず、、これは、「入力されたとき」ではなく「選択されたセルの場所が変わったとき」に発生します。
>つまり、A1に入力してエンター。するとカーソルはA2にきますね。この時に動きます。
>ですから、この時の Target は A2 になっています。
>
>  Target = Range("A1")
>
>このコードは、省略しないで書くと
>Target.Value = Range("A1").Value ということなんです。
>で、TargetはA2になっていますので、
>Range("A2").Value = Range("A1").Value と同じことになります。
>これで、A1の値がA2に記入されるわけがおわかりですね?
>
>で、その後
>If IsEmpty(Range("B1")) Then
>  Range("B1") = Target
>End If
>
>がありますので、B1が空白の場合、B1にも書かれるというわけです。
>
>SelectionChange のコードをすべて削除して以下にしてください。
>
>Private Sub Worksheet_Change(ByVal Target As Range)
>  'A1に入力された場合のみ対応
>  If Not Intersect(Target, Range("A1")) Is Nothing Then
>    '以降の処理でシートに値が書き込まれたときにChangeイベントが
>    '発生すると、また、このルーティンに連鎖して入ってくるので
>    'それを抑止
>    Application.EnableEvents = False
>    If IsEmpty(Range("B1").Value) Then Range("B1").Value = Range("A1").Value
>    'このプロシジャ内でのシートへの書き込みが終わったので
>    'イベントの発生を再開する。
>    Application.EnableEvents = True
>  End If
>End Sub

【71710】Re:なぜでしょうか
発言  UO3  - 12/4/1(日) 7:39 -

引用なし
パスワード
   ▼隼 さん:

おはようございます

実は、今回、差し上げたコードでは、
Application.EnableEvents = False
Application.EnableEvents = True
この処理はしなくても(たまたま)OKです。
ただ、以下に説明しますが、Worksheet_Change を使う場合は、
「お約束」のような感じで、処理前に False、処理後に「必ず」True にするような
コードを書くことを、強く強く推奨します。


Private Sub Worksheet_Change(ByVal Target As Range)

  さまざまな処理1
  さまざまな処理2

  ★シート状のセルの値の変更

  さまざまな処理3
  さまざまな処理4

End Sub

こんなコードだとします。
そうしますと、★のコードを実行したとたんに、またChangeイベントが発生し
VBAは、その下の、さまざまな処理3 を実行する前に、変更されたセルを対象にして、
「新たに」このWorksheet_Changeに入ってきます。
で、また★を実行して、「新たに」・・

永久に、さまざまな処理3 にはいかず、さまざまな処理1 〜 ★ の間を
ぐるぐる回り続けます。これをイベントの連鎖といいます。
これを回避するために、★の実行前に、エクセルによるイベントの検知機能を止め
★が終わった後、イベント検知機能を復活させます。

注意しなければいけないのは、さまざまな処理3 以降で、エラーで中断したり
あるいは、ロジックの不備で、Application.EnableEvents = True が実行されなかった場合。
もう、エクセルは、ずっとイベント検知をしないままですので、そのあとセルを変更しても
うんともすんとも言わなくなります。

このような状態になった場合、
・エクセルを終了して、再度立ち上げると復旧します。
・Application.EnableEvents = True を実行します。
 これは、この1行だけの臨時のマクロを標準モジュールに書いて実行させてもいいですし
 あるいはVBE画面で、表示->イミディエイトウィンドウ で下のほうにでてくるウィンドウで
 Application.EnableEvents = True とタイプしてエンターしても復旧します。

【71711】Re:なぜでしょうか
お礼    - 12/4/1(日) 8:07 -

引用なし
パスワード
   ▼UO3 さん:
分かりやすい解説を、ありがとうございます。
感謝いたします。
>▼隼 さん:
>
>おはようございます
>
>実は、今回、差し上げたコードでは、
>Application.EnableEvents = False
>Application.EnableEvents = True
>この処理はしなくても(たまたま)OKです。
>ただ、以下に説明しますが、Worksheet_Change を使う場合は、
>「お約束」のような感じで、処理前に False、処理後に「必ず」True にするような
>コードを書くことを、強く強く推奨します。
>
>
>Private Sub Worksheet_Change(ByVal Target As Range)
>
>  さまざまな処理1
>  さまざまな処理2
>
>  ★シート状のセルの値の変更
>
>  さまざまな処理3
>  さまざまな処理4
>
>End Sub
>
>こんなコードだとします。
>そうしますと、★のコードを実行したとたんに、またChangeイベントが発生し
>VBAは、その下の、さまざまな処理3 を実行する前に、変更されたセルを対象にして、
>「新たに」このWorksheet_Changeに入ってきます。
>で、また★を実行して、「新たに」・・
>
>永久に、さまざまな処理3 にはいかず、さまざまな処理1 〜 ★ の間を
>ぐるぐる回り続けます。これをイベントの連鎖といいます。
>これを回避するために、★の実行前に、エクセルによるイベントの検知機能を止め
>★が終わった後、イベント検知機能を復活させます。
>
>注意しなければいけないのは、さまざまな処理3 以降で、エラーで中断したり
>あるいは、ロジックの不備で、Application.EnableEvents = True が実行されなかった場合。
>もう、エクセルは、ずっとイベント検知をしないままですので、そのあとセルを変更しても
>うんともすんとも言わなくなります。
>
>このような状態になった場合、
>・エクセルを終了して、再度立ち上げると復旧します。
>・Application.EnableEvents = True を実行します。
> これは、この1行だけの臨時のマクロを標準モジュールに書いて実行させてもいいですし
> あるいはVBE画面で、表示->イミディエイトウィンドウ で下のほうにでてくるウィンドウで
> Application.EnableEvents = True とタイプしてエンターしても復旧します。

1824 / 13645 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free