AutoCAD... AutoLISP... VisualLISP...

  [57] Obiekty niegraficzne (4)

index  

  Kolejną "przygodę" z niegraficznymi obiektami AutoCAD-a rozpoczynamy od słowników. Na początek sprawdzenie czy słownik o zadanej (podanej jako argument) nazwie istnieje. Funkcja wygląda tak:

;;; -------------------------------------------------------------;;;
;;; Funkcja sprawdza czy w rysunku istnieje słownik o nazwie     ;;;
;;; [DictName]. Argument [Root] określa wskaznik słownika wlaści-;;;
;;; ciela. Zwraca T lun Nil                                      ;;;
;;;                                                              ;;;
(defun jk:DCT_isDict? (Root DictName)
  (if (dictsearch Root DictName) T nil)
)
;;; -------------------------------------------------------------;;;
Sprawdzmy jej działanie kolejno wywołując:
(jk:DCT_isDict? (namedobdict) "ACAD_GROUP") zwraca T
oraz:
(jk:DCT_isDict? (namedobdict) "SLOWNIK") zwraca nil
Ponieważ słowniki tworzą hierarchiczną strukturę, do tej pory przeglądaliśmy tylko pierwszy poziom (wywołując funkcję namedobjdict mamy dostęp do słownika nazwanych obiektów). Spróbujmy odczytać wpisy do słownika ACAD_LAYOUT. Wykorzystamy do tego zdefiniowaną wcześniej funkcję jk:DCT_DictList.
W linii poleceń AutoCAD-a wywołajmy:
(jk:DCT_DictList (cdr (assoc "ACAD_LAYOUT" (jk:DCT_DictList (namedobjdict) nil))) nil)
Wynikiem będzie:
(("Arkusz1" . <Nazwa elementu: 184ac50>) ("Arkusz2" . <Nazwa elementu: 1875970>) ("Model" . <Nazwa elementu: 184ac48>))
Widać istniejące wpisy do słownika ACAD_LAYOUT. Pozycje te to obiekty (typu LAYOUT) opisujące istniejące w rysunku zakładki (model i 2 zakładki obszaru papieru). Analogicznie można przeprowadzić sprawdzenie wpisów do słownika ACAD_GROUP. W tym celu wystarczy wywołać:
(jk:DCT_DictList (cdr (assoc "ACAD_GROUP" (jk:DCT_DictList (namedobjdict) nil))) nil)
W przypadku gdy wynikiem będzie nil (w rysunku nie ma zdefiniowanych grup), można w rysunku utworzyć dowolne grupy obiektów (poleceniem _GROUP (GRUPA)), i ponownie wywołać funkcję. Posiadając już podstawową wiedzę na temat słowników, możemy przejść do następnego tematu zatytułowanego:

»  Tworzymy własny słownik

Z punktu widzenia programującego utworzenie słownika jest stosunkowo prostą czynnością. Aby utworzyć słownik musimy nadać mu unikalną nazwę. Ze względu na to, iż może istnieć tylko jeden słownik o zadanej nazwie (w słowniku rodzicu), przed utworzeniem słownika, musimy upewnić się czy nie został on wcześniej utworzony. Wykorzystamy do tego wcześniej zdefiniowaną funkcję jk:DCT_isDict?. Następnie (gdy słownik nie istnieje) za pomocą funkcji entmakex utworzymy obiekt typu DICTIONARY (lista DXF z nazwą obiektu (kod 0) jego klasą (kod 100)), i dodamy go (funkcja dictadd) do słownika którego wskaznik właściciela przekazujemy jako argument Root z nazwą DictName. Definicja funkcji wygląda tak:

;;; -------------------------------------------------------------;;;
;;; Funkcja tworzy słownik o nazwie [DictName]. Słownik zostanie ;;;
;;; utworzony w przypadku gdy nie istnieje już słownik o tej     ;;;
;;; nazwie. Jeżeli argument Msg? jest różny od nil i słownik już ;;;
;;; istnieje wyświetlane jest ostrzeżenie i funkcja zwraca nil.  ;;;
;;; gdy słownik zostanie utworzony zwracany jest wskaznik obiektu;;;
;;;                                                              ;;;
(defun jk:DCT_MakeDict (Root DictName Msg? / Test DictData NewDict)
  (setq Test (jk:DCT_isDict? Root DictName))
  (if Test
    (if Msg?
      (alert
	(strcat "Słownik o nazwie: "
		(strcase DictName)
		" jest już zdefiniowany."
	)
      )
      Nil
    )
    (progn
      (setq DictData
        (list '(0 . "DICTIONARY")'(100 . "AcDbDictionary")))
      (setq NewDict (entmakex dictData))
      (setq NewDict (dictadd Root DictName NewDict))
    )
  )
)
Po załadowaniu funkcji możemy utworzyć własny słownik. Wywołanie:
(jk:DCT_MakeDict (namedobjdict) "JK_DANE-TEST" T) zwraca: <Nazwa elementu: 1874ef0>
sprawdzmy teraz:
(jk:DCT_MakeDict (namedobjdict) "JK_DANE-TEST" ) zwraca: T
spróbujmy jeszcze raz:
(jk:DCT_MakeDict (namedobjdict) "JK_DANE-TEST" T) zwraca nil i wyświetli:
Pierwsze wywołanie utworzyło słownik o nazwie JK_DANE-TEST i zwróciło ENAME (nazwę obiektu). Kolejne potwierdziło istnienie słownika. Ostatnie zaś wywołanie wyświetliło komunikat ostrzegawczy informujące nas o istnieniu słownika o takiej nazwie i zwróciło NIL. Ważnym jest aby konstruować funkcje tworzące słowniki w taki sposób, aby uprzednio sprawdzić czy dany słownik już istnieje. Gdy pominiemy tego typu sprawdzenie, próba utworzenia słownika spowoduje powstanie błędu funkcji dictadd.
Struktura Named Objects Dictionary po utworzeniu nowego słownika: Widoczny nowoutworzony słownik o nazwie JK_DANE-TEST. Rozwinięcie słownika ACAD_MLINESTYLE wskazuje na pojedynczy wpis do słownika o nazwie STANDARD (definicja stylu multilinii). Słownik JK_DATA-TEST nie zawiera żadnych wpisów.
                 

»  Usuwanie słownika

Opisane tutaj metody (usuwanie i pózniej zmiana nazwy) odnoszą się nie tylko do słowników, lecz do wszystkich obiektów niegraficznych. Do usuwania słownika możemy użyć standardowej funkcji AutoLISP o nazwie dictremove. W niektórych zródłach można spotkać się z nazwą funkcji dictdel. W wersji 13 AutoCAD-a, występowały różnice między wersjami oznaczonymi jako 13c...n. Począwszy od wersji 13c4, nazwa funkcji dictdel została zmieniona na dictremove, i do dziś jest obowiązująca.
Istnieje jednak pewne ograniczenie: domyślnie funkcja dictremove nie usuwa słownika z rysunkowej bazy danych. Aby trwale dokonać usunięcia słownika należy użyć funkcji entdel (tak samo jak dla elementów graficznych). W chwili obecnej wyjątkiem od tej zasady są obiekty typu GROUP i MLINESTYLE. Funkcja zwraca nazwę usuniętego obiektu, w przypadku powodzenia lub nil, w przypadku niepowodzenia. Możliwość tę można wykorzystać w następujący sposób: jeśli dictremove się powiedzie - można zastosować entdel. Zdefiniujemy teraz funkcję służącą do usuwania obiektów niegraficznych z dowolnego słownika.

;;; -------------------------------------------------------------;;;
;;; Funkcja usuwa wpis do słownika [Root] o nazwie DictName.     ;;;
;;;                                                              ;;;
(defun jk:DCT_DelDict (Root DictName / Test DictList)
  (setq Test (jk:DCT_isDict? Root DictName))
  (if Test
    (progn
      (setq DictList (jk:DCT_DictList Root nil ))
      (if
	(dictremove Root DictName)
        (entdel (cdr (assoc DictName DictList)))
      )
    )
    Nil
  )
)
Sprawdzmy teraz działanie funkcji. Zakładając że wcześniej został zdefiniowany słownik o nazwie JK_DANE-TEST możemy wywołać w linii poleceń: (jk:DCT_DelDict (namedobjdict) "JK_DANE-TEST")
Funkcja zwróci nazwę usuniętego obiektu: <Nazwa elementu: 1874ef0>
Uprzedzając próby destrukcyjnego wykorzystania umiejętności usuwania obiektów niegraficznych, dodam że, nie można usuwać słowników których nazwa zaczyna się od ACAD. Podobnie nie zostaną usunięte obiekty wykorzystywane w rysunku, jak też wpisy standardowe (np. nie da się usunąć obiektu typu MLINESTYLE o nazwie STANDARD).

Zobacz także: Obiekty niegraficzne (1) , Obiekty niegraficzne (2) , Obiekty niegraficzne (3) , Własny XRECORD,
      aktualizacja: 26-01-2010