[[20250527173949]] 『Worksheet_Changeを2つ以上登録する場合について』(マクロ初心者) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) |

| 全文検索 | 過去ログ ]

 

『Worksheet_Changeを2つ以上登録する場合について』(マクロ初心者)

[挨拶文]
はじめまして。
務めている会社よりエクセルで工数管理を省略化したいと言われ何とかマクロを組めないかと、試行錯誤を繰り返しております。
初めてのマクロで基礎も分かっておらず、数日間悩んでおります。
マクロもWEBから参考し数値変更したものばかりです。

Sheet1にシート非表示のマクロと、日付自動入力のマクロを入力したいのですが、Worksheet_Changeを2つ以上登録する方法がわかりません。
どなたかご教授頂けますと助かります。

シート非表示のマクロ
Const ROW_MIN = 5
Const ROW_MAX = 25
Const COL_INPUT = 15
Const COL_SHEETNAME = 16

Const VALUE_VISIBLE = "〇"

Private Sub Worksheet_Change(ByVal Target As Range)

  Dim configRange As Range
  Set configRange = Range(Cells(ROW_MIN, COL_INPUT), Cells(ROW_MAX, COL_SHEETNAME))
  If Intersect(Target, configRange) Is Nothing Then Exit Sub

  Dim Row As Long
  Dim targetSheet As Worksheet
  For Row = ROW_MIN To ROW_MAX
    Set targetSheet = ThisWorkbook.Worksheets(Cells(Row, COL_SHEETNAME).Value)

    If Cells(Row, COL_INPUT) = VALUE_VISIBLE Then
      targetSheet.Visible = xlSheetVisible
    Else
      targetSheet.Visible = xlSheetHidden
    End If
  Next

End Sub

日付自動入力のマクロ
Private Sub Worksheet_Change(ByVal Target As Range)
Dim r As Range

  For Each r In Target
    If r.Column = 3 Then
       r.Offset(0, -2).Value = Format(Now, "mm/dd")
    End If
  Next r
End Sub

< 使用 Excel:unknown、使用 OS:Windows11 >


 ひとつのプロシージャにまとめればよいでしょう。
 ・日付自動入力のマクロ を先に実行し
 ・シート非表示のマクロ を次に実行
 すればよいでしょう。

 逆の順序で実行すると、
 If Intersect(Target, configRange) Is Nothing Then Exit Sub
 で終了してしまうので。

 なお、日付自動入力のマクロ のなかでは、
             Application.EnableEvents = False
             r.Offset(0, -2).Value = Format(Now, "mm/dd")
             Application.EnableEvents = True
 とすべきです。            
 r.Offset(0, -2).Value = Format(Now, "mm/dd")の実行によって、
 自分自身(イベントプロシージャ)が再実行されるのを防ぐためです。

 # コードの詳細は見ていません。

(xyz) 2025/05/27(火) 18:20:07


コメントありがとうございます。
マクロを1つにまとめるにはどのようなプログラムを組めばよいのでしょうか?

コピペしたら使えるようなものをご提示いただけると助かります。
よろしくお願いいたします。
(マクロ初心者) 2025/05/28(水) 11:14:43


EXCELのVBAで以下の2つのWorksheet_Changeを一つにしたとすれば、
たとえば 

 Private Sub Worksheet_Change(ByVal Target As Range)

    ' --- 日付自動入力 ---
    Dim r As Range

    For Each r In Target
        If r.Column = 3 Then
            r.Offset(0, -2).Value = Format(Now, "mm/dd")
        End If
    Next r

    ' --- シート非表示/表示 ---
    Const ROW_MIN = 5
    Const ROW_MAX = 25
    Const COL_INPUT = 15
    Const COL_SHEETNAME = 16
    Const VALUE_VISIBLE = "〇"

    Dim configRange As Range

    Set configRange = Range(Cells(ROW_MIN, COL_INPUT), Cells(ROW_MAX, COL_SHEETNAME))
    If Not Intersect(Target, configRange) Is Nothing Then
        Dim Row As Long
        Dim targetSheet As Worksheet
        For Row = ROW_MIN To ROW_MAX
            On Error Resume Next ' シート名が不正な場合にも対応
            Set targetSheet = ThisWorkbook.Worksheets(Cells(Row, COL_SHEETNAME).Value)
            If Not targetSheet Is Nothing Then
                If Cells(Row, COL_INPUT).Value = VALUE_VISIBLE Then
                    targetSheet.Visible = xlSheetVisible
                Else
                    targetSheet.Visible = xlSheetHidden
                End If
            End If
            Set targetSheet = Nothing
            On Error GoTo 0
        Next Row
    End If
End Sub

(暇な人) 2025/05/28(水) 12:29:44


既に必要なアドバイスは得られているように思いますが何点か。

■1
>Worksheet_Changeを2つ以上登録
過去ログを見てもらうとなんとなくわかるかと思いますが、そもそも1つのシートモジュールに「Changeイベント」を複数配置できません。
提示したコードの内容をどこまで理解で来ているかわかりませんが、考え方を【条件に一致したら(しなかったら)処理を終了する】という考え方から【条件に一致する(しない)時だけ処理する】という考え方にするとよいとおもいます。

■2
定数をいくつか使用されていますが、この程度であれば定数を使わない方がかえって見やすいんじゃないかと思います。

■3
>コピペしたら使えるようなものをご提示いただけると助かります。
私見になりますが、丸投げしたいのであれば対価を払って作成依頼するようなサイトに移動するのも手だとおもいます。

以下「■1」「■2」を踏まえて、私なりに整理したものを提示します。

 完成品プレゼントの意図はありませんので、理解せずにそのままコピペするだけであれば使用しないでください。

    Private Sub Worksheet_Change(ByVal Target As Range)
        Dim MyROW As Long, MyRNG As Range

        '▼一つ目
        If Not Intersect(Target, Range("O5:P25")) Is Nothing Then '★ここで処理するか判定
            For MyROW = 5 To 25 Step 1
                If Cells(MyROW, "O").Value = "〇" Then
                    ThisWorkbook.Worksheets(Cells(MyROW, "P").Value).Visible = xlSheetVisible
                Else
                    ThisWorkbook.Worksheets(Cells(MyROW, "P").Value).Visible = xlSheetHidden
                End If
            Next
        End If

        '▼二つ目
        Set MyRNG = Intersect(Target, Range("C:C"))
        If Not MyRNG Is Nothing Then '★ここで処理するか判定
            Intersect(MyRNG.EntireRow, Range("A:A")).Value = Format(Now, "mm/dd")
        End If

    End Sub

■4
上記の一つ目について、今のままだと逐一5〜25行目まで処理することになっています。
本来は、O列なりP列が書き変わった行だけ処理すればよかったりしませんか?

(もこな2 ) 2025/05/28(水) 14:22:17


 ん? マクロを1つにまとめる? ↓こういうこと?

 Const ROW_MIN = 5
 Const ROW_MAX = 25
 Const COL_INPUT = 15
 Const COL_SHEETNAME = 16
 Const VALUE_VISIBLE = "〇"

 Private Sub Worksheet_Change(ByVal Target As Range)
    Worksheet_Change_1 Target   '1つ目のイベント処理
    Worksheet_Change_2 Target   '2つ目のイベント処理
 End Sub

 Sub Worksheet_Change_1(ByVal Target As Range)
    Dim configRange As Range
    Set configRange = Range(Cells(ROW_MIN, COL_INPUT), Cells(ROW_MAX, COL_SHEETNAME))
    If Intersect(Target, configRange) Is Nothing Then Exit Sub
    Dim Row As Long
    Dim targetSheet As Worksheet
    For Row = ROW_MIN To ROW_MAX
        Set targetSheet = ThisWorkbook.Worksheets(Cells(Row, COL_SHEETNAME).Value)
        If Cells(Row, COL_INPUT) = VALUE_VISIBLE Then
            targetSheet.Visible = xlSheetVisible
        Else
            targetSheet.Visible = xlSheetHidden
        End If
    Next
 End Sub

 Sub Worksheet_Change_2(ByVal Target As Range)
    Dim r As Range
    For Each r In Target
        If r.Column = 3 Then
            r.Offset(0, -2).Value = Format(Now, "mm/dd")
        End If
    Next r
 End Sub

 ちなみに、 Const VALUE_VISIBLE = "〇"  ← 記号の丸ではなく、漢数字の零で良いの?
  
(ん?) 2025/05/28(水) 21:52:13

残念ながらトピ主の反応がありませんが、同じ悩みをもってたどり着いた人向け。

仕様から考えれば、前者は書き換えがあった行だけ見ればよいはずなのと、P列に存在しないシート名を書かれちゃうとエラー停止してしまうので、そこの対策が必要であるように思います。

また、ChangeイベントはTargetが複数セルになることがあり得ます。
この特性と処理内容を踏まえると、
 前者・・・・1行ずつみていく必要あり
 後者・・・・該当行(セル)を一括処理すればOK
というような整理が可能です。

ということで研究用材料として整理したコードを置いておきます。

    Private Sub Worksheet_Change(ByVal Target As Range)
        Dim tmpRNG As Range, MyRNG As Range

        Stop 'ブレークポイントの代わり

        '▼一つ目(シート非表示のマクロ)
        Set MyRNG = Intersect(Target, Range("O5:P25"))
        If Not MyRNG Is Nothing Then
            On Error Resume Next
            For Each tmpRNG In Intersect(MyRNG.EntireRow, Range("O:O"))
                ThisWorkbook.Worksheets(tmpRNG.Offset(, 1).Value).Visible = tmpRNG.Value = "〇"
            Next tmpRNG
            On Error GoTo 0

        End If

        '▼二つ目(日付自動入力のマクロ)
        Set MyRNG = Intersect(Target, Range("C:C"))
        If Not MyRNG Is Nothing Then
            Intersect(MyRNG.EntireRow, Range("A:A")).Value = Format(Now, "mm/dd")
        End If

    End Sub

(もこな2) 2025/05/31(土) 09:39:33


コメント返信:

[ 一覧(最新更新順) ]


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