空腹おやじのログと備忘録

VBA(主にExcel)でいろいろな実験的な事とか、Linuxのコマンドとか設定とかについて忘れないように、あれこれと・・・

【VBA】種目別に自動採番(別解)

コロ子さん(id:SNegishi)のところで、自動採番処理をやっているのを見て、ちょっと気がついた点をコメントしました。
すぐに修正版がアップされて「おぉ~、仕事はえぇなぁ」と感心していました。
koroko.hatenablog.com


そんな中で、

「Worksheet_SelectionChangeイベントで変更前の値を保持しておいく」のところを静的変数Staticを使おうとしたけど、モジュール変数として使う事がでなかった。
「プローシシャーの外では使えません」のエラーメッセージが出た。
結局上手くできず、いつもの仮置き方式。
仮置き方式でないなら、どのように作るものなのでしょうか・・・?

多分、Worksheet_SelectionChangeの中にStatic変数を置いちゃったんでしょうね。
そのままでは、他のプロシージャからは、そのStatic変数にはアクセス出来ないので、
もう少し工夫が必要ですね。

私の場合、Static変数はほとんど使うことがなくて、大抵の場合、モジュールレベルのPrivate変数で処理しちゃいます。

下記のソースの vPrevValue_ がそれに当たります。
そいつに、Worksheet_SelectionChangeイベントで、必要な条件に一致した時に値を突っ込みます。

あと、Application.EnableEvents で処理中のイベントを抑止してあげないと、不要な処理が走るようです。


あと、先頭部分で処理不要なら、即 Exit Sub するように
以下の理由により、変えてあります。

  • それ以降、何も処理が無いのが明確になる
    • If でくくった場合、「Ifの後に何か処理があるかもしれない」ので確認が必要。プロシージャが長いほど、スクロールが面倒くさい(私の場合)
  • If によるインデントが不要になる


Private変数を使って処理したソースがこれ

Private vPrevValue_    As Variant


Private Sub Worksheet_Change(ByVal Target As Range)

    Dim buf As Range

    If Target.Column <> 1 Then
        '1列目(A列)以外でイベントが発生した場合は、処理を抜ける
        Exit Sub
    ElseIf vPrevValue_ = Target.Value Then
        'データが変わっていなければ、処理を抜ける
        Exit Sub
    End If


    Application.ScreenUpdating = False
    Application.EnableEvents = False


    '初期化
    Range("B" & Target.Row).Value = ""

    'A列でフィルタ
    Range("A1").AutoFilter Field:=1, Criteria1:=Range("A" & Target.Row).Value

    'アクティブセル領域の可視範囲を取得
    Set buf = Range("A1").CurrentRegion.Columns(2).SpecialCells(xlCellTypeVisible)

    '最大値+1を取得
    Range("B" & Target.Row).Value = Application.WorksheetFunction.Max(buf) + 1

    'フィルター条件解除
    ActiveSheet.ShowAllData


    Application.EnableEvents = True
    Application.ScreenUpdating = True
    
End Sub

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    '複数セルを選択している中に、未入力セルが含まれていても処理できるように
    'Target.Count = 1
    'は含めない

'    If Target.Column = 1 And Target.Count = 1 Then
    If Target.Column = 1 Then

        '複数のセルが選択されている場合、Target.Valueを代入すると、
        'vPrevValueは配列になるのでActiveCellを指定する

'        vPrevValue_ = Target.Value
        vPrevValue_ = ActiveCell.Value
    End If

End Sub