Zwei Methoden, wie man sich durch den Objektbaum hangeln kann,
haben wir bereits kennengelernt. Auch wenn mit den
(vla-...)-Funktionen einige Abkürzung 'drin ist', kann
ein versierter Lisp-Programmierer doch schon mal das Gefühl
entwickeln, dass der Code an sich nicht besonders aufregend
ist - das Problem liegt einzig und allein darin, sich in dem
Baum zurechtzufinden und mit den 'artfremden' Datentypen
klarzukommen.
Ich behaupte sogar, dass ActiveX-Code in VisualLisp generell
die Tendenz hat, 'dumm' zu sein. Zu stark spiegeln sich hier
die VisualBasic-Strukturen wider - und Basic-Code zeichnet sich
durch alles Andere als seine 'Intelligenz' aus - da, wo in Lisp
manchmal ein Dreizeiler genügt, muss man in Basic oftmals mit
dem Editor seitenlang Sourcecode zusammenkopieren, um das
Gleiche zu erreichen.
Erinnern wir uns, dass die Stärke von Lisp in der Listenverarbeitung
liegt - eine Stärke, die in dieser Art kaum eine andere Sprache
zu bieten hat. Diese Stärke wird aber oft nicht genutzt, schon gar
nicht, wenn es um ActiveX geht. An dieser Stelle würde ich anraten,
im Zweifelsfalle doch noch einmal einen kleinen Ausflug zu
machen: Zum Einen ins Einsteiger-Tutorial, und zwar dort in die
Kapitel über Stilfragen. Und wenn wir schon dabei sind: Vielleicht
sollte man auch gleich noch einmal das Kapitel über Rekursion
im Fortgeschrittenen-Tutorial lesen.
Zu beide Themen sollte ein gewisses Wissen und Verständnis
vorliegen, denn dieses ist erforderlich, damit man den
Code-Beispielen auf diesen (grünen) Seiten folgen kann. Leider
ist es so, dass man in Newsgroups und auf Homepages oft auf
ganz anderen Code stösst. Um das, was ich meine, zu verdeutlichen,
noch einmal ein Beispiel, wie der Code zum Auslesen der Farbe
des Layers "0" aussehen könnte:
(setq AcadObject(vlax-get-acad-object))
(setq ActiveDocument(vla-get-ActiveDocument AcadObject))
(setq ActiveLayer(vla-get-ActiveLayer ActiveDocument))
(setq Color(vla-get-Color ActiveLayer))
Hier wird ein Schritt nach dem Anderen angegangen und jeweils
einer Variablen zugewiesen. Diese Variablen sind aber völlig
überflüssig - warum wohl bin ich bisher in den letzten Kapiteln
ohne ein einziges
(setq) ausgekommen? Hier werden die
Segel gestreckt - der Lisp-Programmierer ergibt sich, läuft zu
Basic über und versteckt seinen Basic-Code in Lisp-Schreibweise!
Wer solchen Code produziert, sollte ihn konsequenterweise dann
auch in Basic schreiben.
Betrachtet man diese vier Zeilen einmal genau, so wird man
feststellen, dass die Struktur immer gleich ist: Die Rückgabe
einer Funktion wird zum Argument der nächsten. Bisher habe ich
das in diesem Tutorial dann so formuliert:
(vla-get-Color
(vla-get-ActiveLayer
(vla-get-ActiveDocument
(vlax-get-acad-object)
)
)
)
Dieser Code ist kürzer und besser lesbar, und er verzichtet
auf den unsinnigen Gebrauch von
(setq), der nur ausbremst
und Variablen erzeugt, die keiner braucht. Aber betrachten wir
doch die Struktur des Ganzen noch einmal. Hier geht es doch um
eine Abfolge von Color->ActiveLayer->ActiveDocument->acad-object!
Nur am Rande: Dass dies jetzt im Funktionsnamen 'acad-object'
heisst statt 'AcadObject' oder 'Application', zeigt nur, dass
die Verantwortlichen bei AutoDesk sich auch nicht sonderlich viel
Gedanken über die Dinge machen - das ist einfach inkonsequent.
Wahrscheinlich war da noch ein Kontingent Bindestriche zu verteilen.
Lisp wäre nicht Lisp, wenn sich diese Abfolge nicht als Liste
verarbeiten liesse! Und deshalb an dieser Stelle mein Vorschlag,
wie man eine solche Folge von Properties der Sprache Lisp angemessen
verarbeiten kann:
(defun vlax*get-property(obj props / )
(if(null obj)(setq obj(vlax-get-acad-object)))
(if(and(listp props)(cdr props))
(vlax-get-property
(vlax*get-property obj(cdr props))
(car props)
)
(vlax-get-property obj
(if(listp props)(car props)props)
)
)
)
; Das Beispiel mit der Farbe
; von Layer "0":
(vlax*get-property nil
'(Color ActiveLayer ActiveDocument)
)
Das Wichtigste zuerst: Das ist Code auf dem Niveau der
Sprache Lisp! Lisp wird doch nicht umsonst als eine Sprache
der künstlichen Intelligenz bezeichnet - so viel
Abstraktionsvermögen muss einfach sein, dass man das
'Durchhangeln' durch die Äste eines Baumes durch die
wesentlichen Daten wiedergeben kann! Aber nun ein paar
Erklärungen zu den Einzelheiten.
Zunächst zum Namen: Da habe ich mich einfach entschieden,
den ersten Bindestrich durch einen Stern zu ersetzen.
Jeder andere Name würde es auch tun, aber traditionell
zeigt ein Stern im Namen einer Lisp-Funktion an, dass es
sich um eine Sonderform handelt. In diesem Fall ist es
die Sonderform, die nicht nur eine Eigenschaft ausliest,
sondern eine Eigenschaftskette.
Das erste Argument gibt den Ausgangsort an - in den meisten
Fällen wird dies das
application-Objekt sein. Deshalb
genügt es normalerweise, hier ein
nil einzuspeisen,
eine Nicht-Angabe bedeutet, dass wir 'ganz oben' anfangen.
Sollte jedoch ein anderer Ursprung der Folge gewünscht sein,
kann dieser hier angegeben werden.
Auf die Rekursion selbst möchte ich hier nicht näher eingehen,
deshalb der Hinweis auf das Fortgeschrittenen-Tutorial. Wenn das
zweite Argument eine Liste ist, wird sie jedenfalls rekursiv
abgearbeitet. Ist das zweite Argument aber ein Atom, dann ist
die Funktion praktisch identisch mit
(vlax-get-property).
Auch wenn das bisher eigentlich gar nicht behandelt wurde:
Eigenschaften kann man natürlich nicht nur auslesen, sondern
auch modifizieren. Um dem Layer "0" eine neue Farbe zu
verpassen, muss man also nur seine Eigenschaft 'Color' ändern.
Daher können wir - analog zum Auslesen - gleich noch eine
rekursive Vorgehensweise zum Ändern der Eigenschaften definieren:
(defun vlax*put-property(obj props value / )
(if(null obj)(setq obj(vlax-get-acad-object)))
(if(and(listp props)(cdr props))
(vlax-put-property
(vlax*get-property obj(cdr props))
(car props)
value
)
(vlax-put-property obj
(if(listp props)(car props)props)
)
)
)
; setzt die Farbe des aktuellen Layers
; in der aktuellen Zeichnung auf 'rot' (1)
(vlax*put-property nil
'(Color ActiveLayer ActiveDocument)
1
)
Mag sein, dass ich mit dem Gefühl alleine bleibe, in den
Dschungel von Basic und Lisp wieder etwas Licht gebracht zu
haben. Mir tut es jedenfalls gut zu merken, dass man auch in
der ActiveX-Programmierung noch auf die Intelligenz von Lisp
zurückgreifen kann, wenn auch nicht immer...