[[20200514105102]] 『Changeイベントを複数書けない』(初心者うに) ページの最後に飛ぶ

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

 

『Changeイベントを複数書けない』(初心者うに)

 VBA初心者です。
 いくつか「changeイベント+複数」で検索したスレッドを拝見したのですが、
 応用できず、アドバイスをお願いします。

 指定範囲に数字の入力があった場合、
 その計算結果が入っている別セルの値が4を下回っていたら
 それぞれ異なるメッセージボックスを表示させるのが目標です。
 その指定範囲が12か所あるので、各所に入力したタイミングで
 それぞれの計算結果に対して各メッセージボックスを出したいのですが、併記できません。

 ifで併記してみて、最初に記述した箇所以外は動かなかったコードです。

 Private Sub Worksheet_Change(ByVal Target As Range)

 If Intersect(Target, Range("D10:AH10")) Is Nothing Then Exit Sub
 If Range("AM10") < 4 Then
 MsgBox Range("B6").Value & "の" & ActiveSheet.Name & "の" & 
 Range("B10").Value & "が" _
 & vbCrLf & "4を下回っています。"
 End If

 If Intersect(Target, Range("D18:AH18")) Is Nothing Then Exit Sub
 If Range("AM18") < 4 Then
 MsgBox Range("B14").Value & "の" & ActiveSheet.Name & "の" & 
 Range("B18").Value & "が" _
 & vbCrLf & "4を下回っています。"
 End If

 '繰り返し 

 End Sub

 また、いろいろと例示されているコードを試すなかで分からなかったのは下記2点です。 
 ・If Not Intersectを使うメリット
 ・Select Caseに向かないケース

 これからもっと勉強したいと思っているので、様々なアドバイスをいただけると幸いです。
 なお現在不規則勤務のため、失礼ながらお返事が数日遅れることがありますが、
 どうぞよろしくお願いいたします。

< 使用 Excel:Office365、使用 OS:Windows10 >


 参考に

 Private Sub Worksheet_Change(ByVal Target As Range)
    If Intersect(Target, Range("D10:AH10,D18:AH18")) Is Nothing Then Exit Sub
    Select Case Target.Row
        Case 10
            If Range("AM10").Value < 4 Then
                MsgBox Range("B6").Value & "の" & _
                    ActiveSheet.Name & "の" & Range("B10").Value & "が" _
                    & vbCrLf & "4を下回っています。"
            End If
        Case 18
            If Range("AM18") < 4 Then
                MsgBox Range("B14").Value & "の" & _
                    ActiveSheet.Name & "の" & Range("B18").Value & "が" _
                        & vbCrLf & "4を下回っています。"
            End If
    End Select
 End Sub

(ピンク) 2020/05/14(木) 11:22


編集がかぶりましたが、そのまま。

まず、インデントを付けてから、ブレークポイントを設定し何が起こっているのかを把握するのが先決だとおもいます。

そのうえで、複数の条件判定を扱いたいのであれば、Nothingだったら終了するのではなく、Nothing【じゃなかったら】処理する。というように考えてみましょう。

    Private Sub Worksheet_Change(ByVal Target As Range)
        Stop

        If Not Intersect(Target, Range("D10:AH10")) Is Nothing Then
            If Range("AM10") < 4 Then
                MsgBox _
                    Range("B6").Value & "の" & ActiveSheet.Name & "の" & _
                    Range("B10").Value & "が" & _
                    vbCrLf & "4を下回っています。"
            End If
        End If

        If Not Intersect(Target, Range("D18:AH18")) Is Nothing Then
            If Range("AM18") < 4 Then
                MsgBox _
                    Range("B14").Value & "の" & ActiveSheet.Name & "の" & _
                    Range("B18").Value & "が" _
                    & vbCrLf & "4を下回っています。"
            End If
        End If
        '繰り返し
    End Sub

(もこな2 ) 2020/05/14(木) 11:23


 試してないけど ↓ のように書けるはず

 Private Sub Worksheet_Change(ByVal Target As Range)
    Select Case True
        Case Not Intersect(Target, Range("D10:AH10")) Is Nothing: If Range("AM10") < 4 Then MsgBox Range("B6").Value & "の" & ActiveSheet.Name & "の" & Range("B10").Value & "が" & vbCrLf & "4を下回っています。"
        Case Not Intersect(Target, Range("D18:AH18")) Is Nothing: If Range("AM18") < 4 Then MsgBox Range("B14").Value & "の" & ActiveSheet.Name & "の" & Range("B18").Value & "が" & vbCrLf & "4を下回っています。"
    End Select
 End Sub

※ 個人的には読みやすいと思っています。(もちろん異論のあることは承知してます)
(チオチモリン) 2020/05/14(木) 11:33


 Select Case を使うと、例えば10行目と18行目を同時に編集したときに、一方にしか対応できないです
 同時に編集されることはないという前提条件があればいいのですが。
(´・ω・`) 2020/05/14(木) 12:33

そもそも論ですが、
>その指定範囲が12か所ある
とのことですが、具体的にどこです?

どうも、入力されたセルが【指定箇所】の範囲内だったら

 変更されたセルがある行の【AM列】の値をチェックし、4以下であれば、
 4行上のB列 &  その行のB列 が4を超えている

というように読める気がします。

もし、一定のルールがあるなら、そもそも12個のパターン全部を書く必要ないとおもいますがいがでしょうか?

(もこな2 ) 2020/05/14(木) 12:48


 Private Sub Worksheet_Change(ByVal Target As Range)
    Dim c As Range
    For Each c In Target
        If Not Intersect(c, Range("D10:AH10,D18:AH18")) Is Nothing Then
            If Cells(c.Row, "AM").Value < 4 Then
                MsgBox Cells(c.Row - 4, "B").Value & "の" & _
                    ActiveSheet.Name & "の" & Cells(c.Row, "B").Value & "が" _
                    & vbCrLf & "4を下回っています。"
            End If
        End If
    Next c
 End Sub

(ピンク) 2020/05/14(木) 13:37


 みなさま、ご回答ありがとうございます。
 すべてうまく動きました!
 もこな2さまのコードはブレークポイントを確認してからStopを削除して動きました。
 今回は違う行を同時に編集することはないので、いずれも望み通りの結果になりました。

 そして、新たな視点をありがとうございます。
 もこな2さまの仰る通りでございます。
 指定範囲は8行ずつ下がり、チェックするのは必ずAM列で、いずれもその4行上のB列の内容を表示したいのです。
 なぜ気づかず併記しか頭になかったのか、お恥ずかしい……。
 その後にピンクさまが書いてくださったコードも走りました。

 でも近々レイアウトの違うシートで同じことをするので、
 いろんなパターンを併記できるコードも使わせていただきます。

 超初心者がこっぱずかしいことを言いますが、VBAって楽しいですね!
 みなさま、本当にありがとうございました。

(初心者うに) 2020/05/14(木) 14:23


 もこな2さまにお伝えし忘れていました。

 >Nothing【じゃなかったら】処理する
 ためにIf Not Intersectにする必要があるのですね。
 なぜnoを重ねなければいけないのか、そのまま素直に書いたらダメなのかが疑問でしたが、
 理解できました。
 アドバイスありがとうございました。
(初心者うに) 2020/05/14(木) 14:41

 >理解できました。
 との事なので蛇足ながら
 VBA の演算子(演算子の優先順位)
 https://excelwork.info/excel/priority_of_operator/
 とか一読されるとよいかも

 つまり
 ( Not   Intersect(c, Range("D10:AH10,D18:AH18")) )Is Nothing  なのか
   Not ( Intersect(c, Range("D10:AH10,D18:AH18"))   Is Nothing )なのか ということなんですが

 >If Not Intersectにする必要が.... 
 と書かれていますとちょっと...
 
(チオチモリン) 2020/05/14(木) 18:16


 >指定範囲は8行ずつ下がり、チェックするのは必ずAM列で、いずれもその4行上のB列の内容を表示したいのです。
 D10:AH10〜D98:AH98 8行ずつ 計12行に対応してみました。

 Private Sub Worksheet_Change(ByVal Target As Range)
    Dim c As Range
    For Each c In Target
        If (c.Row - 8) Mod 8 = 2 And c.Row <= 98 And c.Column >= 4 And c.Column <= 34 Then
            If Cells(c.Row, "AM").Value < 4 Then
                MsgBox Cells(c.Row - 4, "B").Value & "の" & _
                    ActiveSheet.Name & "の" & Cells(c.Row, "B").Value & "が" _
                    & vbCrLf & "4を下回っています。"
            End If
         End If
    Next
 End Sub

(ピンク) 2020/05/14(木) 19:01


別作業しながら作ってる間に、ピンクさんがより素晴らしいコードを提示されてましたが、せっかくなので投稿しておきます。
    Private Sub Worksheet_Change(ByVal Target As Range)
        Dim MyRNG As Range
        Dim i As Long

        '▼チェック範囲を特定
        With Range("D10:AH10")
            Set MyRNG = .Cells

            For i = 1 To 11 Step 1
                Set MyRNG = Union(MyRNG, .Offset(i * 8))
            Next i
        End With

        '▼変更のあったセルがチェック範囲にあるか判定して、変更のあったセルがチェック範囲に1つもなければ、即終了
        If Intersect(MyRNG, Target) Is Nothing Then Exit Sub

       '▼ ↑で終了していないときだけ処理
       With Cells(Target.Row, "B")
            If Cells(.Row, "AM").Value < 4 Then
                MsgBox .Offset(-4).Value & "の" & Me.Name & "の" & .Value & "が" & vbCrLf & "4を下回っています。"
            End If
        End With

    End Sub

(もこな2 ) 2020/05/14(木) 20:49


↑を改造して行数を減らしてみたバージョン
    Private Sub Worksheet_Change(ByVal Target As Range)

        '▼変更のあったセルがチェック範囲にあるか判定して、変更のあったセルがチェック範囲に1つもなければ、即終了
        If Intersect(Intersect(Range("B10,B18,B26,B34,B42,B50,B58,B66,B74,B82,B90,B98").EntireRow, Range("D:AH")), Target) Is Nothing Then Exit Sub

        '▼ ↑で終了していないときだけ処理
        With Cells(Target.Row, "B")
            If Cells(.Row, "AM").Value < 4 Then MsgBox .Offset(-4).Value & "の" & Me.Name & "の" & .Value & "が" & vbCrLf & "4を下回っています。"
        End With
    End Sub

(もこな2) 2020/05/15(金) 12:51


 みなさま、アドバイスありがとうございます。
 返信が遅くなり申し訳ありません。

 チオチモリンさまのご指摘の通り、カッコの優先順位の話とは捉えられていませんでした。
 あやうく構文であるかのようにうろ覚えしてしまうところでした。

 ピンクさま、Modを使うんですね。
 VBAをさわりはじめる以前も関数としてあまり使ったことがなかったので、
 自分では出てこなかったと思います。

 もこな2さま、2種類もありがとうございます。
 私には「行数を減らしてみたバージョン」がわかりやすかったです。
 まだ、変数でスッキリと収納する頭にはなっていないようです。

(初心者うに) 2020/05/18(月) 14:42


コメント返信:

[ 一覧(最新更新順) ]


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