Utility-Objekt und SelectionSet

In der vergangenen Ausgabe unserer VBA-Einführung haben Sie ein wenig von der Entwicklungsumgebung kennen gelernt, einen Kreis vom Programm in AutoCAD zeichnen lassen und sogar ein erstes kleines Menü entwickelt. Wer sich etwas ernsthafter mit der VBA-Programmierung beschäftigt, wird immer wieder vor der Aufgabe stehen, bereits vorhandene AutoCAD-Elemente zu verarbeiten. Dafür gibt es verschiedene Möglichkeiten. Nachfolgend sollen zwei Wege beschrieben werden, nämlich die Klassen Utility und Selectionset.

Im letzten Teil der VBA-Einführung haben Sie bereits das Utility-Objekt zur interaktiven Koordinatenabfrage kennen gelernt. Neben verschiedenen anderen Methoden stellt es auch die GetEntity-Funktion zur Verfügung. Sie wird dazu benutzt, um den Anwender ein Zeichnungsobjekt auswählen zu lassen. Allerdings wirklich nur genau ein Element. Sollen mehrere Zeichnungsobjekte selektiert werden, gibt es dafür das anschließend etwas näher besprochene Selectionset. Um GetEntity zu testen, starten Sie AutoCAD, zeichnen einige Elemente (z.B. Kreise, Linien, Polylinien etc.) und rufen anschließend VBA mittels der Tastenkombination „Alt-F11“ auf.

Jetzt können Sie folgende kleine Prozedur schreiben, die Sie auffordert, ein Zeichnungselement zu selektieren und anschließend dessen Namen ausgibt.

Public Sub zz1()
Dim Auswahl As acadObject
Dim Punkt As Variant

Utility.GetEntity Auswahl, Punkt, "Wählen Sie ein Element"
MsgBox Auswahl.ObjectName

End Sub


In vielen Fällen ist allerdings mehr als ein Element in der Zeichnung auszuwählen. Mit der Klasse AcadSelectionSets werden Ihnen vielfältig einsetzbare Methoden an die Hand gegeben, um Zeichnungselemente interaktiv oder auch im Hintergrund zu selektieren. Um einen solchen Auswahlsatz anzulegen, sollte er zunächst mit einer Dim- oder Public-Anweisung deklariert werden.

Dim Sset as AcadSelectionset

Angelegt wird der Auswahlsatz mit folgender Programmzeile.

Set Sset1 = ThisDrawing.SelectionSets.Add("Auswahl1")

Nun können Sie Ihrem Auswahlsatz verschiedenste Elemente hinzufügen. Hier die dafür am häufigsten gebrauchten Methoden:
 

Select

Filtern von AutoCAD-Elementen im Hintergrund (also ohne Nutzereingabe).

SelectAtPoint

Auswahl eines Elements an einem bestimmten Punkt (Koordinate). Diese Anweisung ähnelt (!) der GetEntity-Methode, allerdings ohne Abtasten einer Koordinate durch den Nutzer.

SelectByPolygon

Auswahl von Elementen die innerhalb eins Polygons liegen

SelectOnSrceen

Auswahl von Elementen durch den Anwender

Neben den Besonderheiten jeder einzelnen Methode, haben alle eines gemeinsam. Die Elemente können auch noch nach verschiedenen Eigenschaften gefiltert werden. So ist es beispielsweise möglich, alle Polylinien der Zeichnung zu ermitteln, die auf einem bestimmten Layer liegen, oder alle Blöcke zu selektieren, die einen ganz bestimmten Einfügepunkt haben.

Zur Verdeutlichung ein erstes Beispiel, in dem Sie interaktiv mehrere Zeichnungselemente auswählen und deren Objektnamen in einer Message-Box zur Anzeige bringen. Zum Einstieg verzichten wir zunächst auf die genannte Filtermöglichkeit. Bevor Sie die Prozedur starten, sollten Sie natürlich erst verschiedene Elemente zeichnen.

Public Sub Elementliste()
Dim Sset As AcadSelectionSet
Dim Auswahl As acadObject
Dim Liste As String

Set Sset = ThisDrawing.SelectionSets.Add("Elemente1")
Sset.SelectOnScreen
For Each Auswahl In Sset
    Liste = Liste & vbCrLf & Auswahl.ObjectName
Next
MsgBox Liste
Sset.Delete

End Sub


Eingangs werden die erforderlichen Variablen deklariert. Mit Set Sset=… erzeugen Sie einen zunächst noch leeren Auswahlsatz. Die Zeile Sset.SelectOnScreen führt dann dazu, dass Sie in der AutoCAD-Kommandozeile aufgefordert werden, Objekte am Bildschirm auszuwählen. Bitte beachten Sie, dass diese Anweisung noch mit Filter-Parametern ergänzt werden kann, dazu gleich mehr.

Wenn Sie Ihre Auswahl am Bildschirm mit der rechten Maustaste oder der Eingabetaste abgeschlossen haben, wird in der folgenden For-Next-Schleife der Auswahlsatz Element für Element durchsucht. Mit jedem Schleifendurchlauf füllt sich die Liste um ein weiteres Element. Wenn die Schleife abgearbeitet ist, wird die gefüllte Liste in einer Messagebox zur Anzeige gebracht. Vor dem Abschluß der Prozedur erzwingt Sset.Delete das Löschen des Auswahlsatzes aus der Menge der SelectionSets. Erfolgt das nicht, würde beim nächsten Aufruf Ihres Programms eine Fehlermeldung erscheinen, die sagt, dass der Auswahlsatz bereits existiert.

Bitte die „Delete-Anweisung“ nicht mit der „Erease-Anweisung“ verwechseln. Letztere löscht den Inhalt des Auswahlsatzes (einschließlich der Zeichnungselemente), lässt ihn aber als dann leeres Selectionset in der Zeichnung. Am einfachsten, Sie probieren es selbst einfach aus.

Wie eingangs angedeutet, bietet das Selectionset die Möglichkeit, Elemente bei der Auswahl zu filtern, was ähnlich wie der FILTER-Befehehl von AutoCAD zu verstehen ist. Die folgende Prozedur wird das verdeutlichen. Sie ist ein wenig komplexer und arbeitet mit zwei Selectionsets.

Zeichnen Sie zunächst jeweils mehrere Polylinie auf den beiden Layern „Layer1“ und Layer2“. Die Aufgabe des Programms besteht grundsätzlich darin, die Gesamtlänge der Polylinien auf einem bestimmten Layer zu berechnen. Ein Ablauf könnte nun so aussehen (viele Wege führen zum Programm), dass alle Polylinien der Zeichnung gewählt werden, und aus dieser Menge die von Layer2 zur Berechnung genommen werden.

Public Sub Tool_LenPoly()
'Ermittlung der Länge von Polylinien
Dim Sset As AcadSelectionSet
Dim fCode() as Integer
Dim fWert as Variant
Dim selOb as acadObject
Dim Onam as String
Dim Gesamt as Double
Dim POLin as AcadPolyline
Dim LWLin as AcadLWPolyline

Set Sset = ThisDrawing.SelectionSets.Add("sset08")
ReDim fCode(6): ReDim fWert(6)
fCode(0) = -4: fWert(0) = "<AND"
fCode(1) = -4: fWert(1) = "<OR"
fCode(2) = 0: fWert(2) = "lwpolyline"
fCode(3) = 0: fWert(3) = "polyline"
fCode(4) = -4: fWert(4) = "OR>"
fCode(5) = 8: fWert(5) = "Layer1"
fCode(6) = -4: fWert(6) = "AND>"

Sset.Select acSelectionSetAll, , , fCode, fWert
Gesamt = 0
For Each SelOb In Sset
    If SelOb.ObjectName = "AcDb2dPolyline" Then
        Set PoLin = SelOb
        Gesamt = Gesamt + POLin.Length
    End If
    If SelOb.ObjectName = "AcDbPolyline" Then
        Set LwLin = SelOb
        Gesamt = Gesamt + LWLin.Length
    End If
Next
AnzPoly = Sset.Count
MsgBox (LaePol)
Sset.Delete

End Sub


Hier nun die Erklärung einiger Besonderheiten. Nach der schon bekannten Erzeugung eines Auswahlsatzes mit Set Sset = ThisDrawing.SelectionSets.Add("Auswahl") erfolgt die Definition des Filters. Er besteht immer aus zwei Komponenten. Erstens dem so genannten DXF-Gruppencode und zweitens dem eigentlichen Filterwert. Der Gruppencode ist vom Typ Integer und der Filterwert vom Typ Variant (siehe Deklarationen). In jedem Fall müssen es Arrays sein, deren Dimensionierung mit der Anzahl der Parameter identisch ist. Bitte beachten Sie, dass die Zählung üblicherweise bei 0 beginnt. Zum hoffentlich besseren Verständnis sei die Filterdefinition hier erst mal in einer logischen Operation dargestellt:

Auswahl = ((Objekttyp=“Polyline“ ODER Objekttyp=“LWPolyline“) AND Layer=”Layer2”)

Dementsprechend sieht Ihr Programm aus. Mit fWert(0) = "<AND" öffnen Sie die UND-Verknüpfung und in der folgenden Zeile die ODER-Verknüpfung. Der DXF-Code für logische Verknüpfungen ist in beiden Fällen „-4“. Die beiden nächsten Zeilen geben die Filterbedingungen für die Linientypen an. Hier ist der Gruppencode „0“ (für die Bezeichnung des AutoCAD-Elementtyps). Danach wird die ODER-Verknüpfung geschlossen und es folgt die Layer-Bedingung. Layernamen sind vom Code „8“. Letztlich wird die UND-Verknüpfung geschlossen.

Eine Übersicht über alle Gruppencodes finden Sie in der DXF-Hilfe unter dem Abschnitt „Gruppencodes in numerischer Reihenfolge“.

Nachdem Sie die Filterbedingung definiert haben, können Sie endlich alle Objekte auswählen. Das erfolgt mit Sset.Select acSelectionSetAll, , , fCode, fWert. Die allgemeine Syntax lautet „object.Select Mode[, Point1][, Point2][, FilterType][, FilterData]“. Nach der Select-Anweisung folgt als erster Parameter der Filtermodus, also der Mechanismus, nach dem Objekte ausgewählt werden. acSelectionSetAll sagt, dass alle Elemente der Zeichung einbezogen werden sollen. Alternativ könnten Sie den Bereich auch mit acSelectionSetCrossing oder mit acSelectionSetWindow auf einen durch die Punkte Point1 und Point2 definierten Bereich einschränken. In unserem Beispiel allerdings werden diese (optionalen) Parameter nicht angegeben, denn es sollen ja alle Elemente in der Zeichnung untersucht werden. Die letzten beiden Parameter verweisen nun auf die vorstehend definierten Filterbedingungen.

Analog dazu hätten Sie übrigens auch im ersten Beispiel die Bildschirmauswahl (SelectOnScreen) noch mit einem Filter einschränken können.

Was nun folgt, ist die Auswertung des Selektionsergebnisses. In der For-Next-Schleife wird jedes im Auswahlsatz enthaltenen Objekt weiter verarbeitet. Genauer gesagt, werden in einem Selectionset nicht die AutoCAD-Elemente selbst gespeichert, sondern nur Verweise auf diese Objekte.

Dazu muss zunächst der jeweilige Objektname bestimmt werden. Entsprechend dieses Namens unterscheidet die folgende Select-Case-Anweisung, wie mit dem Objekt zu verfahren ist. Handelt es sich um eine Autocad-2D-Polylinie wird, mit Set POLin = selOb zunächst ein entsprechendes Objekt erzeugt. Das ist erforderlich, um in der nächsten Zeile mit POLin.Length dessen Länge abzufragen und zu saldieren.

Analog dazu wird mit LWPolylinien verfahren, oder auch mit (im Beispiel nicht betrachteten) AutoCAD-Linien oder -3D-Polylinien.

Nachdem Sie das Ergebnis in einer Messagebox zur Anzeige gebracht haben, wird zum Schluss der Auswahlsatz wieder gelöscht.

Noch zwei letzte kleine Hinweise für heute. Erstens empfiehlt es sich, die Namen der Auswahlsätze in einer Zeichenketten-Variable zu speichern. Das spart eine lästige Fehlersuche bei geringfügigen Schreibfehlern.

Zweitens kann es bei längeren Programmen schon mal passieren, dass man das Löschen eines Auswahlsatzes vergisst, oder ein Programmbbruch dazu führt, dass ein bereits angelegter Auswahlsatz nicht gelöscht wird.

Dem schafft folgende Funktion Abhilfe, die vor der Erzeugung eines Selectionset zunächst testet, ob es schon vorhanden ist. Wenn ja, wird es gelöscht. Am Ende der Funktion kann es dann erzeugt werden.

Public Function ssetGen(setName As String) As AcadSelectionSet
Dim sCol As AcadSelectionSets
Dim SS As AcadSelectionSet

Set sCol = ThisDrawing.SelectionSets
For Each SS In sCol
    If SS.Name = setName Then
        sCol.Item(setName).Delete
        Exit For
    End If
Next
Set SS = sCol.Add(setName)
Set ssetGen = SS

End Function

Der Funktionsaufruf würde dann mit Set Sset = ssetGen(„Auswahl“) erfolgen. Viel Spaß beim ausprobieren.

Soweit für heute. Teil 3 finden Sie auf hier.

Wir sind Aussteller auf der DWA Landesverbandstagung Baden-Württemberg 2011 in Fellbach

Besuchen Sie Stand 94

© IBB INGENIEURBÜRO BATTEFELD 2009 - 2011
Neu auf der DWA Landesverbandstagung Baden-Württemberg 2011: Mobile Zustandserfassung mit Android Apps, Bricscad für Linux, AutoGIS Kanalinformationssystem
Bricscad V12 Sonderaktion mit 10% Rabatt auf Vollversion, Netzlizenz und Updates sowie kostenloser Download einer Testversion

AutoCAD® ist ein eingetragenes Warenzeichen der Autodesk Inc. USA - Bricscad TM ist Warenzeichen der Bricsys NV, Belgien.