Im vorigen Kapitel ging es um erste Versuche, sich im Baum
der Objekte zurechtzufinden. Um z.B. herauszufinden, welche Farbe
für Layer "0" eingestellt ist, haben wir diese Funktion benutzt:
(defun test6( / )
(vl-load-com)
(vlax-get-property
(vlax-invoke-method
(vlax-get-property
(vlax-get-property
(vlax-get-acad-object)
"ActiveDocument"
)
"Layers"
)
"Item"
"0"
)
"Color"
)
)
(test6) = > 7
In diesem Kapitel soll es nun darum gehen, wie man einen
solchen Wust von Code vermeiden kann - es gibt kürzere Wege,
um herauszufinden, dass der Layer weiss ist. Und wie können wir
das bewerkstelligen? VisualLisp liefert uns dazu ein ganzes
Paket Funktionen, die das mühsame Hangeln von Objekt zu Objekt
vermeiden und uns mehr oder weniger direkt zum Ziel bringen.
Vielleicht werden Sie jetzt aufstöhnen und fragen: 'Und warum
dann erst so umständlich, wenn es auch viel einfacher geht?'
Zwei Gründe gibt es dafür: Die Struktur dieses Baums (und damit
die Objektstruktur von AutoCAD) muss man einfach verstanden
haben, sonst kann man keine ActiveX-Programme schreiben. Dieser
Grund sollte einleuchtend sein. Der zweite Grund ist der, dass
es für die Abkürzungs-Funktionen keine Dokumentation gibt!
Vielleicht existiert sie ja, aber ich habe bisher keine gefunden.
Alle diese Funktionen, um die es hier geht, haben den Namenspräfix
(vla-...). Es gibt eine Menge davon, wieviele es wirklich
sind, werden wir in diesem Kapitel noch ermitteln. Sie werden
durch den obligatorischen Aufruf von
(vl-load-com) erzeugt
und können ab dann benutzt werden. Infolge der nicht vorhandenen
Dokumentation muss man sich allerdings Anzahl und Art der
Argumente selbst zusammenreimen - das bedeutet, man muss sich
im Objektbaum auskennen und dort nachschlagen.
Die Argumente sind allerdings nicht das Problem - schwieriger
ist es zunächst einmal, herauszufinden, welche Funktionen es da
überhaupt gibt. Man kann ja nicht in einer Liste suchen und
dann irgendwann sagen: "Das könnte die sein, die ich gerade
brauche!". Andererseits kann man sie auch sicherlich nicht aus
Bespielprogrammen auswendig lernen - vielleicht hat man alle
'normalen' Lisp-Funktionen im Kopf, aber das sind einfach zu
viele!
Wie kann man denn nun überhaupt feststellen, was es da gibt?
Uns bleibt nur ein Blick in die Symboltabelle des Lisp-Interpreters.
Dafür gibt es ja die Funktion mit dem netten Namen
(atoms-family).
Bei dieser Funktion kann man über das Argument steuern, ob die
Symbol-Namen als Zeichenketten oder als Symbol aufgelistet bekommt.
Damit wir mit Hilfe von
(substr) die vla-Funktionen
herausfiltern können, entscheiden wir uns für Zeichenketten.
(defun get-vla-functions( / rl)
(vl-load-com)
(vl-sort
(vl-remove-if-not
(function
(lambda(name / )
(= (strcase(substr name 1 4)) "VLA-")
)
)
(atoms-family 1)
)
'<
)
)
Zunächst ein paar Worte zu dieser Funktion: Wenn auch einige mit
mit dem Präfix
(vl-...) beginnende Funktionen darin vorkommen,
geht es doch in keiner Weise um ActiveX. Auch wenn
(vl-sort)
und
(vl-remove-if-not) so heissen, sind es doch 'ganz normale'
Lisp-Funktionen - nur eben neu hinzugekommen mit VisualLisp.
Bei
(function) hat man aus irgendwelchen Gründen auf den
Präfix verzichtet.
(function) ist ein
(quote) mit
Zusatzwirkung: Es ist ein Hinweis, dass der quotierte Ausdruck
eine Lambda-Funktion ist. Der VisualLisp-Compiler wird die Funktion
dann zu Bytecode mitkompilieren - bei Verwendung von
(quote)
tut er das nicht. Dies bedeutet aber auch, dass dieser Ausdruck zur
Laufzeit dann nicht mehr veränderbar ist.
Kurz und knapp: Die Funktion erstellt eine Liste aller Symbole in
der Symboltabelle und filtert dann diejenigen heraus, die mit dem
Präfix
(VLA-...) beginnen. Dabei auch gleich noch ein Wort
zur Groß-/Kleinschreibung der Funktionen, Symbole, Konstanten von
ActiveX: Sie spielt keinerlei Rolle. Im Speicher (und damit auch
in der Symboltabelle) wird sowieso alles wie gewohnt in
Grossbuchstaben umgesetzt - denken wir jedenfalls! Die
ActiveX-Funktionen akzeptieren übrigens die Namen
von Eigenschaften sowohl als Zeichenkette als auch als Symbol:
; String-Schreibweise
(vlax-get-property
(vlax-get-acad-object)
"ActiveDocument"
)
; Symbol-Schreibweise
(vlax-get-property
(vlax-get-acad-object)
'ActiveDocument
)
; Gross oder klein spielt...
(vlax-get-property
(vlax-get-acad-object)
"ACTIVEDOCUMENT"
)
; keinerlei Rolle...
(vlax-get-property
(vlax-get-acad-object)
'activedocument
)
; so ist es am lesbarsten
(vlax-get-property
(vlax-get-acad-object)
'ActiveDocument
)
Aber nun zurück zu unserer Familienforschungs-Funktion. Die
Ausgabe ist so lang, dass AutoCAD sie nicht einmal in ganzer
Länge im Textfenster ausgibt. Wir testen also einmal mit
(length), um wieviele Funktionen es überhaupt geht:
(length(get-vla-functions))
=> 1163
Diese Zahl wird bei mir unter AutoCAD 2002 ausgegeben, und da
AutoDESK das komplette VisualLisp-Paket aus 2000i ohne jegliche
Veränderung (d.h. auch ohne Bugfixes usw.) übernommen hat, dürfte
die Zahl auch für AutoCAD 2000i gültig sein. Unsere Funktion ist
also schon mal als Ansatz zu sehen, aber um damit arbeiten zu
können, ist das Ergebnis viel zu unhandlich.
Wir schalten also noch eine Stufe davor. Eine Funktion muss her,
die die ausgegebenen Funktion noch einmal nach Suchkriterien
filtert - wenn uns also z.B. das Stichwort 'Layer' interessiert,
muss die Funktion uns alle VLA-Funktionen ausgeben, die die
Zeichenfolge 'Layer' enthalten.
(defun find-vla-functions(pattern / )
(mapcar'read
(vl-remove-if-not
(function
(lambda(name / )
(wcmatch name
(strcat "*"(strcase pattern)"*")
)
)
)
(get-vla-functions)
)
)
)
(find-vla-functions "layer")
= > (vla-get-ActiveLayer
vla-get-DefaultPlotStyleForLayer
vla-get-Layer
vla-get-LayerOn
vla-get-Layers
vla-get-XRefLayerVisibility
vla-put-ActiveLayer
vla-put-DefaultPlotStyleForLayer
vla-put-Layer
vla-put-LayerOn
vla-put-XRefLayerVisibility)
Welche Überraschung - nicht, dass diese Funktionen
ausgegeben wurden: Das war zu erwarten. Aber dass sie
(mit
(read) in Symbole konvertiert) nicht in
Grossbuchstaben umgesetzt werden, das ist die Überraschung.
Bei ActiveX hört eben alles auf - auch die Aussage des
Handbuchs, dass Symbole zwar 'case insentitive' eingegeben
werden können, dass die Verarbeitung und Ausgabe jedoch
immer in Großbuchstaben erfolgen, wird durch die
ActiveX-Schnittstelle ausgehebelt.
Zurück zu dem, was wir eigentlich wollen - Verkürzung des
ActiveX-Codes. Kehren wir zu einem Beispiel aus dem
Vorkapitel zurück: Es soll die Farbe des Layers "0"
ermittelt werden. Die Funktion, die wir suchen, ist schnell
gefunden, es kann sich nur um
(vla-get-ActiveLayer)
handeln. Eine Funktion, mit der wir die Farbe von etwas
auslesen können, finden wir auch:
(find-vla-functions "color")
=> (vla-get-AutoSnapMarkerColor
vla-get-AutoTrackingVecColor
vla-get-Color
vla-get-DimensionLineColor
vla-get-ExtensionLineColor
vla-get-GraphicsWinLayoutBackgrndColor
vla-get-GraphicsWinModelBackgrndColor
vla-get-GripColorSelected
vla-get-GripColorUnselected
vla-get-LayoutCrosshairColor
vla-get-ModelCrosshairColor
vla-get-TextColor
vla-get-TextWinBackgrndColor
vla-get-TextWinTextColor
vla-get-TrueColorImages
vla-put-AutoSnapMarkerColor
vla-put-AutoTrackingVecColor
vla-put-Color
vla-put-DimensionLineColor
vla-put-ExtensionLineColor
vla-put-GraphicsWinLayoutBackgrndColor
vla-put-GraphicsWinModelBackgrndColor
vla-put-GripColorSelected
vla-put-GripColorUnselected
vla-put-LayoutCrosshairColor
vla-put-ModelCrosshairColor
vla-put-TextColor
vla-put-TextWinBackgrndColor
vla-put-TextWinTextColor
vla-put-TrueColorImages)
Hier sollten wir es vielleicht doch mit der kurzen
Funktion
(vla-get-color) versuchen. Natürlich müssen
jetzt die beiden Funktionen kombiniert aufgerufen werden. Wir
probieren einfach mal aus:
(vla-get-color(vla-get-ActiveLayer))
=> ; Fehler: Zu wenig Argumente
Nun, das ist eigentlich logisch, wenn man bedenkt, dass jede
geöffnete Zeichnung einen aktuellen Layer hat. Wir müssen schon
noch angeben, dass wir uns auf die aktuelle Zeichnung beziehen.
Dass hierzu eine Funktion
(vla-get-ActiveDocument) existiert
und diese dann noch das
application-Objekt als Argument
benötigt - na klar, wissen wir doch.
(vla-get-color
(vla-get-ActiveLayer
(vla-get-ActiveDocument
(vlax-get-acad-object)
)
)
) => 7
Na also! Im nächsten Kapitel folgt ein weiterer Ansatz,
mit dessen Hilfe wir den Code evtl. noch kürzer kriegen!