第1回 直感！スグに使える業務向けVBA汎用プロシージャ(高速化&行・列番号取得)

第0回で配布しました汎用プロシージャのコードの紹介と簡単な解説をやっていきたいと思います！
以下のリンクから .bas ファイルをダウンロードできます（zipファイル）

https://drive.google.com/file/d/11qEUTsq87UItzoKu2okX5WgEopRercCb/view?usp=drive_link

今回ご紹介するプロシージャは
| プロシージャ名		| 概要						|
|-------------------------------|-----------------------------------------------|
| SpeedUp	| 処理の高速化(画面更新停止など)を一括制御	|
| GetRowEnd | 指定列最終セル位置を取得		|
| GetColEnd	| 指定行最終セル位置を取得		|

の3つになります。VBAのド定番の処理ではありますが、より汎用性を高めるべく少し工夫も入れておりますので今後のVBA開発の参考になりましたら幸いです！

## SpeedUp
~~~
Sub SpeedUp(mode As Boolean)
'------------------------------------------------------------------------------------------------------------------------------
'　概要　　｜処理高速化のための環境設定をまとめて制御する
'------------------------------------------------------------------------------------------------------------------------------
'　引数１　｜mode - Trueで高速化設定、Falseで元に戻す(Boolean型)
'------------------------------------------------------------------------------------------------------------------------------
'　実装　　｜Ver.1.0.0(2025/04/20:新規)
'------------------------------------------------------------------------------------------------------------------------------
    
    With Application
        .ScreenUpdating = Not mode '画面更新の停止/再会
        .EnableEvents = Not mode 'イベント処理の停止/再会
        .DisplayAlerts = Not mode '警告表示の停止/再会
        '自動計算の停止/再会
        If mode Then
            .Calculation = xlCalculationManual
        Else
            .Calculation = xlCalculationAutomatic
        End If
    End With
    
End Sub
~~~
特にこれは工夫も何もないですね(笑)
VBAを解説してしてくれているサイトや教本では
~~~
Application.ScreenUpdating = False '画面更新の停止
~~~
を最初に教えてくれるものもありますよね。VBAの動作高速化では王道中の王道といえます。
実はこれ以外にも高速化の方法がありまして、
~~~
Application.Application.EnableEvents = False 'イベント処理の停止
Application.DisplayAlerts = False '警告表示の停止
Application.Calculation = xlCalculationManual '自動計算の停止
~~~
でも高速化が行えます。ちなみに自動計算の停止を行うとその後シート上の数式が自動で計算をしてくれなくなりますのでご注意ください、メイン処理の最初で高速化をONにして最後にOFFにするのが基本的な使い方になるかなと思います。

また、イベント処理を停止することでダブルクリックやセルの値の変化の検知などもできなくなってしまいますので作りたいツールによってEnableEventsの部分をコメントアウトするなど処置の方お願いいたします。

他にもマウス操作を禁止にする方法などもありますが、途中でエラーが発生した時にExcel上でマウス操作ができなくなってしまいかなり面倒なことになりますのでオススメできません。

本プロシージャ使い方としては
~~~
Sub Main()
    
    Call SpeedUp(True) '高速化ON
    
    '途中の処理
    
    Call SpeedUp(False) '高速化OFF
    
End Sub
~~~
このような形になります。いちいちApplication.~と書くのも面倒ですからCall SpeedUp(True or False)で楽して高速化しちゃいましょう！

## GetRowEnd
~~~
Function GetRowEnd(colNumber As Long, Optional targetSheet As Worksheet) As Long
'------------------------------------------------------------------------------------------------------------------------------
'　概要　　｜任意のシートの指定列に入力された最終行番号を返す
'------------------------------------------------------------------------------------------------------------------------------
'　引数１　｜colNumber - 対象の列番号(Long型)
'　引数２　｜targetSheet - 対象のワークシートオブジェクト(規定値:ActiveSheet)(Worksheet型)
'------------------------------------------------------------------------------------------------------------------------------
'　戻り値　｜Long型 - 対象列の最終行番号(データが無い場合は0)
'------------------------------------------------------------------------------------------------------------------------------
'　実装　　｜Ver.1.0.0(2025/04/20:新規)
'------------------------------------------------------------------------------------------------------------------------------
    
    If targetSheet Is Nothing Then Set targetSheet = ActiveSheet
    
    'ユーザー定義エラー
    If colNumber < 1 Then
        Err.Raise vbObjectError + 1001, "GetRowEnd", "引数は1以上の整数にしてください"
    End If
    
    '最終行番号の取得
    GetRowEnd = targetSheet.Cells(targetSheet.Rows.Count, colNumber).End(xlUp).Row
    If targetSheet.Cells(GetRowEnd, colNumber) = "" Then GetRowEnd = 0
    
End Function
~~~
最終行の取得、これも王道中の王道です！個人的にはこれをいかに使いこなせるかがVBAツールの出来の良し悪しを決定づけるとも考えています。VBAツールが「属人性が…」と嫌われてしまう要因に「必要に応じて誰かがVBAを編集しなければならない」があると思います。

例えばですが、シフト表のVBAツールで人事異動などがあって人数の変化があったときにVBEを開いて人数を示す変数の値をいじらなきゃいけない…みたいな、製作者がいるうちはいいですがその製作者が異動でいなくなってしまって残った人が更新の仕方が分からなくてツールが廃れてしまうということあるあるだと思います。かくいう私もVBAを勉強するまでがそういう理由でマクロツール嫌いでした。(プログラミング超苦手だったというのもありますが...)

ですが、最終行の取得といった動的な処理が加わることによりシート上で人数の増減を行ってもVBA側で自動的に検知してくれることによりVBEを開く必要がなくなりよりそのツールが定着しやすくなるかと思います。もちろんマニュアルなどに「この列の下の方に何も書くな」などの注意書き等はしたほうが良いですね。

また、本プロシージャは指定列に何もデータが無い場合0を返します。
~~~
GetRowEnd = targetSheet.Cells(targetSheet.Rows.Count, colNumber).End(xlUp).Row
~~~
のみの場合では指定列に何もデータがなかった場合GetRowEndの値は1になるのですが、次の行の
~~~
If targetSheet.Cells(GetRowEnd, colNumber) = "" Then GetRowEnd = 0
~~~
によってGetRowEndの値が0となります。これにより単なる最終行番号の取得のみならず指定列のデータの有無判定としてもご活用いただけます。

本プロシージャの使い方としては
~~~
Sub Main()
    
    Dim i As Long
    Dim RowEnd As Long
    
    RowEnd = GetRowEnd(1, 対象シート) 'String型ではなくSheet型ですので""で囲わなくて大丈夫です
    
    For i = 1 To GetRowEnd(2)
        '途中の処理
    Next i
    
End Sub
~~~
といった使い方が多いかなと思います。
第2引数の前に**Optional**というワードがくっついているのですがこれが非常に便利でして、**引数を省略可能**にするものなのです！そしてGetRowEndの処理の最初に
~~~
If targetSheet Is Nothing Then Set targetSheet = ActiveSheet
~~~
とありますがこれも非常に重要なものとなっておりまして、「第2引数に何もシートを指定していなければ今アクティブになっているシートで処理するね」という意味になります。

つまりこのプロシージャ一つでアクティブシートはもちろん他のシートの指定列の最終行も取得できてしまいます！他のシートの情報も絡むコードを書くときSheets("他のシート").Cells~と書くのも面倒ですからね(笑)、徹底的に楽していきましょう！

## GetColEnd
~~~
Function GetColEnd(rowNumber As Long, Optional targetSheet As Worksheet) As Long
'------------------------------------------------------------------------------------------------------------------------------
'　概要　　｜任意のシートの指定行に入力された最終列番号を返す
'------------------------------------------------------------------------------------------------------------------------------
'　引数１　｜rowNumber - 対象の行番号(Long型)
'　引数２　｜targetSheet - 対象のワークシートオブジェクト(規定値:ActiveSheet)(Worksheet型)
'------------------------------------------------------------------------------------------------------------------------------
'　戻り値　｜Long型 - 対象行の最終列番号(データが無い場合は0)
'------------------------------------------------------------------------------------------------------------------------------
'　実装　　｜Ver.1.0.0(2025/04/20:新規)
'------------------------------------------------------------------------------------------------------------------------------
    
    If targetSheet Is Nothing Then Set targetSheet = ActiveSheet
    
    'ユーザー定義エラー
    If rowNumber < 1 Then
        Err.Raise vbObjectError + 1001, "GetColEnd", "引数は1以上の整数にしてください"
    End If
    
    '最終列番号を取得
    GetColEnd = targetSheet.Cells(rowNumber, targetSheet.Columns.Count).End(xlToLeft).Column
    If targetSheet.Cells(rowNumber, GetColEnd) = "" Then GetColEnd = 0
    
End Function
~~~
やっていることはGetRowEndとほとんど同じですね。例えばデータベースに対して何か処理をしたい場合にGetRowEndと組み合わせて使うといった場面が多いかと思います。使用例は割愛させていただきます...

最終行・列番号の取得は基本でありながら極意でもあると思っています！
ぜひ様々な場面で使っていただき、「あ、もしかしてここもっと楽になるかも！」と探ってみてください！

## 直感！VBAシリーズ記事一覧
もしよろしければ他の記事もご覧ください！

https://qiita.com/Reko/items/3e482f9a73353e964f00

https://qiita.com/Reko/items/9e211c9c496e12283f33

https://qiita.com/Reko/items/c2dab7b0e8207f8049df

https://qiita.com/Reko/items/b5abcdf614cef5d4073a

https://qiita.com/Reko/items/3451339e723a34ac7897

https://qiita.com/Reko/items/40c66556ac51a8006ea6

https://qiita.com/Reko/items/0269b2bece07a675e797

https://qiita.com/Reko/items/e2d0d0bf2dea4feface1

https://qiita.com/Reko/items/b995c3da88d25f6e0104

https://qiita.com/Reko/items/bc97d79599cfd431b2f3

https://qiita.com/Reko/items/1731aaddfc6e50c209df

https://qiita.com/Reko/items/554a47f2aa944e2eec5e

https://qiita.com/Reko/items/e8253ac68ccafba44ad3