CorelDRAWでマクロを利用するためのドキュメント「Storing Custom Information in Documents」の和訳です。
カスタム・ソリューションでは、後で使用するために、文書内にカスタム・データを保存できます。カスタム・データは、それぞれのオブジェクト、レイヤー、ページや全ての文書に追加することができます。そして、それらの文書の要素を識別するために使用できます。ソリューションで使用するために、カスタム・プロパティを添付します。
カスタム・データが、CorelDRAWとCorel DESIGNERの文書要素と関連できるたくさんの方法が、あります。
オブジェクト・データ管理ソフトウェア
Object Data Manager
CorelDRAWとCorel DESIGNERは、任意のオブジェクトを持つカスタム・データを関連付けることができます。そのユーザー・インターフェイスの文書の右側で、オブジェクト・データ管理ソフトウェア・ドッキング・ウィンドウを使用して、このドッキング・ウィンドウは、Window > ドッキング・ウィンドウ > オブジェクト・データ・マネージャー(CorelDRAW)または、Window > オブジェクト・データ・マネージャーCorel DESIGNER)によってアクセスできます。このドッキング・ウィンドウは、指定、そして、データを書式設定できるプロパティを管理するだけでなく、予めセットされたプロパティの1つを、文書内のオブジェクトに格納するために使用できます。
Object Data ManagerのCorel DESIGNERのバージョンには、カスタム・データを使用して、オブジェクトにタグを付けるCGMのような、テクニカル・ドローイング・データ形式との相互運用性に向けた機能が追加されています。そして、インタラクティブな動作をエクスポートされた文書を割り当てます。しかしながら、CorelDRAWとCorel DESIGNERの両方で、事前に設定されたオブジェクト・プロパティのリストから選択し、新しいプロパティを作成できます。
データ・フィールドのデフォルトのセットを持つCorelDRAWのオブジェクト・データ・マネージャー:
Corel DESIGNERのブジェクト・データ・マネージャー:
新しいフィールドを追加するか、既存のデータ・フィールドの外観/フォーマットを変更するために、オブジェクト・データ・マネージャーのドッキング・ウィンドウの上部にある、「フィールド・エディタ・ボタンを開く」を使用します。:
オブジェクト・データ・マネージャーは、文書内の現在選択されているオブジェクトに関連付けられているデータを表示します。あなたは、Spreadsheetウィンドウを使用して、選択したいくつかのオブジェクトのデータも表示できます。:
VBAマクロのような、オブジェクト・データ・マネージャー・ドッキング・ウィンドウを使用して、文書内のオブジェクトに関連したデータは、カスタム・ソリューションからアクセスできます。
特定のオブジェクトに割り当てられたオブジェクト・データは、Shape.ObjectDataプロパティを通して利用できますが、データ・プロパティのリストは、Document.DataFieldsコレクションによってアクセスできます。
たとえば、次のVBAマクロは、カスタム・データ・フィールド"Height"を作成します。ページに、長方形を作成します。そして、標準的な"Name"と"Comments"プロパティを設定するだけでなく、"2"の値を持つ"Height"プロパティを割り当てます:
Sub CreateCustomData()
Dim field As DataField
Dim s As Shape
Set field = ActiveDocument.DataFields.Add("Height", "General")
Set s = ActiveLayer.CreateRectangle(0, 0, 2, 2)
s.ObjectData("Name") = "Rectangle"
s.ObjectData("Comments") = "Simple rectangle"
s.ObjectData.Add field, 2
End Sub
マクロが実行されたあと、長方形オブジェクトが、作成されます。そして、そのすべての割り当てられたデータは、オブジェクト・データ・マネージャー・ドッキング・ウィンドウで示されます。:
オブジェクト・データを図面で使用できる、多くのアプリケーションがあります。たとえば、床配置図の図面では、オブジェクト・データは、使用される材料費を明示するために使用できます。そして、材料のリストは、カスタム・ソリューションで自動的に作り出すことができます。より具体的な例として、家のシンプルな地下室改修計画を見てみましょう。新しいラミネート床が、インストールされ、すべてのコンセントと照明設備を交換します。地階の材料費を見積もるために、フロアプランの縮尺図が作成されます。:
ここでは、照明器具、コンセント、照明スイッチが、適切なオブジェクトによって示されています。そして、それらのそれぞれは、"Comments"フィールド内の"Cost"データ・フィールドと項目の名前に、概算コストが割り当てられています。:
2つ以上のレイヤーは、地下室のためのサブフロア(4'x8'ボード)とラミネート・ウッド・フローリング(それぞれの板)をレイアウトします。:
それぞれのそれらのオブジェクトは、同じように、"Comments"と"Cost"フィールドをタグ付けします。
次に、VBAマクロを作成して、改修に必要な材料とそのコストのリストを自動的に生成するために、マクロ・マネージャーで、新しいVBAマクロ・プロジェクトを作成します:
VBAエディタでは、プロジェクトのために、新しいクラス・モジュールを追加します。(挿入 > クラス・モジュール)、それに、"Material"という名前をつけ、それのために、次の3つのプロパティを作成します。:
Public Name As String
Public Cost As Double
Public Count As Long
これらは、文書から取得したデータを蓄積するために使用されます。
次に、現在のCorelDRAW文書のすべてのオブジェクトから、材料データを収集するマクロを作成します。そして、使用される材料のリストとそれらのコストを作成します。:
Sub CreateBillOfMaterials()
Dim materials As Collection
Dim m As Material
Dim s As String, total As Double
Set materials = CollectMaterials(ActiveDocument)
s = "Count" & vbTab & "Cost" & vbTab & "Materials"
s = s & vbCrLf & "--------------------------------------------------------------"
For Each m In materials
s = s & vbCrLf & m.Count & vbTab & Format(m.Cost, "$#,##0.00") & vbTab & m.Name
total = total + m.Cost
Next m
s = s & vbCrLf & "--------------------------------------------------------------"
s = s & vbCrLf & "Total:" & vbTab & Format(total, "$#,##0.00")
MsgBox s
End Sub
CollectMaterials()ヘルパー関数を呼び出すことで、上記のマクロは、アクティブ文書内で、遭遇したすべての材料のリストを返す、使用される材料のリストを作成します。続いて、それは、すべての材料を調べます。そして、それらとそれらのコストを一覧にしたテキスト文字列を作成します。
CollectMaterials()ヘルパー関数は、以下のように、実装されます:
Private Function CollectMaterials(ByVal doc As Document) As Collection
Dim materials As New Collection
Dim p As Page, s As Shape
For Each p In doc.Pages
For Each s In p.Shapes
If s.ObjectData("Comments").Value <> "" Then
AddMaterial materials, s
End If
Next s
Next p
Set CollectMaterials = materials
End Function
それは、簡単に、文書のすべてのページとそれぞれのページ上のすべてのオブジェクトを調べます。そして、"Comments"データ・フィールドが設定されているオブジェクトを探します。それが見つかるとすぐに、オブジェクトのデータは、AddMaterial()ヘルパー・メソッドを使用して、材料のリストに追加されます。:
Private Sub AddMaterial(ByRef materials As Collection, ByVal s As Shape)
Dim m As Material
For Each m In materials
If m.Name = s.ObjectData("Comments").Value Then
m.Count = m.Count + 1
m.Cost = m.Cost + s.ObjectData("Cost").Value
Exit Sub
End If
Next
m = New Material
m.Name = s.ObjectData("Comments").Value
m.Cost = s.ObjectData("Cost").Value
m.Count = 1
materials.Add m
End Sub
このメソッドは、"Comments"と"Cost"データ・フィールドをオブジェクトから抽出します。続いて、材料のリストに、データを追加します。同じ名前を持つオブジェクト("Comments"フィールドの値)が、すでにリストに存在する場合、続いて、Countプロパティが、インクリメントされ、材料の全体の価格が、合計されます。それ以外の場合には、新しいエントリが、リストに追加されます。次に、地下室フロア・プラン文書を開いた状態で、このマクロを実行すると、次のメッセージが表示されます。:
プログラムに基づいたデータ(プロパティ・コレクション)
Programmatic Data (Properties collection)
CorelDRAW/Corel DESIGNER内の右側に、ユーザー・インターフェイス・サポートが組み込まれているため、きわめて使いやすい、オブジェクト・データ・マネージャーを使用して、データは、オブジェクトと関連付けられています。しかしながら、同じように、いくつかの制限があります:
- 長方形や曲線のような、Object Managerデータは、個々のオブジェクトにのみ、割り当てることができます。
- あなたは、カスタム・データを文書自体、あるいは、ページとレイヤーのような、構造要素に格納することができません。
- オブジェクト・マネージャー・データは、いくつかのきわめて基本型に制限されています。(主に数字と文字列)。そのため、あなたが、より複雑な構造化データを格納したい場合、あなたは、複数のデータフィールドを使用する必要があります。あるいは、データを文字列にエンコードします。
Object Managerのデータが、ユーザーに見えるようになっています。これが強みである一方で、アプリケーション・ユーザーが、カスタム・ソリューションによって挿入されたデータを表示、あるいは、編集できるようにしたくない場合があります。
上記の欠点の全ては、CorelDRAW/Corel DESIGNERのオブジェクト・モデルで、Document、Page、Layer、およびShapeクラスで使用できる、Propertiesオブジェクトによって解決されます。それぞれのPropertiesオブジェクトは、データの複数の部分を格納することができます。異なるソリューションが、互いのデータを上書きしないようにするために、それぞれのプロパティは、2つの要素で識別されます。:一意の文字列IDと整数インデックス。文字列IDは、具体的なソリューションの固有の一意の文字列にすることをお勧めします。一意性を保証する最も簡単な方法は、文字列IDのためにグローバル一意識別子(GUID)を使用することです。あなたは、整数インデックスを使用して、ソリューションに属するさまざまなプロパティを識別できます。たとえば、そのオブジェクトのPropertiesコレクション内のページ上の各オブジェクトの位置を記憶する簡単なマクロを作成してみましょう。それで、別のマクロを使用して、オブジェクトが文書内で誤って移動された後のオブジェクトの位置を復元できます。:
Private Const SolutionID As String = "41AC5941-219D-492C-896D-5D4D9EFABF5D"
Sub Store()
Dim s As Shape
Dim x As Double, y As Double
For Each s In ActiveSelection.Shapes
s.GetPositionEx cdrCenter, x, y
s.Properties(SolutionID, 1) = x
s.Properties(SolutionID, 2) = y
Next s
End Sub
Sub Restore()
Dim s As Shape
Dim x As Double, y As Double
For Each s In ActiveSelection.Shapes
If s.Properties.Exists(SolutionID, 1) And s.Properties.Exists(SolutionID, 2) Then
x = s.Properties(SolutionID, 1)
y = s.Properties(SolutionID, 2)
s.SetPositionEx cdrCenter, x, y
End If
Next s
End Sub
Sub Clear()
Dim s As Shape
For Each s In ActiveSelection.Shapes
If s.Properties.Exists(SolutionID, 1) Then s.Properties.Delete(SolutionID, 1)
If s.Properties.Exists(SolutionID, 2) Then s.Properties.Delete(SolutionID, 2)
Next s
End Sub
ここでは、store()マクロは、文書内のすべての選択されたオブジェクトを調べます。そして、shapeのPropertiesオブジェクト内のページの上の中心の位置を格納します。SolutionID文字列は、ObjectPositionsマクロに属するプロパティを識別するために使用されます。そして、property #1は、オブジェクトの位置の水平(X)座標を格納します。一方、プロパティ#2は、垂直(Y)座標を格納します。
Restore()マクロは、逆の操作を実行します。選択したオブジェクトごとに、オブジェクトが、以前の位置を保存している場合、オブジェクトをその場所に戻します。
最後に、Clear()マクロは、保存されているオブジェクトの位置を削除します。
アプリケーション・セッション・データ
Application Session Data
オブジェクト・データ・マネージャーとPropertiesコレクションの両方は、それらのデータを文書とその要素に格納します。多くのソリューションでは、マクロやプラグインが、再度呼び出されたとき、再利用するためにいくつかのデータを保存する必要があります。もちろん、データをファイルやシステム・レジストリに書き込むことで、ソリューションは、それらのデータを持続するために、カスタム実装を使用することができます。これは、実行できましたが、面倒で、エラーが発生しやすい。(あなたのソリューションが、書き込みアクセスできるファイルの場所を選択する必要があります。たとえば)。幸運なことに、CorelDRAW/Corel DESIGNERは、開発者にそのような機能を提供します。Applicationクラスは、2つのプロパティ、どの文書にも関連付けられていないデータを保存できる、GlobalUserDataとSessionUserDataを提供します。
文書のPropertiesオブジェクトとして、両方のオブジェクトは、同じインターフェイスに従います。それぞれのプロパティは、文字列ID/整数インデックスのペアで識別されます。SessionUserDataが、アプリケーション・シャットダウンに関して保存しませんが、CorelDRAW/Corel DESIGNERが、終了するとき、GlobalUserDataに格納されるプロパティは、ディスクの上に保存されます。そして、アプリケーションの実行中に、一時的な情報を保存するために使用できます。
たとえば、ユーザーにテキスト文字列を要求し、ページ上に、この文字列を持つ芸術的なテキストオブジェクトを作成する単純なマクロ:
Sub CreateTextObject()
Dim text As String
text = InputBox("Text", "Enter Text String")
If text = "" Then Exit Sub
ActiveLayer.CreateArtisticText 0, 0, text
End Sub
毎回、入力を提供するための空のテキスト・ボックスを持っている、InputBox()関数が、呼び出されます。:
しかしながら、あなたが、以前に入力した値をテキスト・ボックスに事前に入力する場合、あなたは、以前のテキスト文字列をどこかで保存する必要があります。続いて、次にマクロが呼び出されたとき、それを呼び出します。それは、GlobalUserDataとSessionUserDataの出番です。:
Sub CreateTextObject()
Dim text As String
If SessionUserData.Exists("MyCreateTextObjectMacro", 1) Then
text = SessionUserData("MyCreateTextObjectMacro", 1)
End If
text = InputBox("Text", "Enter Text String", text)
If text = "" Then Exit Sub
SessionUserData("MyCreateTextObjectMacro", 1) = text
ActiveLayer.CreateArtisticText 0, 0, text
End Sub
ここでは、私たちは、InputBox()で入力されたテキストをSessionUserDataオブジェクトに格納するためのMyCreateTextObjectMacroのproperty #1を作成しました。そして、テキスト文字列が、以前に保存されている場合、それは、デフォルトで、テキスト・ボックスの中に配置される文字列として、マクロの先頭で呼び出され、InputBox()関数に渡します。そして、マクロが、最後に実行されたとき、"Hello, world!"文字列が、入力されていた場合、続いて、マクロが起動されたときに、ダイアログ・ボックスに自動的に表示されます。:
SessionUserDataを使用することは、あなたが、CorelDRAWを終了して再起動する場合、マクロが使用する最後のテキスト文字列は、次にマクロが実行されるときに記憶されていないことを示しています。ただし、この動作が必要な場合、あなたは、上記の例では、SessionUserDataをGlobalUserDataに置き換えることができます。
ダウンロード・ソース:CustomData.zip