Ein paar Worte vorabHome   Letzte MeldungenNews   Index der Kapitel und der besprochenen FunktionenIndex   Wer ich bin, warum ich diese Seiten mache, KontaktImpressum   Ich freue mich über jeden Eintrag im Gästebuch!Gästebuch   Einige Links zu anderen AutoLisp-SeitenLinks   Copyrights und DisclaimerRechts
Hier können die kompletten Seiten als ZIP-File heruntergeladen werden!

Einführung zum Programmieren mit VisualLisp Welcome to...
Das ActiveX-Objektmodell - Grundlage der vl-Programmierung in AutoCAD Das Objekt
Die vla-Funktionen: Viel ActiveX - wenig Dokumentation Knielang
Funktionen für den schnellen Zugriff in VisualLisp Breiter Gürtel
Variants - der Gummi-Datentyp von VBA Damenhandtasche
Collections - VB-Sammelbehälter in VisualLisp Kommste mit rauf?
Das Auffangen von Fehlern in VisualLisp Plumps
Berechnen von Schnittpunkten zwischen Entities mit ActiveX Windschnittig!
Ein erster, einfacher Reaktor, der viel Arbeit sparen kann Faulheit
Importieren von Views aus einer geschlossenen Zeichnung mit DBX Deutsche Bahn


Zum Einsteiger-Tutorial

Zu den Seiten für Fortgeschrittene

Meine Private HP mit Fotos, Gedichten, Musik und Postkartenversand

Mein Online-Lexikon der Fotografie

Mein völlig abgedrehtes Reisebüro










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...