Autolisp bazı kullanıcılar için blok özelliğini doğru şekilde ayarlamıyor

Dec 29 2020

İlk defa soran, bu yüzden umarım sorunu yeterince iyi tanımlıyorum.

Şirketimizde, aynı AutoCAD sürümüne sahip birkaç kişi tarafından kullanılan bir Autolisp kodumuz var, ancak bazı kullanıcılar için lisp düzgün çalışmayı durdurdu.

Lisp'in işlevi aşağıdaki gibidir:

  • kullanıcı lisp'i çalıştırır
  • program aşağıdakileri ister:
    • bloğun ölçeği
    • bloktaki metin için önek
    • ilk blok varlığı için çalışan numara
    • sayıdaki artış
    • ilk blok nereye yerleştirilir

Bu, bir işaretçi ve aşağıdaki formatta (ön ek) bir metne (numara üç sayıdan oluşmuyorsa olası orta bölüm) (sayı), örneğin PT001 veya PX100 ile bir bloğa yol açmalıdır.

Ancak bunu yapmak yerine, bazı kullanıcılar önek ve sayı eksikliğini yaşıyor ve metnin yalnızca yukarıda belirtilen olası orta bölümünü görmeye başladı, diğer zamanlarda aynı kullanıcı yalnızca önekin gösterildiğini deneyimleyebilir. İşaretçi olması gerektiği gibi görüntülenir, ancak metin beklendiği gibi çalışmaz.

Aşağıdaki kodun kusurlar için analiz edilmesine yardımcı olacak herhangi bir yardım çok takdir edilmektedir.

Kod "kusursuz" görünüyorsa, blok veya öznitelikleriyle ilgili bir sorun olduğunu varsayıyorum.

-E

(defun c:pointnumber()
(setvar "ATTDIA" 0)
(setq sc (getreal "\nEnter scale: "))
(setq px (getstring "\nSet prefix for point number: "))
(setq nr (getint "\nThe number for the first point: "))
(setq ic (getint "\nIncrement of the number: "))
(setq point 1)
(while (/= point nil)
    (setq point (getpoint "\nChoose a point: "))
    (if (/= point nil)
        (progn
        (setq inr (itoa nr))
        (if (< nr 100) (setq md "0"))
        (if (< nr 10) (setq md "00"))
        (if (> nr 99) (setq md ""))
        (setq ph (strcat px md inr))
        (command "insert" "pointnumber" point sc sc 0 ph)
        (setq nr (+ nr ic))
        )
    )
)
(setvar "ATTDIA" 1)(princ)
)

Yanıtlar

1 LeeMac Dec 30 2020 at 01:21

Mevcut kodunuzla ilgili bir dizi sorun vardır: bunlardan bazıları yalnızca kötü uygulama olarak değerlendirilebilir, bazıları kullanıcı geçersiz verilerle yanıt verirse programın başarısız olmasına neden olur ve diğerleri programın başarısız olmasına veya beklenmedik şekilde davranmasına neden olur. Programın yürütüldüğü AutoCAD ortamının ayarları.

1. ATTREQ

Tanımladığınız davranışın ana suçlusu ATTREQ, kullanıcının INSERTkomutun bir parçası olarak öznitelik değerleri için bilgi istemleri alıp almayacağını belirleyen sistem değişkeni olabilir . Eğer ATTREQ=0program çalıştırıldığında, blok varsayılan özelliği değerleriyle takılı olacaktır.

Bu sistem değişkeninin mevcut değerini depolayarak ve komutu 1çağırmadan önce INSERT(öznitelik istemlerinin yayınlandığından emin olmak için) ayarlayarak ve ardından komutun ardından veya komutun sonunda orijinal değeri geri yükleyerek ortamlar arasında tutarlı davranış sağlayabilirsiniz. programı.

Örneğin:

(defun c:test ( / atr )
    (setq atr (getvar 'attreq))
    (setvar 'attreq 1)

    ;; ... Do your thing

    (setvar 'attreq atr)
    (princ)
)

2. OSMODE

Nokta verilerini AutoLISP aracılığıyla bir komuta sağlarken, nokta, noktanın sağlandığı anda etkin olan herhangi bir Nesne Yakalama modundan etkilenecektir. Bunu buradaki cevabımda daha ayrıntılı olarak anlatıyorum .

Bunu önlemenin en kolay yolu, AutoCAD'e sonraki nokta girişi için tüm Nesne Yakalama modlarını yoksayması talimatını vermek üzere "_non"veya "_none"nesne yakalama değiştiricisinin kullanılmasıdır, örneğin:

(command "insert" "pointnumber" "_non" point sc sc 0 ph)

3. Kullanıcı Girişi

Programın yürütülmesi sırasında hatalardan kaçınmak için kullanıcı girdisinin eksikliğini veya geçersiz kullanıcı girdisini hesaba katmalısınız - bu, ifdeyimlerin kullanılması veya initgetişlevin kullanılmasıyla kolayca başarılır , örneğin:

(initget 7) ;; Prevents Enter, zero, or negative numbers
(setq sc (getreal "\nEnter scale: "))

Veya:

(initget 6)
(if
    (and
        (setq sc (getreal "\nEnter scale: "))
        (setq px (getstring "\nSet prefix for point number: "))
        (setq nr (getint "\nThe number for the first point: "))
        (setq ic (getint "\nIncrement of the number: "))
    )
    ;; ... Do your thing
)

Alternatif olarak, bu komut istemlerinin her biri için varsayılan değerleri yapılandırabilirsin , örneğin bir Varsayılan Seçenekle Bilgi İsteme konusundaki eğitimimde açıkladığım yöntemlerden birini kullanarak :

(setq sc (cond ((getreal "\nSpecify scale <1.0>: ")) (1.0)))

4. Yerel ve Global Değişkenler

Şu anda, programınızdaki tüm değişkenler global değişkenlerdir: yani belge (çizim) ad alanı içinde tanımlanırlar ve program çalışmasını tamamladıktan sonra bile değerlerini korurlar.

Değişkenleri Yerelleştirme konusundaki eğitimimde açıkladığım gibi , bu tür değişkenler yanlışlıkla adlarını diğer programlar tarafından kullanılan genel değişkenlerle paylaşırsa veya bir program bir döngü içinde bir liste veya başka hesaplamalı veri yapısı oluşturuyorsa, bu potansiyel olarak sorunlara neden olabilir.

Programın doğru çalışması için global bir değişkenin kullanılması gerekmedikçe, bu değişkenleri işleve göre yerel olarak bildirmenizi öneririm, örneğin:

(defun c:pointnumber ( / ic inr md nr ph point px sc ) ;; Local variables

    ;; ...

)

5. Blok Varlığını Kontrol Etme

Blok adının doğrudan INSERTkomuta verilmesi, ya bu bloğun bir tanımının aktif çizimde zaten mevcut olduğunu ya da bu dosya adına sahip bir çizimin ya çalışma dizininde ya da bir AutoCAD Destek Dosyası Arama Yolunda mevcut olduğunu varsayar - eğer koşullardan hiçbiri karşılanmazsa, INSERTkomut program uygulaması sırasında hata olur.

Bu nedenle, bu koşulları önceden test edebilir, blok bulunamazsa kullanıcıyı bilgilendirebilir, aksi takdirde işlemlerin geri kalanını yürütmeye devam edebilirsiniz:

(if
    (or
        (tblsearch "block" "pointnumber") ;; Checks for existing definition
        (findfile "pointnumber.dwg")      ;; Checks for drawing file
    )
    ;; ...
)

condİşlevi bir dizi if/elseifade yerine de kullanabilirsiniz .

6. Hata Durumunda Ortamı Sıfırlama

Program yürütme sırasında sistem değişken değerlerini değiştirdiğiniz için, program yürütülürken bir hata olması durumunda kullanıcının AutoCAD ortamının orijinal durumuna sıfırlandığından emin olmalısınız - kullanıcının Escprogramdan çıkmak için basmasının da bir hata.

Bunu, Hata İşleme konusundaki eğitimimde anlattığım gibi, yerel bir hata işleyici tanımlayarak gerçekleştirebilirsiniz . Yerel hata işlevi, program yürütülürken bir hatayla karşılaşılırsa değerlendirilir ve böylece AutoCAD ortamını orijinal durumuna sıfırlamak için bu işlevin tanımına ifadeler dahil edebilirsiniz - sizin durumunuzda bu, orijinal değerinin sıfırlanmasını içerir. ATTDIAsistem değişkeni.

Hepsini bir araya koy

;; Define function, declare local variables
(defun c:pointnumber ( / *error* bn ic nr ns pt px sc vl vr )

    ;; Define local error function to reset system variables on error
    (defun *error* ( msg )
        (mapcar 'setvar vr vl) ;; Reset list of system variables
        (if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
            (princ (strcat "\nError: " msg))
        ) ;; end if
        (princ)
    ) ;; end defun

    ;; Define block name
    (setq bn "pointnumber")

    (if (or (tblsearch "block" bn)        ;; Definition in drawing
            (findfile (strcat bn ".dwg")) ;; Drawing file in support path
        ) ;; end or
        (progn
            (initget 6) ;; Prevents 0 & negatives
            (setq sc (cond ((getreal "\nSpecify scale <1.0>: ")) (1.0))
                  px (getstring "\nSpecify prefix <none>: ")
            ) ;; end setq
            (initget 4) ;; Prevents negatives
            (setq nr (cond ((getint "\nSpecify starting number <1>: ")) (1)))
            (initget 6) ;; Prevents 0 & negatives
            (setq ic (cond ((getint "\nSpecify increment <1>: ")) (1)))

            (setq vr '(attreq attdia cmdecho) ;; List of system variables
                  vl  (mapcar 'getvar vr)     ;; Store current values
            ) ;; end setq
            (mapcar 'setvar vr '(1 0 0)) ;; Set system variables appropriately
            (while (setq pt (getpoint "\nSpecify point <exit>: "))
                (setq ns (itoa nr)
                      nr (+ nr ic)
                )
                (repeat (- 3 (strlen ns)) (setq ns (strcat "0" ns))) ;; Pad to 3 digits
                (command "_.-insert" bn "_S" sc "_R" "0" "_non" pt (strcat px ns))
            ) ;; end while
            (mapcar 'setvar vr vl) ;; Reset list of system variables to their original values
        ) ;; end progn
        ;; Else the block was not defined/found
        (princ (strcat "\nThe block \"" bn "\" is not defined in the active drawing and cannot be found."))
    ) ;; end if
    (princ) ;; Suppress the value returned by the last evaluated expression
) ;; end defun

Aşağıdakiler gibi uygulanabilecek başka olası iyileştirmeler de vardır:

  • DXF verilerini doğrudan çizim veritabanına yazmak INSERTiçin ActiveX insertblockyöntemini veya entmake/ entmakexişlevlerini kullanarak standart AutoCAD komutlarına (bu durumda komut) yapılan çağrılara olan bağımlılığın kaldırılması .

  • Öznitelik referanslarının blok referansı içinde karşılaşıldığı sıraya olan bağımlılığı ortadan kaldırmak için nitelik etiket adlarına referans vererek nitelikleri doldurmak ( BATTMANkomut kullanılarak her çizim temelinde değiştirilebilir ).

  • (Benim de tarif edilen bir 'dinamik varsayılan' kullanılması öğretici ), ve potansiyel olarak çizim oturumları arasındaki varsayılan değeri hesaplanması ve saklanması.