第 14 章 オートメーションと VISIO オブジェクト モデル
オブジェクトを取得するには、オブジェクト変数を宣言し、オブジェクト モデル内を移動しながら、目的のオブジェクトへの参照を取得し、取得した参照をオブジェクト変数に割り当てます。オブジェクトへの参照を取得したら、そのオブジェクトのプロパティの値を設定/取得したり、メソッドを使用してオブジェクトに処理を実行させることができます。
このセクションの内容...
Visio® オブジェクトへの参照を格納する変数は、Visio タイプ ライブラリで定義されている Visio のオブジェクト型 (Visio.Page、Visio.Document など) 変数として宣言する必要があります。目的のオブジェクトを取得したら、Set ステートメントを使用してその参照をオブジェクト変数に割り当てます。
すべてのオブジェクトの参照を変数に割り当てる必要はありませんが、1つのオブジェクトを何度も参照するプログラムでは、オブジェクトへの参照を変数に割り当てておくと便利です。たとえば、ページを操作するプログラムには、Page オブジェクトへの参照を格納するためのオブジェクト変数が少なくとも 1 つ用意されています。Page オブジェクトは、プログラムによって操作されるページを表します。参照するオブジェクトは、プログラムの目的によって異なります。一度プログラムを終了すると、次回実行までオブジェクト変数の値を保持し続けることはできません。オブジェクトへの参照はメモリ アドレスへのポインタのようなものです。つまり、その値はプログラムが実行されるたびに変わる可能性があります。
より一般的なオブジェクト型で変数を宣言することもできますが、Visio のオブジェクト型を使用することにより、プログラムの実行速度が上がります。また、Visio と他のアプリケーションを併用してプログラミングを行うような場合、Visio のオブジェクト型を使用することにより、オブジェクト名やプロパティ名の混同や競合を避けることができます。たとえば、Visio ページに対してオブジェクト変数を宣言する場合は、次の構文を使用します。
Dim pageObj As Visio.Page
「Visio.Page」の代わりに「Page」を使用することもできますが、他のアプリケーションで Page オブジェクトが存在する場合に問題が生じます。たとえば、Microsoft Excel と Visio エンジンには Cell オブジェクトが用意されていますが、これらの 2 つのオブジェクトは異なるオブジェクトであり、一方のアプリケーションで他方のオブジェクトを使用することはできません。
変数は、ローカル変数、モジュールレベル変数、またはグローバル変数として宣言できます。変数の有効範囲は、プログラムでの変数の使用方法によって決めます。変数を宣言する方法の詳細については、Microsoft Visual Basic のオンライン ヘルプを参照してください。
ほとんどの Visio オブジェクトには、他のオブジェクトを参照するプロパティがあります。これらのプロパティを使用して、オブジェクト モデルの階層内を順に移動し、使用したいオブジェクトにアクセスします。
たとえば、Shape オブジェクトにアクセスする場合を考えます。最初に、オブジェクト モデルの最上位オブジェクトである Application オブジェクトへのアクセスを取得します。次に、Application オブジェクトの Documents プロパティから Documents コレクションへの参照を取得します。続いて、次のようにオブジェクト モデル内を移動していきます。
また、ほとんどのオブジェクトには、上記のアクセス方向とは逆に、階層内の上位オブジェクトを参照するプロパティがあります。たとえば、Page オブジェクトの Document プロパティは、Page オブジェクトを含む Document オブジェクトへの参照を返します。
コレクションとは、特定の種類のオブジェクトを複数含むオブジェクトのことです (オブジェクトの数が 0 のコレクションもあります)。コレクション内でループ処理をしてすべてのオブジェクトに対して同じ操作を実行したり、コレクション内の特定のオブジェクトへの参照を取得することができます。各コレクションには、次の 2 つのプロパティがあり、これらのプロパティを使用してコレクション内のオブジェクトを参照できます。
Item プロパティの引数は 1 つだけで、この引数はコレクション内のオブジェクトのインデックス (コレクション内の位置) を数値で示します。ほとんどのコレクションでは、先頭のオブジェクトのインデックスは 1 になります。たとえば、Document オブジェクトの Item プロパティ が 5 を返す場合、その Document オブジェクトは Documents コレクションの 5 番目のメンバです。
ただし、インデックスが 1 ではなく 0 から始まるコレクションもあります。この種のコレクションとして、AccelTables、StatusBars、AccelItems、StatusBarItems、Colors、ToolbarSets、MenuSets、Toolbars、Menus、ToolbarItems、MenuItems、および Hyperlinks コレクションがあります。これらのコレクションでは、コレクション内のオブジェクトの Item プロパティが 5 を返す場合、そのオブジェクトはそのコレクションの 6 番目のメンバです。
インデックスを指定してオブジェクトを取得するには、次のようなコードを使用します (shpsObj は Shapes コレクションを表します)。
Set appObj = Visio.Application
Set docsObj = appObj.Documents
Set docObj = Documents.Item(1)
Set pagsObj = docObj.Pages
Set pagObj = pagsObj.Item(1)
Set shpsObj = pagObj.Shapes
Set shpObj = shpsObj.Item(1)
ページ上に少なくとも 1 つの図形があると仮定した場合、このステートメントは Shapes コレクション内の最初の Shape オブジェクトへの参照を返します。コレクションにオブジェクトが含まれていない場合はエラーが発生します。
ヒント コレクションの Count プロパティの値が 0 でないことを確認してから Item プロパティを使用すると、このようなエラーを回避することができます。
Shape オブジェクトおよび Visio オブジェクト モデルで上位にある関連するオブジェクト
Documents、Pages、Masters、Shapes、または Styles コレクションでは、Item プロパティの引数にオブジェクトの名前を指定することもできます。これは、インデックスを使用してオブジェクトを参照するより便利な場合があります。たとえば、次のコードは、Masters コレクション内の「2-D 双方向矢印」という名前の Master オブジェクトを取得します。
Set mastObj = mastsObj("2-D 双方向矢印")
コレクションの Count プロパティは、コレクション内のオブジェクトの数を返します。Count プロパティが 0 の場合、コレクションにオブジェクトは存在しません。たとえば、次のステートメントは、Visio インスタンスで開いている図面の数を表示します。
MsgBox "Open documents = " & Str$(Documents.Count)
Count プロパティは、ループによる反復処理をどのくらい繰り返すかを設定するためによく使われます。For ステートメントでの Count プロパティの使用例を以下に示します。この For ループでは、Documents コレクション内の各 Document オブジェクトについて、ファイル名の最後の 3 文字をチェックしています。ファイル名の最後の 3 文字がステンシルの拡張子である vss の場合は、コンボボックスのリストにその名前が追加されます。
Set docs = appVisio.Documents
For Each docObj In docsObj
If UCase(Right(docObj.Name, 3)) = "vss" Then
ComboBox1.AddItem docObj.FullName
End If
Next
このようなループの場合は、ループ内でオブジェクトを追加したり削除したりしてコレクション内のオブジェクトの数を変更しないでください。オブジェクトの数を変更すると、ループ内の処理のたびに Count プロパティの値が変わってしまい、処理の回数に影響を与えるからです。
ループを使用してコレクションからオブジェクトを削除する場合は、カウンタの数値を減らします。コレクションからオブジェクトが削除されるたびに、Count プロパティの値が 1 つずつ減り、残りのオブジェクトの位置は前方にシフトされます。このため、ループのカウンタを増分すると、いくつかのオブジェクトが処理されずに残ります。この場合、次のようなループを使用します。
Dim shpsObj As Visio.Shapes
For i = ActivePage.shpsObj.Count To 1 Step -1
shpsObj(i).Delete
Next i
プログラムの実行が終了するか、オブジェクトを参照するすべてのオブジェクト変数が有効範囲外になると、プログラム内のオブジェクトは自動的に解放されます。オブジェクト変数がプロシージャに対するローカル変数の場合は、そのプロシージャが実行を完了すると、オブジェクト変数は参照範囲外になります。オブジェクト変数がグローバル変数の場合は、そのオブジェクトが明示的に解放されない限り、プログラムの実行が完了するまでオブジェクト変数は保持されます。
プログラム内のオブジェクトを解放しても、Visio インスタンス内の対応するオブジェクトには影響はありません。たとえば、Document オブジェクトを解放しても、対応する Visio 図面は閉じられません。ただし、図面は開いたままですが、プログラムからはその図面にアクセスできなくなります。
オブジェクトを明示的に解放するには、そのオブジェクト変数に Visual Basic 特有の値である Nothing を設定します。例を次に示します。
Set docObj = Nothing
複数の変数に同じオブジェクトへの参照を割り当てている場合は、オブジェクトを解放する際に必ず各変数に Nothing を設定してください。
オブジェクトを使用する間は、オブジェクトを解放しないでください。オブジェクトを解放すると、プログラムは、Visio インスタンス内の対応するオブジェクトを参照できなくなります。たとえば、Document オブジェクトを解放すると、プログラムはその Visio 図面にアクセスできなくなります。つまり、その図面を保存したり、閉じたり、そのオブジェクトから他のオブジェクトを取得することができなくなります。
ただし、オブジェクトへの参照が無効になった場合は、プログラム内でオブジェクトを明示的に解放しなければならない場合があります。たとえば、ユーザーが Visio 図面を閉じたり、図形を削除すると、それらのオブジェクトへの参照は無効になります。無効なオブジェクト参照が含まれたオブジェクト変数を使用すると、エラーが発生します。
Microsoft Visual Basic for Applications (VBA) オブジェクトの場合と同様に、Visio オブジェクトの参照、プロパティ、およびメソッドは、1 つのステートメント内で連結できます。ただし、コードの行数が増えても、単純な参照のほうがより効率的な場合もあります。
たとえば、次のステートメントは、Visio インスタンスで最初に開いた図面の 3 ページ目の最初の図形を参照しています。
Set shpobj = Documents(1).Pages(3).Shapes(1)
このステートメントを実行すると、1 つのオブジェクト (shpObj に割り当てられた Shape オブジェクト) が取得されます。単純なオブジェクト参照を使用した、以下の一連のステートメントと比較してください。
Set docObj = Documents.Item(1)
Set pagsObj = docObj.Pages
Set pagObj = pagsObj.Item(3)
Set shpsObj = pagObj.Shapes
Set shpObj = shpsObj.Item(1)
これらのステートメントを実行すると、Document オブジェクト、Pages コレクション、Page オブジェクト、Shapes コレクション、Shape オブジェクトの 5 つのオブジェクトが取得されます。前の例とは異なり、これらのオブジェクトへの参照は変数に割り当てられているため、他の処理にも利用できます。プログラム内の後の処理でこれらの中間オブジェクトにアクセスする必要がある場合は、この方法でオブジェクトを取得したほうが、コードが読みやすくなり、保守が簡単になります。
オブジェクト参照は、参照先の項目とは独立しているため、ユーザーがプログラムの制御範囲を超えた操作を実行すると、オブジェクト参照が無効になる場合があります。たとえば、Shape オブジェクトへの参照が含まれるプログラムで、対応する図形をユーザーが削除すると、プログラム内に参照は残りますが、そのオブジェクト参照は、存在しない図形を参照することになるため、無効になります。
参照が無効になるのを防ぐには、オブジェクト変数の有効範囲と有効期間を制限します。たとえば、ユーザーによる制御を許可した後でプログラムの実行を再開する場合は、特定のオブジェクトを解放してから再び取得すると、オブジェクトを利用可能な状態に保ちながら、プログラムがオブジェクトの最新の状態を参照できるようにすることができます。
有効なオブジェクト参照をより確実に管理する方法は、参照するオブジェクトによって引き起こされたイベントを取得することです。たとえば、プログラムに Shape オブジェクトへの参照がある場合は、変数を無効にする可能性がある BeforeShapeDelete などのイベントを処理します。プログラム内のイベント処理の詳細については、「第 21 章 Visio のイベントの処理」を参照してください。