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










Seit der Einführung von VisualLisp und dem damit verbundenen neuen Lisp-Interpreter gibt es eine ganz neue Möglichkeit in Lisp, die dem Programmierer bis dahin verschlossen war: Auftretende Fehler können aufgefangen werden. Bisher musste man damit leben, dass das Auftreten eines Fehlers das laufende Programm auf jeden Fall beendete - es ging dann nur noch um's Aufräumen und das Zurückversetzen von AutoCAD in den Zustand, in dem es zu Beginn des Programms war.

Die neue Funktion, die das Abfangen eines Fehlers ermöglicht, heisst (vl-catch-all-apply). Sie bekommt immer genau zwei Argumente - das erste Argument ist eine Funktion oder ein Lambda-Ausdruck, und das zweite Argument ist eine Liste mit den Argumenten, die dieser Funktion zugeführt werden sollen. Die Funktion arbeitet also genau wie das altbekannte (apply), ein Unterschied besteht jedoch in der Rückgabe: Wenn die Evaluation des Funktionsausdrucks einen Fehler verursacht, wird nicht abgebrochen, sondern es wird ein Fehler-Objekt zurückgegeben.

Ein solches Fehler-Objekt stellt einen neuen, gesonderten Datentyp in Lisp dar. Dieses Fehler-Objekt kann dann aber (bei weiterlaufendem Programm) verarbeitet bzw. verglichen werden. Zunächst aber erstmal ein bisschen Code, um die Dinge zu verdeutlichen:
(defun test1( / )
  (vl-catch-all-apply 'vla-item
    (list
      (vla-get-Layers
        (vla-get-ActiveDocument
          (vlax-get-acad-object)
        )
      )
      "NichtVorhanden"
    )
  )
)

(test1)
  => #<%catch-all-apply-error%>

(type(test1))
  => VL-CATCH-ALL-APPLY-ERROR
                  
Wenn wir den Code nun noch etwas modifizieren (wir speichern das Ergebnis des Item-Aufrufs ab und vergleichen den erhaltenen Datentyp), haben wir schon eine Methode, wie wir absturzfrei auf die Layers-Collection zugreifen können:
(defun test2(layer-name / result)
  (if
    (/=
      (type
        (setq result
          (vl-catch-all-apply 'vla-item
            (list
              (vla-get-Layers
                (vla-get-ActiveDocument
                  (vlax-get-acad-object)
                )
              )
              layer-name
            )
          )
        )
      )
     'VL-CATCH-ALL-APPLY-ERROR
    )
    result
  )
)

(test2 "0")
  =>

(test2 "NichtVorhanden")
  => nil
                  
Das klappt doch wunderbar! Allerdings modifizieren wir noch ein wenig weiter, denn VisualLisp bietet zum Umgang mit abgefangenen Fehlern noch zwei weitere neue Funktionen: (vl-catch-all-error-p) ist eine Prädikatfunktion, mit der wir ein wenig Schreiberei sparen können: Sie macht genau das, was wir mit unserem (type)-Vergleich erledigt haben - sie testet, ob ihr Argument ein #<%catch-all-apply-error%> ist.
(defun test3(layer-name / result)
  (if
    (not
      (vl-catch-all-error-p
        (setq result
          (vl-catch-all-apply 'vla-item
            (list
              (vla-get-Layers
                (vla-get-ActiveDocument
                  (vlax-get-acad-object)
                )
              )
              layer-name
            )
          )
        )
      )
    )
    result
  )
)

(test2 "0")
  =>

(test2 "NichtVorhanden")
  => nil
                  
Eine kleine kosmetische Änderung, sonst nichts - der Code verhält sich genauso wie vorher. Die zweite Funktion zum Behandeln von abgefangenen Fehlern heisst (vl-catch-all-error-message). Sie ist nur dann von Interesse, wenn man die Ursache des aufgefangenen Fehlers nachträglich ermitteln möchte. Der Fehlertext, der bei einem nicht aufgefangenen Fehler auf der Kommandozeile ausgegeben würde, wird hier als Zeichenkette zurückgegeben. In unserem Fall können wir allerdings auf diese Analyse verzichten, da wir genau wissen, dass der Fehler durch die Item-Methode verursacht wird.

Wir können nun unsere im vorigen Kapitel definierte Funktion (collection-member-p) noch einmal auf andere Weise definieren:
(defun collection-member-p(name collection / )
  (not
    (vl-catch-all-error-p
      (vl-catch-all-apply 'vla-item
        (list collection name)
      )
    )
  )
)

(collection-member-p "0"
  (vla-get-Layers
    (vla-get-ActiveDocument
      (vlax-get-acad-object)
    )
  )
)
  => T

(collection-member-p "NichtVorhanden"
  (vla-get-Layers
    (vla-get-ActiveDocument
      (vlax-get-acad-object)
    )
  )
)
  => nil
                  
Die beiden Versionen sind im Verhalten völlig gleich - bei grossen Collections dürfte allerdings diese Version etwas schneller sein. Für die praktische Arbeit sollte man aber vielleicht doch eine Funktion vorziehen, die entweder (falls enthalten) das Collection-Item zurückgibt, oder (falls nicht vorhanden) nil. Diese Funktion könnte so aussehen:
(defun collection-item(name collection / result)
  (if
    (not
      (vl-catch-all-error-p
        (setq result
          (vl-catch-all-apply 'vla-item
            (list collection name)
          )
        )
      )
    )
    result
  )
)

(collection-item "0"
  (vla-get-Layers
    (vla-get-ActiveDocument
      (vlax-get-acad-object)
    )
  )
)
  => #<VLA-OBJECT IAcadLayer 0fc04474>

(collection-item "NichtVorhanden"
  (vla-get-Layers
    (vla-get-ActiveDocument
      (vlax-get-acad-object)
    )
  )
)
  => nil