【入門編】シェイプシート(ShapeSheet)の数式ハック:VBAからCellsU経由でガードや数式(FormulaU)を操る – Visio VBA解析バイブル

スポンサーリンク

【Visio VBA 深掘り】シェイプシートの数式ハック!CellsUとFormulaUで図形のガードを突破せよ

皆さん、こんにちは!業務自動化の最前線でVisioと格闘しているチーフアーキテクトです。
Visio VBAの世界へようこそ。マクロの記録から一歩進んで、「図形そのものの挙動をプログラムで制御したい」そう願う皆さんのために、今回はVisioの心臓部とも言える「シェイプシート」をVBAから操る極意をお伝えします。

「もっとVisioを自由に動かしたい」「決まったルールで図形を自動配置したいのに、GUIだと手間がかかる」そう感じているあなたに、今回の記事はきっと新たな扉を開いてくれるでしょう。

シェイプシートはVisioの「設計図」

Visioで図形を選択して右クリックし、「ShapeSheetの表示」を選ぶと、見慣れない表計算ソフトのようなウィンドウが開きますよね。これが「シェイプシート」です。

一般的には、図形のサイズ変更や色変更はVisioのGUI(グラフィカルユーザーインターフェース)で行います。でも、シェイプシートは単なるプロパティの羅列ではありません。そこには、図形のサイズ、位置、色といったプロパティだけでなく、「この図形がどのように振る舞うべきか」 を定義する数式やイベントがびっしりと詰まっているのです。

まるで、建物の設計図や機械の回路図のように、その図形のあらゆる特性が詳細に記述されています。そして、この設計図を直接VBAから書き換えることができれば、Visioの可能性は文字通り無限に広がるのです。

なぜシェイプシートをVBAからハックするのか?

「GUIでできることを、わざわざVBAでやる意味があるの?」と思うかもしれません。しかし、VBAからシェイプシートを直接操作する手法は、以下のような点で圧倒的な優位性を持っています。

1. 動的な制御と自動化:

  • 特定の条件に基づいて図形のサイズ、位置、色、そして挙動そのものをプログラムで動的に変更できます。
  • 例えば、「特定のテキストが入力されたら、図形の背景色を自動で変える」といった連動も、VBAから数式を書き込むことで実現可能です。

2. 一括設定と変更:

  • 100個、1000個といった大量の図形に対して、一斉に特定のルールやプロパティを適用・更新できます。手作業では考えられない効率性です。

3. 「ガード」の突破と再設定:

  • Visioには、図形のサイズや位置などがユーザーによって変更されないようにロックする「Guard(ガード)」関数があります。GUIからは設定が難しい、あるいは一度設定すると解除しにくいこのガードも、VBAを使えば意図的に設定・解除・変更が自由自在です。

4. パフォーマンスの最適化:

  • 大量の図形をGUIで一つずつ操作するよりも、VBAで一括処理する方がはるかに高速です。特に複雑な図面を扱う際には、このパフォーマンスの差が生産性に直結します。
  • オブジェクトのライフサイクルを意識し、不要な描画更新を抑制するなどの配慮をVBAコードに組み込むことで、さらに効率的な処理が可能になります。

今回のテーマは、このシェイプシートにVBAから直接数式を流し込み、図形の挙動を「プログラム的に設計し直す」手法です。特に、図形の動作を制限する`Guard`関数をVBAで操る方法に焦点を当てていきましょう。

VBAからシェイプシートを操る基本の「き」:CellsUとFormulaU

Visioのオブジェクトモデルを少しだけおさらいしましょう。

`Application` → `Document` → `Page` → `Shape`

VBAからシェイプシートのセルにアクセスするには、まず操作したい`Shape`オブジェクトを取得する必要があります。そして、その`Shape`オブジェクトが持つ重要なプロパティが `CellsU` です。

`CellsU` プロパティとは?

`Shape.CellsU(セル名)`

`CellsU`は、シェイプシート内の特定のセルにアクセスするためのプロパティです。引数として「セル名」を文字列で指定します。このセル名が少し曲者ですが、慣れれば直感的に使えるようになります。

例えば、図形の幅(Width)にアクセスしたい場合は `Shape.CellsU(“Width”)`、塗りつぶしの前景色(FillForegnd)なら `Shape.CellsU(“FillForegnd”)` のように記述します。カスタムプロパティ(Shape Data)やユーザー定義セル(User-defined Cells)も同様にアクセスできます。

`FormulaU` と `ResultU` の違い

`CellsU`で取得したセルオブジェクトには、主に以下の2つのプロパティを使ってアクセスします。

  • `Cell.FormulaU`: そのセルに記述されている数式そのもの(文字列)を取得または設定します。
  • 例: `Shape.CellsU(“Width”).FormulaU = “GUARD(2 in)”`
  • `Cell.ResultU`: その数式が評価された結果の値を取得します。値を直接設定することも可能ですが、数式を削除して定数として書き込まれます。
  • 例: `Debug.Print Shape.CellsU(“Width”).ResultU` (単位付きで結果が返る)
  • `Shape.CellsU(“Width”).ResultU = 3` (数式が”3 in”に上書きされる)

私たちが今回ハックしたいのは「数式」なので、主に `FormulaU` を使います。

`Guard` 関数とは?

シェイプシートの数式には、様々な関数が使えます。その中でも`Guard`関数は、そのセルの値がユーザー操作によって変更されないように「保護」する役割を持ちます。

書式: `GUARD(数式)`

例: `GUARD(2 in)` → この図形の幅は常に2インチに固定され、ユーザーはGUIから変更できません。
例: `GUARD(Width 1.2)` → この図形の幅は、現在の幅の1.2倍に固定されます。ユーザーが変更しようとしても、常にこの数式が再評価され、元の比率が維持されます。

これは非常に強力な機能ですが、GUIからは直接ガードをかける機能が提供されていないため、シェイプシートを直接編集するか、VBAを使う必要があります。

実践コード例:図形のサイズをGuardで保護し、VBAで解除・変更する

それでは、実際にVBAを使ってシェイプシートの数式を操作し、図形をガードしたり、そのガードを解除・変更したりしてみましょう。

準備:簡単な図形を配置する

まず、Visioで新規描画を開き、適当な長方形ツールで図面内に長方形を一つ描画してください。

コード例1:選択した図形にGuard関数を設定する

以下のVBAコードをVisioのVBAエディタ(Alt + F11)に貼り付けて実行してみてください。

Sub ApplyGuardToShape()
Dim vsoApp As Visio.Application
Dim vsoDoc As Visio.Document
Dim vsoPage As Visio.Page
Dim vsoShape As Visio.Shape

‘ 開発環境でのパフォーマンス最適化(処理中に画面がちらつくのを防ぎ、高速化します)
‘ 大量の図形を処理する際に特に重要です。
Set vsoApp = Visio.Application
vsoApp.ScreenUpdating = False ‘ 画面更新を一時停止
vsoApp.DeferRecalc = True ‘ 再計算を一時停止
vsoApp.EventsEnabled = False ‘ イベント発生を一時停止

On Error GoTo ErrorHandler ‘ エラーハンドリングを設定

‘ 現在アクティブなページを取得
Set vsoPage = vsoApp.ActivePage

‘ 選択されている図形が1つだけであることを確認
If vsoApp.ActiveWindow.Selection.Count = 1 Then
Set vsoShape = vsoApp.ActiveWindow.Selection.Item(1) ‘ 選択図形を取得

‘ —————————————————-
‘ ここが核心!Shape.CellsUとFormulaUを使って数式を書き込みます
‘ 図形の幅(Width)セルに “GUARD(2 in)” という数式を設定します
‘ これにより、幅が2インチに固定され、GUIからの変更ができなくなります
‘ —————————————————-
vsoShape.CellsU(“Width”).FormulaU = “GUARD(2 in)”

‘ 図形の高さ(Height)セルにも “GUARD(3 in)” という数式を設定
vsoShape.CellsU(“Height”).FormulaU = “GUARD(3 in)”

‘ 塗りつぶしの前景色(FillForegnd)を青色にガード
‘ Visioの色パレット番号またはRGB関数で指定できます
‘ 例: RGB(0,0,255) は青色
vsoShape.CellsU(“FillForegnd”).FormulaU = “GUARD(RGB(0,0,255))”

MsgBox “選択した図形の幅、高さ、塗りつぶし色にGuard関数を設定しました。”, vbInformation

Else
MsgBox “図形を1つだけ選択してから実行してください。”, vbExclamation
End If

ExitProcedure:
‘ 処理の終了時に必ずリソースを解放し、設定を元に戻す
If Not vsoApp Is Nothing Then
vsoApp.ScreenUpdating = True
vsoApp.DeferRecalc = False
vsoApp.EventsEnabled = True
End If
Set vsoShape = Nothing
Set vsoPage = Nothing
Set vsoDoc = Nothing
Set vsoApp = Nothing
Exit Sub

ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
Resume ExitProcedure ‘ エラーが発生しても必ず終了処理を実行
End Sub

実行後、何が起こるか?
コードを実行し、ガードをかけた図形を選択してみてください。そして、幅や高さをマウスでドラッグしたり、図形データウィンドウから変更しようとしたりすると、変更できないことに気づくはずです。これが`Guard`関数の威力です。

コード例2:Guardを解除し、新しい値を設定する

今度は、先ほどガードをかけた図形のガードを解除し、新しいサイズを設定してみましょう。

Sub ReleaseGuardAndResizeShape()
Dim vsoApp As Visio.Application
Dim vsoDoc As Visio.Document
Dim vsoPage As Visio.Page
Dim vsoShape As Visio.Shape

Set vsoApp = Visio.Application
vsoApp.ScreenUpdating = False
vsoApp.DeferRecalc = True
vsoApp.EventsEnabled = False

On Error GoTo ErrorHandler

Set vsoPage = vsoApp.ActivePage

If vsoApp.ActiveWindow.Selection.Count = 1 Then
Set vsoShape = vsoApp.ActiveWindow.Selection.Item(1)

‘ —————————————————-
‘ Guard関数を解除し、新しい数式または値を直接設定します
‘ FormulaUに直接値を文字列として代入することで、
‘ Guard関数が上書きされ、新しい数式(または単なる値)が設定されます。
‘ —————————————————-

‘ 幅を4インチに設定(Guard解除)
‘ “4 in” という文字列をFormulaUに代入すると、シェイプシートには “4 in” と記述されます。
‘ もし FormulaU = “4” とした場合は、Visioの既定単位で解釈されます。
vsoShape.CellsU(“Width”).FormulaU = “4 in”

‘ 高さを2インチに設定(Guard解除)
vsoShape.CellsU(“Height”).FormulaU = “2 in”

‘ 塗りつぶしの前景色を黄色に設定(Guard解除)
vsoShape.CellsU(“FillForegnd”).FormulaU = “RGB(255,255,0)” ‘ 黄色

MsgBox “選択した図形のGuard関数を解除し、新しいサイズと色を設定しました。”, vbInformation

Else
MsgBox “図形を1つだけ選択してから実行してください。”, vbExclamation
End If

ExitProcedure:
If Not vsoApp Is Nothing Then
vsoApp.ScreenUpdating = True
vsoApp.DeferRecalc = False
vsoApp.EventsEnabled = True
End If
Set vsoShape = Nothing
Set vsoPage = Nothing
Set vsoDoc = Nothing
Set vsoApp = Nothing
Exit Sub

ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
Resume ExitProcedure
End Sub

実行後、何が起こるか?
コードを実行すると、図形の幅が4インチ、高さが2インチに変わり、背景色が黄色になります。そして、再度GUIから幅や高さを変更できるようになっているはずです。VBAによって、ガードが解除された証拠です。

応用例:動的なGuardを設定する

`Guard`関数は、ただ値を固定するだけでなく、他のセルの値に連動させて保護することも可能です。例えば、図形の幅は常に高さの2倍になるようにガードする、といったこともできます。

Sub ApplyDynamicGuardToShape()
Dim vsoApp As Visio.Application
Dim vsoDoc As Visio.Document
Dim vsoPage As Visio.Page
Dim vsoShape As Visio.Shape

Set vsoApp = Visio.Application
vsoApp.ScreenUpdating = False
vsoApp.DeferRecalc = True
vsoApp.EventsEnabled = False

On Error GoTo ErrorHandler

Set vsoPage = vsoApp.ActivePage

If vsoApp.ActiveWindow.Selection.Count = 1 Then
Set vsoShape = vsoApp.ActiveWindow.Selection.Item(1)

‘ 幅が常に高さの2倍になるようにガードを設定
‘ シェイプシートの数式では、他のセルを参照する際にそのセル名を使います。
‘ 例: Height は図形の高さのセルを指します。
vsoShape.CellsU(“Width”).FormulaU = “GUARD(Height 2)”

‘ 高さを初期値として2インチに設定(これはガードされていません)
vsoShape.CellsU(“Height”).FormulaU = “2 in”

MsgBox “選択した図形の幅が高さの2倍になるように動的なGuardを設定しました。”, vbInformation

Else
MsgBox “図形を1つだけ選択してから実行してください。”, vbExclamation
End If

ExitProcedure:
If Not vsoApp Is Nothing Then
vsoApp.ScreenUpdating = True
vsoApp.DeferRecalc = False
vsoApp.EventsEnabled = True
End If
Set vsoShape = Nothing
Set vsoPage = Nothing
Set vsoDoc = Nothing
Set vsoApp = Nothing
Exit Sub

ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
Resume ExitProcedure
End Sub

実行後、何が起こるか?
このコードを実行後、図形の高さをGUIで変更してみてください。すると、高さに合わせて幅も自動的に変わり、常に幅が高さの2倍に保たれるはずです。これが、数式による動的な制御の真骨頂です。

よくある落とし穴とプロからのアドバイス

VBAからシェイプシートを操作する際、初学者の方が見落としがちなポイントや、パフォーマンスを意識する上で重要な点をいくつかご紹介します。

1. 単位の重要性

Visioのシェイプシートの数式では、`”2 in”` (インチ)、`”5 mm”` (ミリメートル)、`”10 pt”` (ポイント)、`”45 deg”` (角度) のように、単位を明示的に指定することが非常に重要です。単位を省略すると、Visioの既定の単位(多くはページの設定に依存)で解釈され、意図しないサイズになることがあります。

2. 文字列としての数式

`FormulaU`プロパティに代入するのは、あくまで「数式を表す文字列」です。VBAの変数や計算結果を数式に組み込む場合は、文字列結合を適切に使う必要があります。

Dim newWidth As Double
newWidth = 5 ‘ 5インチに設定したい場合

‘ NG: vsoShape.CellsU(“Width”).FormulaU = GUARD(newWidth & ” in”) ‘ GUARD関数は文字列の一部として扱われる
‘ OK: vsoShape.CellsU(“Width”).FormulaU = “GUARD(” & newWidth & ” in)”

3. シェイプシートのセル名の理解

`CellsU`の引数に指定するセル名は、GUIで表示されるプロパティ名と完全に一致しない場合があります。例えば、線の太さはGUIでは「線の重み」ですが、シェイプシートでは`LineWeight`となります。正確なセル名を知るには、シェイプシートを開き、目的のセルをクリックして左上の名前ボックスを確認するのが確実です。

4. パフォーマンスへの配慮:画面更新と再計算の抑制

大量の図形をVBAで処理する場合、Visioが図形の変更のたびに画面を更新したり、数式を再計算したりすると、処理速度が大幅に低下します。これを避けるために、コード例でも示したように、処理の開始時にVisioアプリケーションのいくつかのプロパティを一時的に無効化し、終了時に元に戻すのがプロの常套手段です。

  • `Application.ScreenUpdating = False`: 画面の描画更新を停止します。
  • `Application.DeferRecalc = True`: 数式の自動再計算を一時停止します。
  • `Application.EventsEnabled = False`: Visioのイベント発生を一時停止します。

これらの設定は、VBA処理のボトルネックを解消し、劇的な速度向上をもたらします。ただし、処理終了時には必ず`True`に戻すことを忘れないでください。さもないと、Visioが奇妙な動作をする原因になります。

5. オブジェクトの解放

VBAでは、`Set`キーワードでオブジェクト変数を割り当てたら、処理の終了時に`Set obj = Nothing`として明示的に解放することが推奨されます。これにより、メモリリークを防ぎ、Visioアプリケーションの安定性を保ちます。特にループ処理で大量のオブジェクトを生成・操作する際には、この「オブジェクトのライフサイクル」への配慮が非常に重要になります。

‘ オブジェクトの解放
Set vsoShape = Nothing
Set vsoPage = Nothing
Set vsoDoc = Nothing
Set vsoApp = Nothing

6. エラーハンドリング

予期せぬエラー(例えば、図形が選択されていない、存在しないセル名を指定したなど)に備えて、`On Error GoTo`ステートメントを使ってエラーハンドリングを導入しましょう。これにより、プログラムが途中で停止することなく、適切なメッセージを表示して終了できます。

まとめと次のステップ

今回は、Visio VBAを使ってシェイプシートの数式、特に`Guard`関数を操作するプロフェッショナルな手法について解説しました。

  • シェイプシートがVisio図形の「設計図」であり、その挙動を定義する心臓部であること。
  • `Shape.CellsU`プロパティを使って、特定のセルにアクセスすること。
  • `Cell.FormulaU`プロパティで数式を読み書きし、`Cell.ResultU`でその評価結果を得ること。
  • `Guard`関数を使って図形のプロパティを保護し、VBAからそれを解除・再設定する方法。
  • パフォーマンス最適化のためのVBAテクニック。

これらを理解し実践できれば、あなたはもはやマクロの記録に頼る初学者ではありません。Visioの図形を、あなたの意図通りに、プログラムで完全に制御できる真のVisio VBAエンジニアへの道を歩み始めたことになります。

ここをクリアすれば、Visio VBAの基本はバッチリですよ!

さらに踏み込むなら、シェイプシートのイベントセル(`EventDblClick`など)にVBAマクロを直接呼び出す数式を書き込んだり、カスタムプロパティ(Shape Data)とシェイプシートの数式を連携させて、よりリッチな図形を作成する道も開けます。

Visio VBAの旅はまだまだ続きます。この知識を武器に、あなたの業務自動化をさらに加速させていきましょう!

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