Veni, Vidi, VISIO

Veröffentlicht: 18. Dez 2002 | Aktualisiert: 21. Jun 2004

Von Senaj Lelic

VISIO ist vielen Benutzern als vielseitiges und komfortables Programm für die Erstellung von Diagrammen und Zeichnungen bekannt. Erst zusammen mit einigen Zeilen VBA-Code aber lässt sich die volle Funktionalität von VISIO ausnutzen. Unter anderem die automatische Generierung von Zeichnungen, Verbindung mit Office-Anwendungen und die Visualisierung von Prozessen.

Auf dieser Seite

 Das Visio-Objektmodell
 Einer nach dem anderen
 Gruppenarbeit
 Aktiv werden
 Ab in die Zelle
 Den Meister gefunden
 Kleb' Dir eine
 Properties im Dutzend
 Netze malen
 Gemeinsam stark

Das Visio-Objektmodell

Die Benutzung von Visio-Objekten folgt dem üblichen OLE-Schema: zuerst benötigen Sie einen Verweis auf ein Objekt, dann kann mit den Methoden und Eigenschaften des Objekts gearbeitet werden.
Einen Verweis auf ein Objekt erhalten Sie in der Regel durch die Nutzung einer Eigenschaft eines Objektes, welches in der Hierarchie des Visio-Objektmodells höher angesiedelt ist. Ein Objektmodell ist die Auflistung aller Objekte, welche eine Anwendung über die Automatisierungsschnittstelle zur Verfügung stellt.
In VBA ist das grundlegende Objekt VISIO, die VISIO-Anwendung selbst. So kann mit dem Ausdruck Visio.Documents auf die einzelnen Dokumente innerhalb der laufenden Anwendung zugegriffen werden.
Abbildung 1 zeigt einen Ausschnitt aus dem Objektmodell von VISIO, das vollständige Modell finden Sie in der Online-Hilfe zu VISIO und als Datei im Verzeichnis VISIO\DVS.

Bild01

Bild 1 (ObjModel.wmf): Klar und strukturiert: das Objektmodell von VISIO.

 

Einer nach dem anderen

Einer der Vorteile des Objektmodells von VISIO gegenüber anderen OLE-Servern ist der klare Aufbau des Objektmodells. Basis für viele Elemente ist immer eine Collection mit dem Namen im Plural, welche dann die einzelnen Elemente des Namens enthält.
Ein Visio-Dokument kann aus mehreren Seiten bestehen (ähnlich den Arbeitsblättern in Excel), daher heißt die entsprechende Eigenschaft des Document-Objektes auch Pages. Diese liefert eine Collection von Page-Objekten. Auf einer Seite liegen mehrere Shapes, weshalb über die Eigenschaft Shapes eines Page-Objektes auf die Collection der Shape- Objekte zugegriffen werden kann.
Einige Methoden und Eigenschaften liefern keine Collections, sondern ein Array von Werten auf einmal. Ein Beispiel hierfür ist die Methode GetNames der Masters-Collection. Um die Namen aller MasterShapes eines Dokumentes auszulesen, können Sie folgendermaßen vorgehen:

Sub GetMasters()
    Dim MasterNames() As String
    Visio.Documents( _
    "Clipart.vss").Masters.GetNames _
    MasterNames
    For i = LBound(MasterNames) _
    To UBound(MasterNames)
        Debug.Print MasterNames(i)
    Next i
End Sub

 

Gruppenarbeit

Grundbestandteil einer VISIO-Zeichnung sind Shapes. Im einfachsten Fall besteht ein Shape aus einer Linie mit einem Anfangs- und einem Endpunkt. Allerdings wird auf komplexe Shapes genauso einfach zugegriffen wie auf die einfachsten Shapes: jedes Shape.Objekt besitzt die Möglichkeit, mit anderen zu einer Gruppe kombiniert zu werden. Das Ergebnis ist wieder ein Shape.Objekt, nämlich die gerade erzeugte Gruppe. Daher besitzt jedes Shape.Objekt auch selbst eine Eigenschaft Shape, welche bei einer Gruppe die einzelnen Shape-Objekte enthält, aus denen die Gruppe besteht.

 

Aktiv werden

Zur Erleichterung der Programmentwicklung existieren in VBA bei Visio einige Objekte, welche den Zugriff auf gerade aktive Dokumente und Seiten sehr erleichtern. Dies sind ActiveWindow, ActiveDocument und ActivePage.
Der Vorteil dieser Objekte liegt darin, dass Sie sich beim Programmieren sehr einfach auf die jeweils aktive Seite bzw. das gerade aktive Dokument beziehen können. Geben Sie zum Testen das folgende Kommando im Direktfenster des VBA-Editors ein:

Print ActiveDocument.Name,  _ 
ActiveDocument.Title

Damit erhalten Sie sowohl den Dateinamen als auch den Titel (der Dokumenteneigenschaften) des aktiven Dokumentes.

 

Ab in die Zelle

Einer der Gründe für die Vielseitigkeit von VISIO ist das zugrunde liegende Design der Shapes. Intern werden alle notwendigen Daten in einem so genannten ShapeSheet gespeichert, das ist eine Art von Kalkulationsblatt für die Zeichnungselemente. Damit lässt sich beispielsweise ohne eine Zeile Programmierung festlegen, dass ein Shape immer doppelt so breit wie hoch dargestellt werden soll. Auch Datenfelder, Farben und alles andere sind letztlich nur Formeln im ShapeSheet. Natürlich können Sie mit VBA auf diese Zellen und Zeilen zugreifen und so auch Datenfelder hinzufügen oder das Verhalten von Shapes ändern.
Um das Shape mit dem Namen Anfang blau einzufärben, benötigen Sie zuerst eine Referenz auf das Shape:

Dim vShape as Visio.Shape
vShape = ActivePage.Shapes("Anfang")

Jetzt wird aus dem ShapeSheet ein Verweis auf die Zelle mit dem Namen FillForeGnd geholt, welche die Farbe des Füllvordergrundes steuert:

Dim vCell As Visio.Cell
Set vCell = vShape.Cells("FillForeGnd")
vCell.Formula = "RGB(51;152;204)"

Wie Sie sehen, ist neben der Angabe der Farbnummer für die vordefinierten Farben auch die Verwendung der Funktion RGB zulässig, um jede Farbe im 24Bit-Farbraum zu definieren.
Eine Auflistung aller Zellen und ihrer Namen sowie der Abschnitte des ShapeSheets erhalten Sie aus der Online-Hilfe.

 

Den Meister gefunden

Um die Erstellung von Zeichnungen aus standardisierten Komponenten zu beschleunigen, stellt VISIO so genannte MasterShapes in eigenen Dateien zur Verfügung. Ein MasterShape ist eine Gruppe von Zeichnungselementen, welche einfach per Drag & Drop auf die Zeichenfläche gezogen wird und dadurch eine Kopie oder eine Instanz von sich erzeugt. Andere Programme besitzen unter dem Namen Symbolbibliothek oder Vorlagen ein ähnliches Konzept.
In VBA erfordert das Plazieren eines solchen Shapes über einen Master nur drei Zeilen:

Set vMasters = Visio.Documents( _
"Basic Network Shapes.vss").Masters
set vMaster = vMasters( _
"Desktop PC")
set vShape =  _
ActivePage.Drop(vMaster,10.0,2.0)

Zuerst wird in einer Objektvariablen das Objekt mit der Masters-Collection gespeichert. Diese Collection enthält alle MasterShapes der angegebenen Datei (diese Dateien werden in VISIO als 'Stencils' oder 'Schablonen' bezeichnet und haben die Erweiterung .VSS).
Als zweiter Schritt wird eine Objektvariable erzeugt, welche auf ein ganz bestimmtes MasterShape zeigt, hier das mit dem Namen "Desktop PC".
Schließlich wird mit der Methode Drop eines Page-Objektes (hier der aktiven Seite) eine Instanz des Masters auf der Zeichenfläche platziert.
VISIO bietet für das Umrechnen von Werten, welche das System liefert, eine ganze Reihe Einheiten, von Inches über Millimeter bis zu Pixeln.
Beim Ablegen eines neuen Shapes auf dem Zeichenblatt aber akzeptiert die Methode Drop nur Werte in der Einheit Inches, also werden zwei Routinen für die Umrechnung in das metrische System benötigt:

' Umrechnung mm in Inches
Function mm2inch(  _
ByVal mm As Double) As Double
   mm2inch = mm / 25.4
End Function
' Umrechnung Inches in mm
Function inch2mm(  _
ByVal inch As Double) As Double
   inch2mm = inch * 25.4
End Function

Besonders leistungsfähig ist VISIO aber dadurch, dass die Verbindung eines so erzeugten Shapes zu seinem Master erhalten bleibt. Beim Ablegen des Masters auf der Zeichenfläche werden Ereignisse ausgelöst, auf die ein VBA-Modul reagieren kann.
Zusätzlich lassen sich über das Konzept des ShapeSheets jederzeit sowohl Master als auch 'normale' Shapes durch benutzerdefinierte Datenfelder erweitern. So ist es beispielsweise kein Problem, das ShapeSheet um ein Datenfeld für die IP-Adresse eines Computers zu ergänzen und dann per VBA darauf zuzugreifen:

set vShape =  _
ActivePage.Shapes("HP9000")
Set vCell = vShape.Cells("Prop.IP")
vShape.text = vCell.Formula

 

Kleb' Dir eine

Verschiedene Shapes lassen sich in VISIO durch so genannte Verbinder dauerhaft 'verkleben'. Wird nach einer solchen Operation eines der verbundenen Shapes bewegt, so ändert sich der Verbinder entsprechend mit.
Für diese Funktionalität existiert in VBA die Methode GlueTo:

set vArrow =  _
ActivePage.Shapes("Result")
set vShape =  _
ActivePage.Shapes("Process.4")
vArrow.Cells("EndX").GlueTo _
vShape.Cells("Connections.X3")

Dies verbindet den Endpunkt des Verbinders mit dem Namen Result und dem dritten Verbindungspunkt des Shapes. Des Weiteren wird er mit dem Namen Process.4 verbunden, wobei eine evtl. bereits vorher bestehende Verbindung des Pfeils gelöst wird.

 

Properties im Dutzend

Viele VISIO-Zeichnungen, die als Dokumentation begonnen wurden, leiden daran, dass nach einiger Zeit die eine oder andere Eigenschaft oder Beschriftung fehlt. Dem lässt sich für eine beliebige Anzahl von Shapes auf einer Seite ganz leicht mit ein paar Zeilen VBA-Code abhelfen.
Im ShapeSheet besteht wie bereits erwähnt die Möglichkeit, eigene Zellen zu erstellen und dort Daten zu einzelnen Shapes abzulegen. Genau dies soll unser Programm erledigen: bei allen Shapes einer Seite, welche noch keine benutzerdefinierte Eigenschaft Inventarnummer haben, soll dies ergänzt werden.

Sub MakeProperties()
    Dim vShape As Visio.Shape
    Dim i, j As Integer
    For i = 1 To _
    ActivePage.Shapes.Count
        Set vShape = _
        ActivePage.Shapes(i)
        If Not vShape.CellExists(  _
        "Prop.Inventarnummer", _
        True) Then
            If Not _
            vShape.SectionExists( _
            visSectionProp, True) Then
            j = vShape.AddSection( _
            visSectionProp)
                   End If
        j = vShape.AddNamedRow( _
        visSectionProp, _
        "Inventarnummer", 0)
        vShape.Cells( _
       "Prop.Inventarnummer.Prompt" _
        ).Formula = "=" & Chr(34) _
       & "Bitte Inv.-Nr. eingeben " _
       & Chr(34)
       vShape.Cells(  _
       "Prop.Inventarnummer.Type" _
       ).Formula = 0
      End If
   Next i
End Sub

Nach dem Durchlaufen dieser Prozedur besitzt jedes Shape einen Eintrag im ShapeSheet, der in der Zeichnung über das Kontextmenü und die Option Shape / Custom Properties bzw. Shape / Datenfelder ... aufgerufen werden kann.

Bild02

Bild 2 (screenshot2.tif): Verwendung von Custom Properties / Datenfeldern

 

Netze malen

Als ein letztes, praktisch einsetzbares Beispiel für die VBA-Programmierung von VISIO werden wir Inventurdaten eines Netzwerkes aus einer Datenbank auslesen und per Programm eine Zeichnung dieses Netzwerks in VISIO generieren.
Natürlich ist dies noch kein Ersatz für professionelle Software, aber bereits ein ganz guter Ausgangspunkt für eine automatisierte Dokumentation 'on demand'.
Die Daten liegen für unser Beispiel in einer MS Access Datenbank mit dem Namen machines.mdb und besitzen den in Tabelle 1 gezeigten Aufbau:

Bild03

Bild 3 (Tabelle1.tif): Aufbau der Datenbank für die Inventardaten

Die Daten werden mit einer SQL-Abfrage ausgelesen und enthalten unter anderem eine Spalte Type, in der das gewünschte MasterShape angegeben wird. So enthält die Zeichnung später gleich die richtigen Bildsymbole für Server und Arbeitsplatzrechner.

Dazu wird eine Reihe von Deklarationen benötigt, um die entsprechenden Variablen zu erhalten:

' der SQL-String für die Abfrage
Dim sSQL As String
sSQL = "SELECT * FROM machines"
' für den Zugriff aus die MDB-Datei
Dim rs As Recordset
Dim db As Database
' Visio-Variablen
Dim vShape As Visio.Shape
Dim vMasters As Visio.Masters
Dim vMaster As Visio.Master
Dim vDoc As Visio.Document
' Hilfsvariablen
Dim xpos as Integer
Dim ypos as Integer
Dim sMasterName As String
Dim sText As String

Um die entsprechende Datei mit den MasterShapes zu laden, die als Vorlage dienen, wird mit der Methode OpenEx die Datei geöffnet und als angedocktes Fenster und schreibgeschützt neben unserem Zeichnungsfenster dargestellt.
Danach wird in der Variablen vMasters der Verweis auf die Collection mit den MasterShapes gespeichert.
Jetzt können wir darangehen, die Abfrage der Datenbank durchzuführen und die Zeichnung dynamisch zu erzeugen.
Alles was noch erledigt werden muss, ist die Definition des Beginns der Zeichenoperation auf der Seite. VISIO verwendet ein 'normales' Koordinatensystem, das heißt der Nullpunkt einer Seite liegt links unten. Über die Eigenschaft PaperHeight ist es ein Leichtes, diese Daten zu erhalten und die Position für das erste Shape festzulegen:

Set vDoc = Visio.Documents.OpenEx( _
"Basic Network Shapes.VSS", _
visOpenRO + visOpenDocked)
Set vMasters = Visio.Documents( _
"Basic Network Shapes.vss").Masters
Set db =  _ OpenDatabase("machines.mdb", , True)
Set rs = db.OpenRecordset(sSQL)
ypos = ActiveDocument.PaperHeight( _
"mm") - 40  ' 4 cm vom oberen Rand
xpos = 20   ' 2 cm vom linken Rand
rs.MoveFirst

Jetzt wird in einer Schleife durch das RecordSet gelaufen und jedes Mal ein Satz aus der Tabelle der Datenbank gelesen. Der Name für das benötigte MasterShape steht in der Spalte Type (in einem Programm für den tatsächlichen Einsatz wird man diese Information nicht immer so einfach erhalten, sondern unter Umständen über eine Umsetzung den Namen des Mastershapes erst errechnen müssen).
Mit der Methode ActivePage.Drop wird eine Instanz des Mastershapes auf der Zeichenfläche platziert und dann die Beschriftung (die Eigenschaft Text eines Shapes) aus den restlichen Spalten der Tabelle erzeugt.
Jetzt muss nur noch der Zeiger im RecordSet weiterbewegt werden, bis das Ende der Tabelle erreicht wurde.

Do
    sMasterName = _
    rs.Fields("Type").Value
    Set vMaster = _
    vMasters.Item(sMasterName)
    Set vShape = _
    ActivePage.Drop(vMaster, _
    mm2inch(xpos), mm2inch(ypos))
    sText =  _
    rs.Fields("Manufacturer").Value  _
    & " " &   _
    rs.Fields("ModelNumber").Value
    sText = sText & Chr(13) & Chr(10) _
    & rs.Fields("IPAddr").Value
    vShape.Text = sText
    xpos = xpos +   _
    vShape.Cells("Width").Result("mm") _
    + 15
    rs.MoveNext
Loop Until rs.EOF

Alles, was jetzt noch zu tun bleibt, ist das Schließen der Verbindung zur Datenbank und sicherheitshalber das Setzen der Objektvariablen auf Nothing.

rs.Close
db.Close
Set rs = Nothing
Set db = Nothing

Als Ergebnis erhalten wir dann die in der Abbildung gezeigte Ausgabe, aktuell aus der Datenbank generiert.

Bild04

Bild 4 (screenshot1.tif): Das Ergebnis: eine programmerzeugte Ansicht der LAN-Datenbank.

 

Gemeinsam stark

Das Geheimnis erfolgreicher VBA-Programmierung für VISIO ist also gar kein solches. Alles, was Sie benötigen, finden Sie bereits vor: ein gut strukturiertes und leicht erfassbares Objektmodell, eine große Menge von bereits mit Zusatzfeldern versehenen MasterShapes und dazu das extrem flexible Konzept des ShapeSheets.
Viele Dinge lassen sich zwar bereits entweder mit VBA- Makros oder über das ShapeSheet erledigen, aber erst die Kombination der beiden Konzepte erlaubt es, VISIO beispielsweise als Online-Netzwerkvisualisierungstools zu benutzen.
Natürlich kann im Rahmen eines Artikels nicht das gesamte Objektmodell und schon gar nicht jede Zeile des ShapeSheets vorgestellt werden, aber Sie haben sicherlich bereits jetzt einen Einblick in die grenzenlosen Möglichkeiten von VISIO erhalten.

Anmerkung
Die Beispiel- Quellcodes gehen von einem englischen VISIO aus, werden aber genauso unverändert auf einer deutschen VISIO- Version laufen.