【実務・中級編】Shape.CellsRowIndexとCellsColumnIndexを活用したShapeSheetセルの高速インデックスアクセス手法 – Visio VBA解析バイブル

スポンサーリンク

Visio VBAの隠された高速化の鍵:ShapeSheetセルへの「インデックスアクセス」という神髄

Visio VBAで大量のシェイプを操作する際、パフォーマンスの壁にぶつかった経験はありませんか?特に、シェイプのプロパティを一つずつ設定していくような処理では、その遅さに辟易することもあるでしょう。多くの開発者が文字列でセルを指定する `CellsU` メソッドに頼りがちですが、それは「近道」に見えて、実は「遠回り」なのです。

本稿では、Visio VBAにおけるシェイプのプロパティ操作の真髄に迫ります。それは、`Shape.CellsRowIndex` と `CellsColumnIndex` を駆使した「インデックスアクセス」という手法です。この手法をマスターすれば、あなたのVisio VBAコードは劇的に高速化され、業務効率化ツールの開発において、他を圧倒するパフォーマンスを発揮できるようになります。

なぜ `CellsU` は遅いのか?:文字列指定の落とし穴

まず、なぜ `CellsU` がパフォーマンスのボトルネックになりやすいのかを理解しましょう。`CellsU` メソッドは、シェイプシートのセルを、その名前(例: “Width”, “Height”, “PinX”)という文字列で指定します。

‘ CellsUによるセルの取得(例)
Dim widthCell As Visio.Cell
Set widthCell = MyShape.CellsU(“Width”)
widthCell.FormulaU = “100 mm”

この処理が実行されるとき、Visioは内部的に以下のステップを踏んでいます。

1. 文字列解析: 指定された文字列(例: “Width”)を解析し、対応するセクション、行、列を特定します。
2. セルの検索: シェイプシートの構造を検索し、該当するセルを見つけ出します。
3. プロパティへのアクセス: 見つかったセルオブジェクトのプロパティにアクセスします。

この「文字列解析」と「検索」のプロセスは、特にループ内で何度も実行されると、無視できないオーバーヘッドとなります。シェイプの数が増えれば増えるほど、その遅延は指数関数的に増大するのです。これは、まるで毎回辞書を引いて単語の意味を調べるようなものです。単語を覚えるまでが大変ですが、一度覚えてしまえば「高速で意味を理解できる」でしょう?それと同じです。

秘密兵器:`CellsRowIndex` と `CellsColumnIndex` の力

ここで登場するのが、`Shape.CellsRowIndex` と `CellsColumnIndex` です。これらは、セクション、行、列を数値で指定するためのプロパティです。

  • `Shape.CellsRowIndex(Section, Row)`: 指定されたセクション内の行インデックスに対応する行オブジェクトを取得します。
  • `Shape.CellsColumnIndex(Section, Column)`: 指定されたセクション内の列インデックスに対応する列オブジェクトを取得します。

しかし、これらのプロパティを直接使いこなすには、セクション、行、列の数値インデックスを知っている必要があります。ここで、さらに強力な `CellsSRC` メソッドが登場します。

`CellsSRC(Section, Row, Column)` メソッドは、セクション、行、列の数値インデックスを指定して、直接セルのオブジェクトを取得します。

‘ CellsSRCによるセルの取得(例)
Dim widthCell As Visio.Cell
‘ Section=visSectionObjectInfo (0), Row=visRowXForm1D (0), Column=visXFormWidth (1)
Set widthCell = MyShape.CellsSRC(visSectionObjectInfo, visRowXForm1D, visXFormWidth)
widthCell.FormulaU = “100 mm”

ここで重要なのは、`visSectionObjectInfo`, `visRowXForm1D`, `visXFormWidth` といった定数です。これらはVisio VBAで定義されており、特定のセクション、行、列を指し示すためのマジックナンバーです。これらの定数を用いることで、`CellsU` のような文字列解析のオーバーヘッドを完全に排除し、直接セルのメモリ位置にアクセスするような感覚で処理を実行できます。

なぜ `CellsSRC` が圧倒的に速いのか?:直接的なメモリマッピング

`CellsSRC` メソッドは、指定された数値インデックスを元に、Visioの内部データ構造から直接セルのメモリ位置を特定します。文字列解析のステップが一切ないため、その処理速度は `CellsU` とは比較にならないほど高速です。

例えるなら、`CellsU` が「地図帳で住所を探して、その場所へ行く」のに対し、`CellsSRC` は「GPSの座標で直接目的地へ到達する」ようなものです。大量のシェイプを扱う場合、この差は歴然となります。

どのセルがどれに対応するのか?:定数の世界へようこそ

`CellsSRC` を活用する上で避けて通れないのが、これらの定数です。Visio VBAでは、セクション、行、列に対応する定数が多数定義されています。これらは、Visioのヘルプやオブジェクトブラウザで確認できますが、よく使うものをいくつか紹介しましょう。

代表的なセクション定数:

  • `visSectionObjectInfo`: オブジェクトの基本情報(Width, Height, Angleなど)
  • `visSectionText`: テキスト関連の設定
  • `visSectionLine`: 線属性の設定
  • `visSectionFill`: 塗りつぶし属性の設定
  • `visSectionGeometry`: 図形形状の定義

代表的な行定数 (例: `visSectionObjectInfo` 内):

  • `visRowXForm1D`: 1D変換(Width, Height, PinX, PinY, Angleなど)
  • `visRowXForm2D`: 2D変換(LocPinX, LocPinYなど)

代表的な列定数 (例: `visSectionObjectInfo` の `visRowXForm1D` 内):

  • `visXFormWidth`: Width
  • `visXFormHeight`: Height
  • `visXFormPinX`: PinX
  • `visXFormPinY`: PinY
  • `visXFormAngle`: Angle

これらの定数を組み合わせることで、目的のセルに直接アクセスできます。

実践! `CellsSRC` を用いた高速シェイププロパティ設定

では、具体的に `CellsSRC` を使ったコードを見ていきましょう。ここでは、多数のシェイプの幅と高さを一括で設定する例を示します。

脆弱なコード例(`CellsU` を使用)

Sub SetShapeSize_Slow()

Dim shp As Visio.Shape
Dim vsoPage As Visio.Page
Dim i As Long
Dim numShapes As Long

Set vsoPage = Visio.ActivePage

‘ 処理対象のシェイプ数を取得
numShapes = vsoPage.Shapes.Count

‘ 処理速度向上のため画面更新を一時停止
Application.ScreenUpdating = False
Application.ActiveWindow.Page.AutoLayout = visAutoLayoutNone ‘ レイアウト更新も無効化

‘ 各シェイプの幅と高さを設定
For i = 1 To numShapes
Set shp = vsoPage.Shapes(i)

‘ CellsUによる幅の設定(低速)
shp.CellsU(“Width”).FormulaU = “50 mm”
‘ CellsUによる高さの設定(低速)
shp.CellsU(“Height”).FormulaU = “30 mm”
Next i

‘ 画面更新を再開
Application.ScreenUpdating = True
‘ レイアウト更新を有効化
Application.ActiveWindow.Page.AutoLayout = visAutoLayoutNormal

MsgBox “シェイプサイズの更新が完了しました(低速版)。”, vbInformation

End Sub

このコードは、機能的には問題ありませんが、ループ内で `CellsU` を繰り返し呼び出すため、シェイプ数が増えると顕著に遅くなります。

堅牢かつ高速なコード例(`CellsSRC` を使用)

Sub SetShapeSize_Fast()

Dim shp As Visio.Shape
Dim vsoPage As Visio.Page
Dim i As Long
Dim numShapes As Long

Set vsoPage = Visio.ActivePage

‘ 処理対象のシェイプ数を取得
numShapes = vsoPage.Shapes.Count

‘ 処理速度向上のため画面更新を一時停止
Application.ScreenUpdating = False
Application.ActiveWindow.Page.AutoLayout = visAutoLayoutNone ‘ レイアウト更新も無効化

‘ よく使うセルへの参照を保持(パフォーマンス向上)
‘ Width, Height, PinX, PinY は visSectionObjectInfo の visRowXForm1D に属する
Const SECTION_OBJ_INFO As Integer = visSectionObjectInfo
Const ROW_XFORM_1D As Integer = visRowXForm1D
Const COL_WIDTH As Integer = visXFormWidth
Const COL_HEIGHT As Integer = visXFormHeight
‘ Const COL_PINX As Integer = visXFormPinX ‘ 必要に応じて追加
‘ Const COL_PINY As Integer = visXFormPinY ‘ 必要に応じて追加

Dim widthCell As Visio.Cell
Dim heightCell As Visio.Cell

‘ 各シェイプの幅と高さを設定
For i = 1 To numShapes
Set shp = vsoPage.Shapes(i)

‘ CellsSRCによる幅の設定(高速)
Set widthCell = shp.CellsSRC(SECTION_OBJ_INFO, ROW_XFORM_1D, COL_WIDTH)
widthCell.FormulaU = “50 mm”

‘ CellsSRCによる高さの設定(高速)
Set heightCell = shp.CellsSRC(SECTION_OBJ_INFO, ROW_XFORM_1D, COL_HEIGHT)
heightCell.FormulaU = “30 mm”
Next i

‘ 画面更新を再開
Application.ScreenUpdating = True
‘ レイアウト更新を有効化
Application.ActiveWindow.Page.AutoLayout = visAutoLayoutNormal

MsgBox “シェイプサイズの更新が完了しました(高速版)。”, vbInformation

End Sub

コード解説と注意点:

1. 画面更新の無効化: `Application.ScreenUpdating = False` は、VBA処理中の画面描画を一時停止し、パフォーマンスを大幅に向上させます。大量のオブジェクトを操作する際には必須のテクニックです。
2. レイアウト更新の無効化: `Application.ActiveWindow.Page.AutoLayout = visAutoLayoutNone` も同様に、シェイプの配置変更に伴う再描画処理を抑制し、処理速度を向上させます。
3. 定数の定義: `Const` を使用して、セクション、行、列のインデックスを定数として定義しています。これにより、コードの可読性が向上し、インデックス番号を直接記述するよりもバグを減らすことができます。
4. セルの参照の保持: ループ内で毎回 `CellsSRC` を呼び出すのではなく、`widthCell` や `heightCell` のような `Visio.Cell` オブジェクトとして参照を保持しています。これにより、さらにオーバーヘッドを削減できます。これは、セルのプロパティ(`FormulaU` など)にアクセスする際にも有効です。
5. `FormulaU` の使用: セルに値を設定する際には、`FormulaU` プロパティを使用するのが一般的です。これにより、単位(”mm”, “cm”, “in” など)を含めて正確な値を設定できます。

堅牢な設計のための考慮事項

1. バグの発生を防ぐための設計

  • 定数の活用: 前述の通り、`CellsSRC` では定数を使うことで、数字の誤入力によるバグを防ぎます。
  • エラーハンドリング: `On Error Resume Next` は安易に使うべきではありません。特に `CellsSRC` のインデックスが不正な場合、予期せぬエラーが発生する可能性があります。`On Error GoTo ErrorHandler` を適切に配置し、エラー発生時の処理を定義することが重要です。
  • Nullチェック: シェイプが存在しない、または特定のセルが存在しないといった状況も考慮し、`Set` でオブジェクトを取得した後に `If Not shp Is Nothing Then` のようなチェックを入れることで、Null参照エラーを防ぎます。

2. ファイル・データベース連携時の注意点

Visio VBAで作成したツールが、外部ファイル(CSV, Excelなど)やデータベースと連携する場合、以下の点に注意が必要です。

  • データ整合性: 外部データソースから読み込んだ値が、Visioのセルの期待するフォーマット(数値、単位付き文字列など)と一致するかどうかを厳密にチェックする必要があります。例えば、CSVファイルから幅の値を読み込む際に、数値でないデータが含まれているとエラーの原因となります。
  • 単位の統一: Visioのセルの値は、設定されている単位系に依存します。外部データソースが異なる単位系で値を保持している場合、変換処理を Vba コード内で実装する必要があります。`Application.ConvertFormula` メソッドが役立ちます。
  • トランザクション処理: データベース連携の場合、一連の処理が失敗した場合に、データベースの状態を元に戻す(ロールバック)ためのトランザクション処理を検討しましょう。
  • パフォーマンス: 大量のデータをファイルやデータベースから読み書きする場合、その処理自体がボトルネックにならないように、バッファリングや非同期処理などを検討する必要があります。VBA単体での限界を感じる場合は、VB.NETやC#などのより強力な言語での開発も視野に入れましょう。

3. 保守性と再利用性を高めるプロダクションコード

コピペで動くコードは重要ですが、長期的な保守や機能拡張を考えると、より構造化されたコードが求められます。

  • モジュール化: 関連する処理を個別のプロシージャやモジュールに分割します。例えば、「シェイプのサイズ設定」を一つのプロシージャ、「テキストの変更」を別のプロシージャにするなどです。
  • クラスモジュール: より高度なオブジェクト指向設計を行う場合、シェイプをラップするクラスを作成し、そのクラスのメソッドとしてプロパティ設定処理を実装することも有効です。これにより、コードの再利用性やカプセル化が向上します。
  • コメントの徹底: コードの意図、処理の流れ、注意点などをコメントとして詳細に記述します。これは、将来的にコードを理解し、修正する際に不可欠です。

まとめ:`CellsSRC` でVisio VBAのポテンシャルを解き放つ

`Shape.CellsSRC` メソッドと、それに伴うセクション・行・列の数値インデックス(定数)の活用は、Visio VBAにおけるシェイプ操作のパフォーマンスを劇的に向上させるための究極のテクニックです。

`CellsU` のような文字列指定は、手軽に見えても、大量のシェイプを扱う際には致命的な遅延を生みます。`CellsSRC` を理解し、適切に使いこなすことで、あなたの開発するVisio VBAアプリケーションは、これまで考えられなかったほどの高速処理を実現し、ユーザーに驚きと満足を与えることができるでしょう。

業務効率化ツールの開発担当者であるあなたにとって、この「インデックスアクセス」という神髄は、まさにプロジェクト成功への最短ルートです。ぜひ、この知識を武器に、よりパワフルで洗練されたVisio VBAソリューションを開発してください。

タイトルとURLをコピーしました