SeaGate HomePage 別館
本館 別館 ブログ
 
トップページ
第01回
第02回
第03回
第04回
第05回
第06回
第07回
第08回
第09回
第10回
第11回
第12回
第13回
第14回
おまけ
VBAではじめるAutoCADカスタマイズ VBAではじめるAutoCADカスタマイズ
第12回 知っておくと便利なAutoCAD VBAの定石

■ はじめに

これまでの連載でいろいろなサンプルプログラムを紹介してきました。しかし、VBAからAutoCADのオブジェクトを利用してプログラムを記述する方法には、いくつかお決まりのパターンのようなものがあります。これらのパターンを頭の中に入れておくとプログラムを手早く記述できるようになり、また、いろいろな場面で応用することができます。今回は、AutoCAD VBAプログラミングの定石や知っておくと便利な機能などについて説明します。

■ 図面に関するメソッド、プロパティ

AutoCAD VBAで新規に図面を作成したり既存の図面を開いたりするには、DocumentsコレクションのAddメソッドやOpenメソッドを使用します。AddメソッドやOpenメソッドの実行が成功して図面が作成されたり開かれたりすると、その結果作成された図面(Documentオブジェクト)をメソッドの戻り値として取得することができ、同時にそのDocumentオブジェクトがDocumentsコレクションに追加されます。

Add([テンプレートファイル名]) 図面を新規作成する。NEW[新規作成]コマンドと同じ。
Open(ファイル名[, 読み込み専用]) 既存の図面ファイルを開き、それをアクティブなドキュメントにする。AutoCADのOPEN[開く]コマンドと同じ。

特定の図面を閉じたりファイルに保存したりするには、その図面自身を表わすDocumentオブジェクトのCloseメソッドやSaveメソッド、SaveAsメソッドを使用します。図面を閉じるとそのDocumentオブジェクトは削除され、参照できなくなります。また、CloseメソッドはDocumentsコレクションにもあり、こちらはDocumentオブジェクトのCloseメソッドとは違って引数を取らず、現在AutoCADで開いているすべての図面を閉じます。

Close([図面の保存][, ファイル名]) 指定した図面や開いているすべての図面を閉じる。DocumentオブジェクトではCLOSE[閉じる]コマンド、DocumentsコレクションではCLOSEALL[すべて閉じる]コマンドと同じ。
Save 図面をファイルに上書き保存する。SAVE[保存]コマンドと同じ。
SaveAs(ファイル名, ファイル形式) 図面に名前を付けて指定したファイルに保存する。SAVEAS[名前を付けて保存]コマンドと同じ。

図面を閉じたりAutoCADを終了したりする前に、図面の中にファイルに保存されていない変更点があるかどうかを調べたいことがあります。図面に未保存の変更がないことを確認するには、DocumentオブジェクトのSavedプロパティを使用します。Savedプロパティは図面に未保存の変更があるとFalseを返します。また、Documentオブジェクトの持つImportメソッドやまたはExportメソッドを使用すると、図面にDWG形式以外のファイルから図形などを読み込んだり、図面をDWG形式以外のファイルに書き出したりすることができます。

図面に関するメソッド、プロパティの使用例
> プログラムコードを別ウィンドウで表示 ※ 行番号を入力する必要はありません

SDIモードとMDIモード

アプリケーションがそのウィンドウにただ1つのドキュメントのみを表示する方式をSDI(Single Document Interface)といい、複数のドキュメントを子ウィンドウに表示する方式をMDI(Multiple Document Interface)といいます。2000以降のAutoCADでは、従来のSDIに加えてMDIもサポートされるようになり、1つのAutoCADで複数の図面を開くことができるようになりました。SDIモードとMDIモードはAutoCADの[オプション]ダイアログの[システム]タブ[単一図面互換モード]やSDIシステム変数によって切り替えることができます。

SDIモードでは常にただ1つの図面が開かれた状態となっているので、DocumentsコレクションからAddメソッドやCloseメソッドを呼び出して新しく図面を追加したりすべての図面を閉じたりすることができません。逆に、MDIモードでは現在開かれているすべての図面を閉じてしまう(ゼロのドキュメント状態)こともできるので、ゼロのドキュメント状態の時はThisDrawingにプログラムコードを記述したり、ThisDrawingキーワードを使用して現在アクティブな図面を参照したりすることはできません。

■ Addメソッド

これまでの連載でも何度か紹介しているように、コレクションオブジェクトにそのメンバーとなるオブジェクトを新しく作成して追加するには、メンバーオブジェクトの追加元となるコレクションオブジェクトのAddメソッドや名前にAddの付くメソッドを使用します。このような処理は、図面やモデル空間、画層や線種など、階層構造を持つオブジェクトを新しく作成する際に頻繁に使用されます。また多くの場合、メソッドを実行した結果作成されたメンバーオブジェクトをメソッドの戻り値として取得することができます。

階層構造を持つオブジェクトの例
階層構造を持つオブジェクトの例

Addメソッドや名前にAddの付くメソッドによって新たに作成されたオブジェクトは、既定の外観や属性で作成されます。例えば画層の場合、既定の色は白(色番号7)で、既定の線種は実線(Continuous)となり、これらを変更するには、作成されたオブジェクトのプロパティの値などを変更します。

Addメソッドの使用例
> プログラムコードを別ウィンドウで表示 ※ 行番号を入力する必要はありません

サンプルプログラムSample02の線種の追加では、LinetypesコレクションのAddメソッドではなく、Loadメソッドを使用して線種(LineTypeオブジェクト)を図面に追加しています。LinetypesコレクションのAddメソッドを使用してLineTypeオブジェクトを新たに作成することはできますが、現在のバージョンのAutoCAD VBAではLinetypeオブジェクトに線種の定義を行うためのプロパティなどが用意されていないので、通常はLoadメソッドを使用して既存の線種定義ファイル(サンプルプログラムでは"acadiso.lin"ファイル)から目的の線種を図面にロードします。

Withステートメント

サンプルプログラムの図形(線分)の追加のように、Withステートメントを使用すると、最初に1度だけオブジェクト名を指定すれば、各プロパティやメソッドの前にオブジェクト名を指定する必要がなくなるので、1つのオブジェクトに対する処理をブロック化してプログラムコードを簡潔に記述することができます。また、オブジェクトに対する複数のプロパティ設定やメソッドの呼び出しが高速化されるという効果もあります。ただし、実際にはよほど大規模なプログラムでもない限り、体感できるほどプログラムの実行が高速化されるわけではありません。


■ For Each...Next文

連載第5回でも説明したように、For Each...Next文を使用するとコレクションオブジェクトに含まれるすべてのメンバーオブジェクトを1つずつ取り出すことができます。コレクションオブジェクトに含まれるすべてのメンバーオブジェクトを列挙したり、ある条件に一致するメンバーオブジェクトを探したい時など、AutoCAD VBAではFor Each...Next文を使用したプログラムの記述パターンが頻繁に使用されます。

ただし、For Each...Next文を使用してコレクションオブジェクトに含まれるメンバーオブジェクトを列挙している間は、コレクションオブジェクトのAddメソッドやメンバーオブジェクトの編集メソッドなどを使用しないようにします。For Each...Next文の途中でメンバーオブジェクトを追加したり削除したりすると、正しくメンバーオブジェクトを列挙できなくなってしまうことがあります。

以下のサンプルプログラムでは、現在アクティブな図面のモデル空間内にある図形などのオブジェクトの中から線分(オブジェクトの名前がAcDbLineのもの)であるもの数を数えています。"If objEntity.ObjectName = "AcDbLine" Then"の部分はオブジェクトの型を調べるVBAのTypeOfキーワードとIs演算子を使用して、"If TypeOf objEntity Is AcadLine Then"と書き換えることもできます。

> プログラムコードを別ウィンドウで表示 ※ 行番号を入力する必要はありません

以下のプログラムコードは、現在アクティブな図面の画層の中から指定した画層を検索する例で、Layersコレクションに含まれるLayerオブジェクトをFor Each...Next文で列挙し、その名前が指定したものと一致するかどうかを調べています。UCaseは指定した文字列のアルファベットを小文字から大文字に変換するVBAの関数で、名前の比較を大文字に変換して行っています。ただし、AutoCADは画層名の大文字・小文字を区別しないので、実際にはUCase関数はなくても問題ありません。

> プログラムコードを別ウィンドウで表示 ※ 行番号を入力する必要はありません

以下のプログラムコードは、現在アクティブな図面にロードされている線種をすべて列挙しています。vbCrLfは改行コード(キャリッジリターンとラインフィードの組み合わせ)を表わすVBAの組み込み定数(あらかじめ定義されている定数)で、メッセージボックスに表示される文字列を改行するために文字列の間に挿入しています。

> プログラムコードを別ウィンドウで表示 ※ 行番号を入力する必要はありません

以下のサンプルプログラムでは、連載第7回で説明した選択セットを利用して図面上で選択した図形をすべて赤色に変更しています。現在アクティブな図面のSelectionSetsコレクションに"Sample06"という名前でSelectionSetオブジェクトを追加し、図面上で指定した図形をSelectOnScreenメソッドでSelectionSetオブジェクトに格納した後、For Eachステートメントで格納した図形を1つずつobjEntity変数に取り出して処理を行っています。

> プログラムコードを別ウィンドウで表示 ※ 行番号を入力する必要はありません

■ Countプロパティ、Itemメソッド

コレクションオブジェクトにはAddメソッドや名前にAddの付くメソッド以外にも、共通するメソッドやプロパティがあります。例えばCountプロパティを使用すると、コレクションオブジェクトに含まれるすべてのメンバーオブジェクトの数を取得することができます。またItemメソッドを使用すると、0から始まるインデックス番号や名前などを表わす文字列を指定してコレクションオブジェクト内の特定のメンバーオブジェクトを取得することができます。

以下のサンプルプログラムでは、Countメソッドを使用して現在アクティブな図面のモデル空間内にある図形や画層の数を表示しています。For...Each文を使用してすべてのメンバーオブジェクトを列挙して数えることもできますが、単に数を知りたいだけならCountプロパティを使用したほうが簡潔でプログラムの実行速度も速くなります。

> プログラムコードを別ウィンドウで表示 ※ 行番号を入力する必要はありません

以下のプログラムコードは、サンプルプログラムSample04でFor Each...Next文を使用して作成した画層の検索をItemメソッドで書き換えたものです。画層はその名前で一意に特定することができるので、Itemメソッドの引数にインデックス番号ではなく画層名を指定して直接Layerオブジェクトを取得しています。そして、Layerオブジェクトを取得する際にエラーが発生するかどうかで指定した画層が存在するかどうかを判別しています。

> プログラムコードを別ウィンドウで表示 ※ 行番号を入力する必要はありません

以下のサンプルプログラムでは、サンプルプログラムSample05でFor Each...Next文を使用して作成した線種の列挙を、通常のFor...Next文で書き換えたものです。LinetypesコレクションのCountプロパティで線種の数を取得し、Itemメソッドの引数に0から線種の数-1までのインデックス番号を指定して線種名を取得しています。

> プログラムコードを別ウィンドウで表示 ※ 行番号を入力する必要はありません

既定のメソッド

Itemメソッドはコレクションオブジェクトの既定のメソッドです。既定のメソッドとはコレクションオブジェクトのメソッド名を明示的に指定しなかった時、指定したものと見なされるメソッドのことです。例えば、サンプルプログラムSample08で指定した画層を取得しているプログラムコード(1)は、メソッド名Itemを省略して(2)のように記述することができ、(1)と(2)はまったく同じ意味です。

(1) Set objLayer = ThisDrawing.Layers.Item(findLayer)
(2) Set objLayer = ThisDrawing.Layers(findLayer)

コレクションオブジェクトはその機能が1次元の配列変数と似ているため、(2)のようにメソッド名Itemを省略して配列変数と同じような形式で記述されるのが一般的です。


■ ズームの使用方法

AutoCAD VBAで図面ビューの拡大ズームや縮小ズームを行うには、名前にZoomの付くApplicationオブジェクトのメソッドを使用します。ズームメソッドにはAutoCADのZOOM[ズーム]コマンドの各オプションとほぼ1対1に対応するものが用意されていて、代表的なズームメソッドには下表に示すようなものがあります。ズームメソッドがApplicationオブジェクトのメソッドであることからわかるように、ズームメソッドは現在のアクティブなモデル空間やペーパー空間のビューポートに対してのみ適用されます。

ZoomAll 現在のビューポートを図面全体に表示する。ZOOM[ズーム]コマンドの[図面全体(A)]と同じ。
ZoomCenter(中心点, 倍率) 現在のビューポートを指定した中心点と(高さ)でズームする。ZOOM[ズーム]コマンドの[中心点(C)]と同じ。
ZoomExtents 現在のビューポートを図面範囲までズームする。ZOOM[ズーム]コマンドの[オブジェクト範囲(E)]と同じ。
ZoomPrevious 現在のビューポートを直前の図面範囲にズームする。ZOOM[ズーム]コマンドの[前画面(P)]と同じ。
ZoomScaled(倍率, 倍率の基準) 現在のビューポートを指定した倍率でズーム表示する。ZOOM[ズーム]コマンドの[倍率(S)]と同じ。
ZoomWindow(左下点, 右上点) 現在のビューポートを矩形の対角の2つのコーナーによって指定した領域までズームする。ZOOM[ズーム]コマンドの[窓(W)]と同じ。

ズームメソッドの使用例
> プログラムコードを別ウィンドウで表示 ※ 行番号を入力する必要はありません

■ SendCommandメソッド

最後に究極(?)のメソッドSendCommandを紹介します。SendCommandはDocumentオブジェクトが持つメソッドで、このメソッドを使用すると、その図面のコマンドウィンドウに直接コマンド文字列を送信することができます。コマンド文字列中に[Enter]キーを入力する必要がある時は、文字列の途中や最後にスペースまたはVBAの組み込み定数vbCr(キャリッジリターンコード)を使用します。

以下のサンプルプログラムでは、AutoCADのDIVIDE[ディバイダ]コマンドを利用して分割位置に作図された点を選択セットに格納し、点の位置に円を作図してから削除しています。SendCommandメソッドによってコマンドウィンドウに送信されるコマンド文字列は「_divide (handent "[ハンドル]") [分割数] 」で、handentは指定したハンドル(AutoCADの図形に付けられる固有の値)を持つ図形名を取得するAutoLispの関数です。

> プログラムコードを別ウィンドウで表示 ※ 行番号を入力する必要はありません

連載第2回でも説明したように、VBAではAutoCADのすべての機能が使用できるわけではありません。SendCommandメソッドを使用すれば、VBAでは作成するのが難しいAutoCADのコマンドをVBAから実行させることができます。ただし、SendCommandメソッドはAutoCADのスクリプト機能と同様、ユーザーと対話的な処理を行うのには向きません。また、場合によってはVBAプログラムの動作が不安定になる場合もあるので、あくまでも補助的な利用にとどめ、VBAで実現可能な処理はVBAでプログラミングした方がよいでしょう。

■ 最後に

連載第2回で説明したように、AutoCADのオブジェクトモデルはActiveXの仕様にもとづいて設計されています。そのため、オブジェクトのつながりや構成には一定の規則があり、多くのオブジェクトが同じような処理手順で操作することができるのです。次回は、AutoCADと同様、ActiveXオートメーションに対応したExcelやWordなどのアプリケーションをAutoCAD VBAから制御し、AutoCADと連携して動作するプログラムの作成方法について説明します。
SeaGate
コレクション



inserted by FC2 system