ナレッジベース KB0070
think-cellをアクティブにするとExcelのマクロが鈍化する
VBA マクロにおいてパフォーマンス問題が発生する一般的な原因として、.Select
関数の使用があります。Excel でセルを選択するたびに、それぞれの Excel アドイン (think-cell を含む) に対してこの選択対象変更イベントが通知されるため、マクロの動作が著しく低下します。特にマクロ レコーダーを使用して作成されたマクロでは、このタイプの問題が発生しがちです。
Microsoftも、パフォーマンスを改善するためにVBAコードで.Selectステートメントを避けるよう推奨しています。
- Officeブログ:「Excelで大きな範囲をスキャンする最も早い方法は?」
- MSDN:Excel 2007のパフォーマンス改善:「範囲オブジェクトなどのExcelオブジェクトを選択またはアクティブ化せずに直接参照する」(「より速いVBAマクロ」セクション内)
例:.Select
ステートメントの使用を回避する方法
シンプルなマクロAutoFillTable
を見てみましょう。
Sub AutoFillTable()
Dim iRange As Excel.Range
Set iRange = Application.InputBox(prompt:="Enter range", Type:=8)
Dim nCount As Integer
nCount = iRange.Cells.Count
For i = 1 To nCount
Selection.Copy
If iRange.Cells.Item(i).Value = "" Then
iRange.Cells.Item(i).Range("A1").Select
ActiveSheet.Paste
Else
iRange.Cells.Item(i).Range("A1").Select
End If
Next
End Sub
この関数は、セルの範囲を指定するようユーザーに要請する入力ボックスを開きます。この関数は、範囲内のすべてのセルを移動します。空でないセルが見つかった場合は、このセルのコンテンツをクリップボードにコピーします。この関数はクリップボードのコンテンツをその後の空のセルすべてに貼り付けます。
AutoFillTable
では、クリップボードを使用してセルのコンテンツがコピーされます。このため、この関数は操作される各セルを選択し、どのセルをコピーし、どのセルに貼り付けるのかExcelが把握できるようにする必要があります。推奨される解決策が、以下の AutoFillTable2
関数に示されています。
Sub AutoFillTable2()
Dim iRange As Excel.Range
Set iRange = Application.InputBox(prompt:="Enter range", Type:=8)
Dim iCellMaster As Excel.Range
For Each iCell In iRange.Cells
If iCell.Value = "" Then
If Not iCellMaster Is Nothing Then
iCellMaster.Copy (iCell)
End If
Else
Set iCellMaster = iCell
End If
Next iCell
End Sub
AutoFillTable2
は、前者と比べて 2 つ重要な違いがあります:
- 最も重要なのは、セルを選択する必要がないという点です。代わりに、空でないセルが見つかった場合、このセルは
iCellMaster
変数に保存されます。その後、空のセルが見つかるたびに、iCellMaster
のコンテンツはすべてiCell
にコピーされます。 - これは Visual Basic 言語機能
For Each … Next
を使用して、範囲内のすべてのセルにアクセスします。この時点ですでに読みやすさが改善されています。