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










In Lisp sind - im Gegensatz zu vielen anderen Sprachen - Variablen völlig untypisiert, d.h. an ein Symbol kann jeder beliebige Datentyp gebunden werden. Wir können einer Variablen zunächst ein Ganzzahl, dann eine Liste und später auch noch eine Zeichenkette oder einen Auswahlsatz zuweisen - der Interpreter wird sich nicht darüber beschweren. In C/C++, Java, Pascal, Delphi sieht das völlig anders aus. Jede Variable wird für einen bestimmten Datentyp deklariert und darf dann auch nur diesen Datentyp enthalten. Falls man in diesen Sprachen einer als Integer deklarierten Variablen eine Zeichenkette zuweisen will, endet das nur mit einer Fehlermeldung.

Auch Basic gehörte ursprünglich zu diesen typisierten Sprachen, allerdings wurde in VisualBasic dieses Konzept durch die Einführung des Datentyps Variant aufgeweicht. Einer Variablen vom Typ Variant kann man fast alle Datentypen zuweisen, und jede Variable, die nicht für einen anderen Datentyp deklariert wurde, hat automatisch den Typ Variant.

Wir wissen ja schon, dass wir es bei der VisualLisp- bzw. ActiveX-Programmierung mit neuen Datentypen zu tun haben, und der variant ist sicherlich neben VLA-OBJECT der am häufigsten vorkommende. Und was kann in so einem Variant alles drin sein, womit müssen wir rechnen?

Ein Variant kann selbstverständlich eine Zahl (Ganz-, Real-) oder eine Zeichenkette enthalten - da entsteht für Einsteiger selten ein Problem. Er kann aber auch ein Objekt enthalten, dass wir dann mit den vl-Bordmitteln weiterverarbeiten können. Schwieriger wird es, wenn ein Variant ein Datenfeld (in VisualLisp heisst dieses dann safearray) enthält. Diese Kombination bereitet den ActiveX-Einsteigern erfahrungsgemäss etwas Kopfzerbrechen.

Werfen wir doch einmal einen Blick auf einen Variant - wir schauen uns nur die Rückgabe einer Funktion an, die mit Sicherheit einen Variant zurückgibt. Als Beispiel greifen wir auf die Eigenschaft 'Limits' des aktiven Dokuments zu. Dazu können wir entweder den langen Weg gehen, d.h. wir arbeiten uns bis zum 'ActiveDocument' vor, oder wir benutzen unseren Funktionsfinder, was wahrscheinlich zu einem kürzeren Code führt:
(find-vla-function "*limits*")
    = > ("VLA-GET-LIMITS" "VLA-PUT-LIMITS")

(vla-get-limits
  (vla-get-activedocument
    (vlax-get-acad-object)
  )
)
#<variant 8197 ...>
                  
Nun, was bedeutet die Zahl 8197? Es handelt sich hier offensichtlich nicht um eine Speicherstelle in Hexadezimal-Schreibweise, wie wir sie von anderen Datentypen her kennen. Ein Blick in die Online-Hilfe schafft wieder einmal Aufklärung - nach einigem Suchen finden wir im VisualLisp Developer's Guide unter der Überschrift Converting AutoLisp Datatypes to ActiveX Data Types eine Tabelle, die uns weiterhilft. Dort wird eine Reihe in Lisp vordefinierter Konstanten aufgelistet, und durch Ausprobieren lässt sich herausfinden, dass die Konstante vlax-vbArray den Wert 8192 hat:
!vlax-vbarray   => 8192
!vlax-vbdouble  => 5
                  
Eine Konstante mit dem Wert 8197 werden wir allerdings nicht finden. Das seine Ursache darin, dass hier zwar keine binäre Codierung vorliegt, wie wir sie z.B. von der Systemvariablen "Osmode" kennen, aber trotzdem Werte zusammengezählt werden. Anhand der vlax-vb...-Konstanten können wir uns nun zusammenreimen, dass es sich hier um ein Array handelt (8192)und dass in diesem Array Doubles (5) enthalten sind.

Ein solcher Variant, der ein Array enthält, lässt sich leider nicht ohne weiteres weiterbearbeiten - hier ist Konvertierungsarbeit angesagt. Werfen doch einmal einen Blick auf die Funktionen, die zur Verarbeitung von variants überhaupt zur Verfügung stehen:
  • (vlax-make-variant ...) werden wir bald benötigen, um den Datentyp variant zu erzeugen
  • (vlax-variant-type ...) gibt uns eine Zahl zurück, die anzeigt, welcher Datentyp enthalten ist - das sind natürlich genau diese Zahlen, die auch in den vlax-Konstanten abgespeichert sind, z.B. 5 für einen Double oder 8192 für ein Array
  • (vlax-variant-value ...) liest den Wert eines variant aus und gibt ihn zurück. Damit werden wir uns noch näher befassen.
  • (vlax-variant-change-type ...) verursacht einen sog. type cast. Wird z.B. von Double nach Integer konvertiert, gehen die Kommastellen verloren. Nicht jede Kombination ist hier möglich und sinnvoll.
Hier soll es jetzt also um variants gehen, die bei Aufruf von (vlax-variant-type ...) eine Zahl zurückgeben, die größer als 8192 ist - die also ein Array enthalten. Ein Array, in der Online-Hilfe auch Datenfeld genannt, hat wenig Ähnlichkeit mit den Listen, die wir aus Lisp kennen. Ein Array hat zum Einen eine festgelegte Größe, d.h. ein Zugriff mit einem ausserhalb des Bereichs liegenden Index führt zu einem Fehler. Dies ist auch der Grund, weshalb man es in VisualLisp Safe-Array genannt hat. Zum Anderen kann ein Array immer nur einen einzigen Datentyp enthalten, während bei den Lisp-Listen natürlich alle Kombinationen vorkommen können.

Mit der Funktion (vlax-variant-value) bekommen wir also Zugriff auf das im variant abgelegte Array, der Datentyp ist nun Safearray:
(vlax-variant-value
  (vla-get-limits
    (vla-get-activedocument
      (vlax-get-acad-object)
    )
  )
)
=> #<safearray...>
                  
Für das Auslesen eines Arrays wiederum stellt uns VisualLisp zwei verschiedene Funktionen zur Verfügung. Die eine, (vlax-safearray-get-element), dient zum Auslesen einzelner Elemente - das einzige Argument ausser dem Array selbst ist der Index (falls das Array mehrdimensional ist, erhöht sich aber die Anzahl der Argumente, da die Anzahl der Indizes steigt. Ein viel einfacherer Weg besteht allersings darin, das Array in eine Lisp-Liste umzuwandeln. Dazu gibt es die praktische Funktion (vlax-safearray->list) (Hier liegt kein Tippfehler vor, der stilisierte Pfeil deutet die Richtung der Konvertierung an). Dass die beiden 2D-Punkte, die die Zeichnungslimiten festlegen, als eine Liste mit vier Koordinaten herauskommen, ist kein Problem der Konvertierung - die Punkte liegen so bereits in dem linearen Array.
(vlax-safearray->list
  (vlax-variant-value
    (vla-get-limits
      (vla-get-activedocument
        (vlax-get-acad-object)
      )
    )
  )
)
=> (0.0 0.0 420.0 297.0)
                  
Das Zusammenspiel von Objekten, Collections, Arrays und Variants mag den Einsteiger in die Materie vielleicht kurzfristig etwas irritieren. Diese Dinge zu beherrschen ist allerdings keineswegs schwierig. Ärgerlich wird es allerdings, wenn man plötzlich auf einen Datentyp in einem variant stösst, der offensichtlich in VisualLisp vergessen wurde. Wir verwenden für ein Beispiel noch einmal die rekursive Form (vlax*get-property), die im letzten Kapitel vorgestellt wurde. Es soll die Hintergrundfarbe der Layout-Fenster ausgelesen werden:
(vlax*get-property nil
'(GraphicsWinLayoutBackgrndColor Display Preferences)
)
=> #<variant 19 0>
                  
Ein Variant des Typs 19 ist nirgendwo in der Online-Hilfe zu finden. Man kann nur kombinieren, dass diese Farbe nicht als AutoCAD-Farbe angegeben wird, sondern als RGB-Farbe - was eigentlich auch logisch erscheint. Es liegt also mit dem Typ 19 offensichtlich ein eigener Datentyp für RGB-Farbwerte vor. Diesen Farbwerten kann man beispielsweise in Excel oder Access begegnen: es handelt sich um Integerwerte im Bereich zwischen 0 und 16777215, was dem Bereich einer vorzeichenlosen 24-Bit-Ganzzahl entspricht. Auch das erscheint logisch, da ja RGB-Farben jeweils ein Byte (8 Bit) für jeden der drei Farbkanäle benutzen.

Beim Variant-Typ 19 für RGB-Farben bleibt uns nichts anderes übrig, als mit (vlax-variant-change-type) einen 'type cast' nach vlax-vbLong durchzuführen. Dies hat keine gravierenden Konsequenzen, ausser dass jetzt natürlich möglich wird, eine ungültige Farbnummer zuzuweisen, da der Wertebereich des Long größer ist als der einer Farbe und auch negative Zahlen vorkommen können.

Einen Variant vom Typ 19 mit VisualLisp zu erzeugen, ist auch kein Problem - man muss nur auf eine vlax-vb...-Konstante verzichten und den Typ 19 als Zahl angeben. Allerdings kann man sich die Mühe auch durchaus sparen, da die ActiveX-Funktionen, die den Typ 19 als Argument erwarten auch einen Long akzeptieren, solange er nicht aus dem Gültigkeitsbereich fällt. Merkwürdig ist dabei jedoch, dass auch in VisualBasic für AutoCAD kein Variant vom Typ 19 zu finden ist. Die VB-Funktion RGB(red, green, blue) gibt einen Long zurück!