[[20160316123249]] 『Worksheet_Changeイベントが2回呼び出されてしまax(しごとにん) ページの最後に飛ぶ

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

 

『Worksheet_Changeイベントが2回呼び出されてしまう?』(しごとにん)

行コピー後、コピー先の行選択し右クリックから「コピーしたセルの挿入」を行うと
Worksheet_Changeイベントが2回呼び出されてしまうようなのですが、
回避方法はないのでしょうか。

例えば、下記の場合、MsgBoxが2回表示されてしまいます。
1回表示としたいのですが。。

Private Sub Worksheet_Change(ByVal Target As Range)
  MsgBox "テスト", vbInformation
End Sub

< 使用 Excel:Excel2013、使用 OS:Windows7 >


 質問文をよく読まないままコメントしました。
 いったんコメントを消去します。

(β) 2016/03/16(水) 12:45


追記

A.特定の列を含む行の挿入(行単位でのコピぺ含む)が行われた場合、挿入先の特定の列の値をクリア(この列はコピーしたくない)
B.特定の列を含む行の削除が行われた場合、何もしない
C.行の挿入ではなく、セル単位で編集が行われた場合、何もしない

という処理を行いたいのですが、

A.B.について、挿入・削除の判別方法がわからなかったので、MsgBoxで「クリアしてもよいか?」選択させようと考えたのですが、
上記の問題に遭遇してしてしまいました。。

(しごとにん) 2016/03/16(水) 13:02


ホントですねぇ。Excel2010でも、同様にイベントが2回発生してしまいますね。
対策ですが、共通変数を用意しておき、イベント発生時に1にすると同時に、0に戻すような処理をOnTimeで起動しておく、とか?

【シートモジュール】

 Private Sub Worksheet_Change(ByVal Target As Range)
    If iFlag = 0 Then
        iFlag = 1
        Application.OnTime Now, "sReset"
        MsgBox "テスト", vbInformation
    End If
 End Sub

【標準モジュール】

 Public iFlag As Long

 Public Sub sReset()
    iFlag = 0
 End Sub
(???) 2016/03/16(水) 13:13

 なるほど、そうですね。
 右クリックでのコピーしたセルの挿入の挙動は以下ですね。

 1.行を挿入。
 2.コピー内容の書き込み。

 であれば、Changeイベントが2回発生するのは、あぁ、そうだなぁということなんですが
 ステップ実行で調べますと、1.のイベント時、すでに挿入された行には値が書きこまれているんですね。
 なので、それで終わるはずですけど、なぜか、もう一度、同じ Targetで同じ値を持ってイベントが連鎖。
 いわゆるChangeイベントプロシジャ内でのセル変更によるイベント連鎖ではないので、う〜ん・・難問かも。

 識者さんからのアドバイスを待ちましょう。
 (自分でも、もう少し、追いかけてみます。)

(β) 2016/03/16(水) 13:21


 Sub Macro1()
    Rows("1:1").Select
    Selection.Copy
    Application.CutCopyMode = False '★追加すると1回表示になる。
    Rows("10:10").Select
    Selection.Insert
 End Sub
(マリオ) 2016/03/16(水) 13:40

 行挿入を、「Worksheet_Change」として取り扱わないように処理すれば、いいいんですかね?
(マリオ) 2016/03/16(水) 13:59

早々にたくさんのご回答ありがとうございます。

どちらかを無効化するしかないのですね。

マリオさん
>行挿入を、「Worksheet_Change」として取り扱わないように処理すれば、いいいんですかね?

みなさんのアドバイスを見る限り、
これができれば、解決できそうですが、、
(しごとにん) 2016/03/16(水) 14:13


 無理やりだけど、これで挿入のときに一回だけにならない??
    Option Explicit

    Dim LastRow As Long
    Dim InFlg As Boolean

    Private Sub Worksheet_Change(ByVal Target As Range)
        If InFlg Then
            InFlg = False
        Else
            If UsedRange.Rows.Count < LastRow Then
                Debug.Print "削除"
            ElseIf UsedRange.Rows.Count > LastRow Then
                InFlg = True
                Debug.Print "挿入"
            End If
        End If
    End Sub

    Private Sub Worksheet_SelectionChange(ByVal Target As Range)
        LastRow = Me.UsedRange.Rows.Count
    End Sub
(稲葉) 2016/03/16(水) 14:17

 ん〜稲葉さんのを参考にして、次のようにすると、行挿入を、「Worksheet_Change」として
 取り扱わないけど、
【行コピー後、コピー先の行選択し右クリックから「コピーしたセルの挿入」】で
 一度もMsgBoxが表示されない(+_+)

  Dim LastRow As Long

    Private Sub Worksheet_Change(ByVal Target As Range)
        If UsedRange.Rows.Count <> LastRow Then Exit Sub
        MsgBox "テスト", vbInformation
    End Sub
    Private Sub Worksheet_SelectionChange(ByVal Target As Range)
        LastRow = Me.UsedRange.Rows.Count
    End Sub
(マリオ) 2016/03/16(水) 14:30

>A.B.について、挿入・削除の判別方法がわからなかったので、MsgBoxで「クリアしてもよいか?」選択させようと考えたのですが、

稲葉さんにコメントいただいたものを参考に、挿入・削除の判定ができそうなので、
こちらは解決しそうです。

Ctrl+vなどで行単位でコピペした場合は、行挿入が発生しないので、
Flagでの制御は難しそうですね。。。

試技していませんが、
Flg制御の代わりに、Worksheet_Changeの最後に、LastRow = UsedRange.Rows.Countを追加してやれば、
2度呼ばれた場合の2度目は無視されるのではと予想しました。

これから、試します・・
(しごとにん) 2016/03/16(水) 14:53


 >Ctrl+vなどで行単位でコピペした場合は、行挿入が発生しないので、 
 >Flagでの制御は難しそうですね。。。 
 その場合は、Ifの最後にElseをもうけて、Targetで処理すればよいのでは??
(稲葉) 2016/03/16(水) 14:59

稲葉さんおっしゃるとおり、分岐追加することで対応できました。
ありがとうございます。

>Worksheet_Changeの最後に、LastRow = UsedRange.Rows.Countを追加
こちらも予想通りでした。

みなさまのおかげでなんとか先に進めそうです。
ありがとうございました!!!
(しごとにん) 2016/03/16(水) 15:32


コメント返信:

[ 一覧(最新更新順) ]


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