2011年2月26日土曜日

Excel VBAの再計算設定

ExcelのVBAで大量のデータを処理する場合など、再計算の処理をコードで制御することで大幅な高速化につながる。

1.Calculation、ScreenUpdating
最初と最後に

Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
~処理~
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True

のコードを入れる。
1行目はExcelの再計算の設定を"手動"にし、Calculateメソッドを実行しない限り再計算を行わない、というものである。
2行目は再計算ではないが、画面の再描画をOFFにするもので、Macroの処理が終わるまでステータスバー等以外の画面が更新されない。
これらはサイトや本などで割とよく見る手法である。

以下、これの更に応用例を挙げる。


2.他のプロシージャからコールする、又は他のBookから実行する場合

Dim c As Integer
 c = Application.Calculation
Dim a As Boolean
 a = Application.ScreenUpdating

Application.Calculation = xlCalculationManual

Application.ScreenUpdating = False

~処理~

Application.Calculation = c

Application.ScreenUpdating = a

とする。
他のプロシージャ、例えばControl()の中で

Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False

Call Task()

~処理~

Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True

のようにTaskプロシージャをコールしている場合、Task()の方にも同様の記述がしてあると、Taskプロシージャが完了した時点で再計算、再描画の設定が自動、ONになってしまい、その後のControlプロシージャの処理が全て自動再計算/自動再描画の状態で行われてしまう。

これを避けるためにTask()のコードに手動再計算の処理を入れない、あるいは終了時に自動再計算に戻す処理を入れない、ということをすると、今度はTaskプロシージャを単独で動かすときに弊害が生じる。

これは、
・まず最初に現在の再計算/再描画の設定を変数に取得する
・終了時はプロシージャ開始時の再計算/再描画設定に戻す
ことで解決できる。


3.特定の範囲のみを再計算する(1)
再計算の必要な箇所が特定の1シート、あるいは特定のRangeに限られるという場合はCalculateに代えて以下を使う。
Worksheets("シート名").Calculate
あるいは
[再計算範囲].Calculate

普段使われるCalculateは、より丁寧に記述すると実はApplication.Calculateであり、対象のApplication全体(通常は開いているブック全て)を再計算の対象とする。
再計算の範囲は他にも「特定のワークシート」「指定されたセル範囲」があり、必要な箇所のみ再計算を行うようにするとより効率がいい。

ただし、再計算の必要な箇所が複数シートに渡っている場合、複数シートを対象とする再計算のメソッドはどうやら無いようである。また、特定のブックのみを再計算するメソッドも無いようである。
こういう時には、次の方法を使う。

4.特定の範囲のみを再計算する(2)
以下のように、EnableCalculationプロパティを設定する。
Worksheets("シート名").EnableCalculation = False

上の3.で書いたように、複数シートあるいは特定のブックを対象とする再計算が必要な場合、素直には達成できない。仮に複数シートを1シートずつ順番に再計算していくと、後で再計算を行ったシートの結果を先に再計算を行ったシートが参照している場合、誤った計算結果を返してしまう。

これを防ぐため、発想を逆にして、「再計算の必要なシート以外は手動でも再計算しない」という、より強い設定を行う。
具体的には、ワークシートのプロパティにEnableCalculationというのがあるので、これをFalseに設定する。
これを行うと、自動だろうが手動だろうが、Calculateメソッドではそのワークシートは再計算されない。
再計算時に不要なシートを全てEnableCalculation = Falseに設定した上で、Application.Calculateで全体を再計算すれば、シートの計算順序による間違いも起こらず、計算速度を保つことができる。

特定のブックのみ再計算させたい場合も同じである。その他の開いているブックについて、全てのシートを再計算不可にしてしまえばいい。
こういうコードが役に立つと思う。

Dim ws As Worksheet
For Each ws In Workbooks("ブック名").Worksheets
 ws.EnableCalculation = False
Next ws

0 件のコメント:

コメントを投稿