対象シェイプを補足する

操作対象のシェイプを補足する(更新中・リンク先が無い場合があります。)

VBAによってPage上のShapeを操作する場合、まず対象のShapeを、人間がするように映像データとしてではなく、文字列として捉える必要があった。
ま、何をするにも操作対象を指定できなくてはお話にならないというわけだ。
というわけで、この方法の調査は比較的序盤に行う必要があった。

まとめ

まだまとめきれてないデス。






オブジェクトIDを使用する方法

Visioにしろ、Excelにしろ、VBAの勉強において誰もが通る道として、ユーザーの操作を記録してくれるマクロが記述したコードを研究する方法があるわけだが、そこで最初に見つけた『オブジェクトID』を使用する方法から調査、記録してゆく。

前提知識

オブジェクトIDがなんなのかわからなければお話にならない。
オブジェクトIDは以下の手順で確認できる。
  1. 対象のシェイプを右クリック
  2. 表示されたコンテキストメニューの[書式]→[オブジェクト情報]をクリック
  3. 表示された「オブジェクト情報」ウインドウの一番上にある「ID」項目に記載の番号を確認する。

そして、このオブジェクトIDは以下の規則に従っている事がわかった。
  • ページ上にドロップされた順に1から割り振られる。
  • 一度そのシェイプに割り振られたIDは他の編集操作によって変化しない。
  • シェイプを削除すると、そのシェイプで使用していたIDは解放され、次にドロップされたシェイプで使用される。

まあ、例外もあるのだろうが、それは追々補足してまとめてゆけばよい話なので、この認識で話を進める。


コードを使用した対象シェイプの捕捉

では実際にこのオブジェクトIDを使用して対象シェイプをVBAのソースコードから指定してみる。
もっと噛み砕いて言えば、通常マウスを使って対象シェイプをクリックして選択する行為をVBAコードに置き換えてみる。

  • オブジェクトとして取り扱う例
オブジェクトとして……この方法を採用するメリットは複数の要素に対して変更を加える時など、複雑な処理をする時だろうか。
Visio基礎知識で触れているが、Visio VBAにおいて変更を加えることができるほとんどすべての要素は階層構造で指定する事になるが、シェイプを指定しようと思うと思いのほか階層が深くなり、毎回変更を加えようと思うたびにそのすべてを記述する(フルパスで指定する)のはダルい。
そこで代替テキストとしての変数を宣言し、その変数に対して変更を加える事で処理内容の簡略化を図り、動作の把握と設計を容易にする。

以下は対象シェイプに既に記述されている文字列のうち、指定範囲を指定したテキストと置き換える操作をマクロとして記録したものだ。
Sub Macro1()
    Dim vsoCharacters1 As Visio.Characters
    Set vsoCharacters1 = Application.ActiveWindow.Page.Shapes.ItemFromID(3).Characters
    vsoCharacters1.Begin = 2
    vsoCharacters1.End = 5
    vsoCharacters1.Text = "test"
End Sub

※Visio 2007ならそのまま使えるハズだが、あらかじめオブジェクトID:3を持ったシェイプを用意し、その中に6文字以上文字列を記述しておく必要がある。ほかのバージョンについては知らん。
※マクロを使用していて、"Macro1"がすでに登録されているなら、適当な名称に変更して貼り付ける事。



対象のシェイプをオブジェクト(複数のデータを保持する要素)として取り扱う場合は、まず対象のシェイプを「これからこのシェイプをVBAではオブジェクトとして取り扱うよー」と宣言する必要がある。
そのために必要な記述が以下の部分だ。
Dim vsoCharacters1 As Visio.Characters
Set vsoCharacters1 = Application.ActiveWindow.Page.Shapes.ItemFromID(3).Characters

要するに"Visio.Characters"型の変数"vsoCharacters1"という入れ物を用意(変数を宣言)して、ここに"Shapes"クラスの"ItemFromID(3)"プロパティの"Charactors"プロパティを放り込んでいる。
以後、"vsoCharacters1"変数は"Application.ActiveWindow.Page.Shapes.ItemFromID(3).Characters"というオブジェクトとして取り扱うことができるようになるわけだ。
それぞれのプロパティやら型やらの意味はリファレンスに任せるとして、まずは雰囲気を掴みたい。
この時、"ItemFromID(3)"の()内にある"3"という数字がオブジェクトIDという事になる。
ここから逆説的に"ItemFromID"プロパティはオブジェクトIDによりシェイプを一意に指定するためのプロパティであることがわかる。
この数字の"3"のおかげで、ページ上にいくつのシェイプが配置されていようとも、"3"というオブジェクトIDを持つ一つのシェイプを指し示すことができるというわけだ。

その後、このシェイプに操作を加えたいなら、
vsoCharacters1.Begin = 2 (=既存文字列がある場合、カーソル開始位置の指定)
vsoCharacters1.End = 5 (=既存文字列がある場合、カーソル終了位置の指定)
vsoCharacters1.Text = "test" (=挿入する文字列)

などとして、変更を加えたいオブジェクトのプロパティを指定して、そこに対して値を代入する事でシェイプの各要素を操作する事になる。
ちなみに、上記マクロを実行すると、既存文字列の冒頭3~5文字目までが"test"文字列と置き換わる。
まったく文字列の無いシェイプに新規に文字列を挿入するなら、以下の通りだ。
vsoCharacters1.Begin = 0
vsoCharacters1.End = 0
vsoCharacters1.Text = "test"

マクロでは上記のように記録されるが、実際には
vsoCharacters1.Text = "test"

だけで事足りる。
んまあ、どちらがより『美しい』のかは私には判断がつかないが、定義する事で起こる不具合より、定義しないで起こる不具合の方が多い気がするから前者のが良いのかなぁ?
常に何もテキストが無いシェイプに文字を入力するような状況なら・・・とか、使われ方にもよるんだろうけどね。


  • 操作対象を選択状態にしていじくる場合
VBAでは『選択状態(選択範囲)』を一つのオブジェクトとして取り扱う事ができるらしい。
『選択状態』というのは概念であるから、それをオブジェクトとして取り扱うというのはしっくりこないが、『選択状態』が発生するためには選択する対象が必要であって、『選択状態』は必然的に『選択された対象』と同義になる。

簡単に言えば、先の手順で入れ物に放り込んだ(変数に代入した)要素そのものを、操作を行うたびに指定して変更する事になる。
この方法のメリットはどのシェイプに対しての操作かが、ソース上から判別しやすいという点だろうか。
デメリットは当然、複雑な処理になるとイチイチ指定するたびに長々と対象要素を指定しなくてはならないため、ダルいという事だ。
簡単な操作をVBAで自動化する際にはむしろこちらの方が後々の修正の際に楽かもしれない。

以下はすでに配置されたシェイプのうち、指定したシェイプを移動する操作をマクロとして記録したものだ。
Sub Macro3()
    ActiveWindow.DeselectAll
    ActiveWindow.Select Application.ActiveWindow.Page.Shapes.ItemFromID(1), visSelect
    Application.ActiveWindow.Selection.Move 1.692913, 0.019685
End Sub

各行の意味としては
Sub Macro3()
    現在アクティブなウインドウにおけるシェイプの選択を全て解除
    対象シェイプを選択状態に追加(オブジェクトIDは"1")
    選択状態にあるシェイプを指定座標に移動
End Sub

とまあ、シンプルな流れだ。

本セクションのテーマであるシェイプの指定は03行目になる。
03     ActiveWindow.Select Application.ActiveWindow.Page.Shapes.ItemFromID(1), visSelect

ちなみに上記行は以下のように書き換える事も可能。
03     Call ActiveWindow.Select(Application.ActiveWindow.Page.Shapes.ItemFromID(1), 2)
※この記述の違いについての説明はSubプロシージャを参照。

Selectメソッドを使用してオブジェクトID:1を持つシェイプを選択状態に遷移させている。
そして、04行目で選択状態を指定座標へ移動させる、すなわち選択したシェイプを移動させているわけだ。

この方法ではよりユーザーの操作に近い方法でシェイプを補足している点が特徴的だろう。
選択範囲をオブジェクトと見なせば、前項で解説したような使用方法も適用できるのかもしれない。


  • 直接対象シェイプのプロパティをいじる方法

以下更新中。


最終更新:2013年05月23日 15:55