「動けばいい」は素人の発想だ。CorelDRAW VBAにおけるページ方向判定の堅牢な設計思想
業務自動化の現場において、マクロが「たまたま動く」ことと、「プロフェッショナルなツールとして機能する」ことの間には、深くて暗い川が流れている。
多くの開発者が、CorelDRAW VBAを学び始めた際、まず「特定の操作を自動化すること」に熱中する。しかし、私がプロジェクトリーダーとして求めているのは、単なる自動化コードではない。例外的なユーザー操作や、予期せぬドキュメントの状態に直面しても、沈黙してエラーを吐き出し続けるような脆弱なコードを、いかに排除するかという設計思想だ。
今回のテーマは、もっとも基礎的ながら、設計の質が如実に現れる「ページの向き(Orientation)の判定と条件分岐」である。
単に `If` 文を書くだけではない。プロダクションレベルのコードに求められる「防御的プログラミング」の真髄を伝授する。
1. 致命的なアンチパターン:マジックナンバーの罠
初心者が書くコードには、共通の欠陥がある。それは、APIの定数(Enumeration)を理解せず、生の数値(マジックナンバー)で比較してしまうことだ。
❌ 避けるべきコード例
' 悪い例:これでは保守が不可能だ
If ActivePage.Orientation = 0 Then
' 縦向きの処理
ElseIf ActivePage.Orientation = 1 Then
' 横向きの処理
End If
なぜこれが「悪」なのか?
第一に、可読性が皆無だ。半年後の君、あるいはチームのメンバーがこのコードを見たとき、「0って何だっけ?」とリファレンスを漁ることになる。第二に、CorelDRAWの内部仕様変更や、他のオブジェクトへの応用時にバグを誘発する。
プロフェッショナルは、APIが定義している列挙型(Enum)を直接使用する。これにより、コードは「自己文書化(Self-documenting)」されるのだ。
2. アーキテクトの解法:堅牢な判定ロジック
実務で利用するツールには、必ず「ガード句」が必要だ。
「今、ドキュメントが開いているか?」「アクティブなページは存在するか?」を確認せずに `ActivePage` にアクセスするのは、地雷原を全速力で走るようなものだ。
以下に、私が現場で推奨する、プロダクション品質の基本テンプレートを示す。
✅ プロダクション品質のコード例
Option Explicit
''' <summary>
''' ページの向きを判定し、それに応じた処理を実行するメインルーチン
''' </summary>
Public Sub ExecuteOrientationBasedTask()
' 1. エラーハンドリングの確立
On Error GoTo ErrorHandler
' 2. オブジェクトの存在確認(防御的プログラミング)
' ドキュメントが開かれていない状態で実行されると、ここでエラーが発生するため
If Documents.Count = 0 Then
MsgBox "エラー: 操作対象のドキュメントが開かれていません。", vbCritical, "実行エラー"
Exit Sub
End If
' 3. アクティブなページへの参照取得
Dim targetPage As Page
Set targetPage = ActivePage
' 4. 向きの判定と条件分岐
' CorelDRAWの定数 (cdrPortrait, cdrLandscape) を直接使用する
Select Case targetPage.Orientation
Case cdrPortrait
' --- 縦向き(Portrait)の場合の処理 ---
Debug.Print "現在のページは【縦向き】です。縦長レイアウトを適用します。"
Call ProcessPortraitLayout(targetPage)
Case cdrLandscape
' --- 横向き(Landscape)の場合の処理 ---
Debug.Print "現在のページは【横向き】です。横長レイアウトを適用します。"
Call ProcessLandscapeLayout(targetPage)
Case Else
' 万が一、想定外の値が返ってきた場合のフォールバック
MsgBox "警告: 未知のページ方向を検出しました。", vbExclamation
End Select
' 正常終了
Exit Sub
ErrorHandler:
' エラー内容を詳細にログ出力、またはユーザーに通知
MsgBox "予期せぬエラーが発生しました。" & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Description: " & Err.Description, vbCritical, "システムエラー"
End Sub
''' <summary>
''' 縦向きページ専用のロジック(関数の分離:単一責任の原則)
''' </summary>
Private Sub ProcessPortraitLayout(p As Page)
' ここに具体的な描画やガイド線の配置ロジックを記述する
' 例: 縦長に合わせてガイド線を中央に配置するなど
End Sub
''' <summary>
''' 横向きページ専用のロジック
''' </summary>
Private Sub ProcessLandscapeLayout(p As Page)
' 横長レイアウト用の処理
End Sub
3. なぜこの設計が「強い」のか
このコードには、単なる「条件分岐」以上の意図が込められている。
① 単一責任の原則 (Single Responsibility Principle)
`ExecuteOrientationBasedTask` は「判定」に専念し、実際の「描画処理」は `ProcessPortraitLayout` 等の別サブプロシージャに委ねている。これにより、ロジックの肥大化を防ぎ、テストや修正が容易になる。
② 決定論的なエラー処理
`On Error GoTo ErrorHandler` を冒頭に配置することで、実行時エラーが発生した際に、アプリケーションが「応答なし」で固まるのを防ぎ、ユーザーに適切な情報を与えることができる。これは、クライアントに納品するツールにおいて最低限の礼儀だ。
③ セレクティブな分岐 (`Select Case`)
`If…ElseIf` よりも `Select Case` を推奨する。理由は、拡張性だ。将来的に、特殊なページ設定(例えば、3D的な視点を持つオブジェクトなど)が追加されたとしても、`Case` を一行追加するだけで対応できる。
4. 実務への応用:外部データとの連携を見据えて
君が次に作るツールは、おそらくExcelやCSVから「用紙サイズ」や「向き」を読み込み、それに基づいてCorelDRAWのページを自動生成するものになるだろう。
その際、以下の点に注意せよ。
- データ型の不一致を避ける: Excelから読み込んだ「縦」という文字列をそのまま使うのではなく、必ず内部的な定数(`cdrPortrait`)にマッピングする変換関数を介せ。
- ページ生成のライフサイクル: `Pages.Add` で新しいページを作成した直後は、そのページが必ずしも `ActivePage` になっていない場合がある。必ず生成したオブジェクトを変数に格納し、その変数に対して操作を行え。
最後に
コードを書くとき、常に自分に問いかけてほしい。
「もし、想定外のデータが入力されたら、このコードは優雅に(Gracefully)失敗できるか?」
「動く」のは当たり前だ。我々エンジニアが目指すべきは、「壊れない」、そして「変化に強い」設計である。
次回のセッションでは、この判定ロジックを拡張し、ガイド線を数学的に精密に配置するアルゴリズムについて解説する。準備しておけ。
