マクロ記録の先へ。Visio VBAで「ページサイズ変更と図面枠の自動中央配置」をマスターする
こんにちは。今日は、Visio VBAの世界へ足を踏み入れたばかりのあなたへ、少しだけ「プロの視点」をお裾分けしようと思います。
Visioで図面を作成しているとき、こんな経験はありませんか?
「ページサイズをA4からA3に変更したら、せっかく配置した図面枠が左上に寄ってしまった……」
マクロの記録機能を使えば、確かに「ページサイズを変える操作」は記録できます。しかし、マクロの記録は「あなたが今行った操作のスタンプ」を記録するだけで、「ページが変わったから、これに合わせて図面枠を動かそう」という論理的な判断はしてくれません。
ここをクリアすれば、Visio VBAの基本はバッチリですよ。今日は、ページサイズを自動判別し、図面枠を完璧に中央へ再配置するロジックを、その仕組みから丁寧に紐解いていきましょう。
1. なぜ図面枠は「左上」に寄ってしまうのか?
問題を解決する前に、まずは「なぜそうなるのか」というメカニズムを理解しましょう。ここが、単なる作業者とエンジニアを分ける境界線です。
Visioのページは、数学のグラフと同じ「座標系」で管理されています。
多くの設定では、ページの左上が原点 $(0, 0)$ となっています。
1. ページサイズを変える $\rightarrow$ 座標の「右」と「下」の範囲が広がる。
2. 図面枠の座標 $\rightarrow$ 図面枠が「左上から $10\text{mm}$」の位置にあると指定されていた場合、ページが大きくなってもその図面枠は「左上から $10\text{mm}$」の位置に居続けます。
結果として、ページが広大になればなるほど、図面枠は相対的に「左上にポツンと残された」状態に見えてしまうのです。
私たちがすべきことは、「新しいページの幅と高さの半分」の座標を計算し、そこに図面枠を移動させること。たったこれだけのことなのですが、VBAで書くには少しコツがいります。
2. 実装の鍵を握る「3つの重要概念」
コードを書く前に、これから使う3つの武器を紹介します。これらはVisio VBAの心臓部です。
① PageSheet(ページシート)
Visioのページは、単なるキャンバスではなく、実は「Sheet(シート)」という概念を持っています。ページ自体の幅(Width)や高さ(Height)といった属性は、この「PageSheet」という特別な場所に格納されています。
② PinX / PinY(ピンの位置)
ここが一番の重要ポイントです!
図形(Shape)の位置を指定するとき、図形の「左端」を指定するのか、「中心」を指定するのか。これを決めているのが Pin(ピン) です。
プロの設計では、図形の中心にピンを置きます。そうすれば、「PinX = ページの幅の半分」 と指定するだけで、図形が完璧に中央に配置されるからです。
③ CellsU(ユニバーサル・セル)
VBAでプロパティを操作する際、`Cells` ではなく `CellsU` を使う癖をつけましょう。`U` は Universal の略です。これは、言語設定(日本語版か英語版か)に左右されず、確実にプロパティを特定するための、エンジニアとしての「作法」です。
3. 実践:中央配置リサイズ・スクリプト
それでは、実際に動くコードを見てみましょう。
このコードは、「現在のページサイズを読み取り、’Drawing Frame’ という名前の図形を探して、その中心をページの真ん中に持っていく」 という動きをします。
Option Explicit
''' <summary>
''' ページサイズを自動判別し、指定した図形を中央に再配置する
''' </summary>
Sub ResizePageAndCenterFrame()
Dim vsoPage As Visio.Page
Dim vsoShape As Visio.Shape
Dim pageWidth As Double
Dim pageHeight As Double
Dim targetShapeName As String
' --- 設定エリア ---
' 中央に配置したい図形の名前を指定してください
targetShapeName = "Drawing Frame"
' ------------------
On Error GoTo ErrorHandler
' 1. 現在のページを取得
Set vsoPage = ActivePage
' 2. ページサイズを取得 (PageSheetからWidthとHeightを読み取る)
' CellsUを使用することで、言語環境に依存しない安定した取得が可能になります
pageWidth = vsoPage.PageSheet.CellsU("PageWidth").ResultIU
pageHeight = vsoPage.PageSheet.CellsU("PageHeight").ResultIU
' ※ ResultIUは内部単位(Inches)での取得を意味しますが、
' Visioの計算上、そのまま数値として扱えます。
' 3. 図面枠(ターゲットとなる図形)を探す
' ページ内のすべての図形をループして名前をチェックします
Set vsoShape = Nothing
Dim vsoTempShape As Visio.Shape
For Each vsoTempShape In vsoPage.Shapes
If vsoTempShape.Name = targetShapeName Then
Set vsoShape = vsoTempShape
Exit For
End If
Next vsoTempShape
' 図形が見つからなかった場合の処理
If vsoShape Is Nothing Then
MsgBox "エラー: '" & targetShapeName & "' という名前の図形が見つかりません。" & vbCrLf & _
"図形の名前を確認してください。", vbExclamation
Exit Sub
End If
' 4. 図形を中央へ移動させる
' 図形の「PinX(中心のX座標)」を「ページ幅の半分」に設定
' 図形の「PinY(中心のY座標)」を「ページ高さの半分」に設定
' ※Visioの座標系では、Y座標は下から上に向かって増える点に注意!
' 描画の更新を高速化するため、一時的に画面更新を止めるようなイメージです
vsoShape.CellsU("PinX").FormulaU = pageWidth / 2 & " in"
vsoShape.CellsU("PinY").FormulaU = pageHeight / 2 & " in"
MsgBox "ページサイズに合わせ、図面枠を中央に配置しました!", vbInformation
Exit Sub
ErrorHandler:
MsgBox "予期せぬエラーが発生しました:" & vbCrLf & Err.Description, vbCritical
End Sub
4. コードの解説:ここがプロの仕事
このコード、ただ動くだけではありません。いくつか「現場で役立つ工夫」を盛り込んでいます。
なぜ `FormulaU = … & ” in”` と書いているのか?
Visioのセルに値を書き込むとき、単に数字を入れるのではなく、`”10 in”`(10インチ)のように単位を明示するのが最も安全な方法です。これにより、計算誤差や単位の取り違えを防ぐことができます。
エラーハンドリングの重要性
`On Error GoTo ErrorHandler` を入れています。もし「図形が見つからなかった」ときや「ページがロックされていた」ときに、プログラムがいきなり強制終了してユーザーを驚かせるのは、良いエンジニアの仕事ではありません。「何が起きたか」を優しく教えてあげるのがマナーです。
ループによる図形の探索
`ActivePage.Shapes(“Drawing Frame”)` と直接指定することもできますが、もし名前が少し違っていたらエラーになります。今回のように `For Each` でループさせて探す方法は、より柔軟で、エラーに強い実装と言えます。
5. まとめ:次に進むあなたへ
今回のステップを振り返りましょう。
1. 座標の仕組みを知る(ページは広がり、図形は元の位置を守ろうとする)
2. Pin(ピン)の概念を理解する(中心を動かせば、配置は簡単になる)
3. PageSheetから情報を引き出す(ページそのものの性質を読み取る)
これをマスターしたあなたは、もう「マクロの記録」という魔法の杖を振るだけの初心者ではありません。「オブジェクトのプロパティを制御し、論理的に配置を組み立てる」という、真の自動化エンジニアへの第一歩を踏み出したのです。
「図面枠の名前を変えてみたらどうなるだろう?」
「複数のページを一括で処理するにはどうすればいいだろう?」
そんな疑問が湧いてきたら、それが成長のサインです。ぜひ、コードを書き換えて実験してみてください。
応援していますよ。次はもっと高度な、レイヤー操作や複雑なデータ連携の世界でお会いしましょう!
