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










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!