Autolisp tidak mengatur atribut blok dengan benar untuk beberapa pengguna

Dec 29 2020

Penanya pertama kali, jadi semoga saya menjelaskan masalah dengan cukup baik.

Kami memiliki kode Autolisp di perusahaan kami yang digunakan oleh beberapa individu dengan versi AutoCAD yang sama, tetapi untuk beberapa pengguna cadel berhenti berfungsi dengan benar.

Fungsi cadel adalah sebagai berikut:

  • pengguna menjalankan cadel
  • program meminta hal-hal berikut:
    • skala blok
    • awalan untuk teks dalam blok
    • nomor berjalan untuk entitas blok pertama
    • kenaikan angka lari
    • dimana menempatkan blok pertama

Ini harus mengarah ke blok dengan penanda dan teks dengan format berikut (awalan) (kemungkinan bagian tengah jika nomor tidak terdiri dari tiga nomor) (nomor berjalan), misalnya PT001 atau PX100.

Alih-alih melakukan ini, beberapa pengguna telah mengalami kekurangan awalan dan nomor dan mulai melihat hanya bagian tengah teks yang mungkin disebutkan di atas, sementara di lain waktu pengguna yang sama dapat mengalami bahwa hanya awalan yang ditampilkan. Penanda ditampilkan sebagaimana mestinya, tetapi teksnya tidak berfungsi seperti yang diharapkan.

Bantuan apa pun dalam menganalisis kode di bawah ini untuk menemukan kekurangan sangat kami hargai.

Jika kode tampaknya "tanpa cacat", saya berasumsi bahwa ada masalah dengan blok atau atributnya.

-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)
)

Jawaban

1 LeeMac Dec 30 2020 at 01:21

Ada sejumlah masalah dengan kode Anda saat ini: beberapa di antaranya mungkin hanya dianggap praktik buruk, beberapa akan menyebabkan program gagal jika pengguna merespons dengan data yang tidak valid, dan lainnya akan menyebabkan program gagal atau berperilaku tidak terduga tergantung pada pengaturan lingkungan AutoCAD tempat program dijalankan.

1. ATREQ

Penyebab utama perilaku yang telah Anda gambarkan kemungkinan besar adalah ATTREQvariabel sistem, yang menentukan apakah pengguna akan menerima petunjuk untuk nilai atribut sebagai bagian dari INSERTperintah. Jika ATTREQ=0saat program dijalankan, blok tersebut akan disisipkan dengan nilai atribut defaultnya.

Anda dapat memastikan perilaku yang konsisten antara lingkungan dengan menyimpan nilai saat ini dari variabel sistem ini dan menyetelnya ke 1sebelum memanggil INSERTperintah (untuk memastikan bahwa prompt atribut dikeluarkan), dan kemudian memulihkan nilai asli setelah perintah atau di akhir perintah. program.

Sebagai contoh:

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

    ;; ... Do your thing

    (setvar 'attreq atr)
    (princ)
)

2. OSMODE

Saat memberikan data titik ke perintah melalui AutoLISP, titik tersebut akan dipengaruhi oleh mode Jepretan Objek yang aktif pada saat titik tersebut diberikan. Saya menjelaskan ini secara lebih rinci dalam jawaban saya di sini .

Cara termudah untuk menghindari ini adalah melalui penggunaan pengubah "_non"atau "_none"objek snap untuk menginstruksikan AutoCAD untuk mengabaikan semua mode Jepretan Objek untuk input titik berikutnya, misalnya:

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

3. Masukan Pengguna

Anda harus memperhitungkan kurangnya input pengguna atau input pengguna yang tidak valid untuk menghindari kesalahan selama eksekusi program - ini mudah dicapai baik melalui penggunaan ifpernyataan atau initgetfungsi, misalnya:

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

Atau:

(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
)

Sebagai alternatif, Anda dapat mengonfigurasi nilai default untuk masing-masing prompt ini, menggunakan salah satu metode yang saya jelaskan dalam tutorial saya tentang Meminta dengan Opsi Default , misalnya:

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

4. Variabel Lokal vs. Global

Saat ini, semua variabel dalam program Anda adalah variabel global : yaitu, variabel tersebut ditentukan dalam namespace dokumen (gambar) dan akan mempertahankan nilainya bahkan setelah program menyelesaikan eksekusinya.

Seperti yang saya jelaskan dalam tutorial saya tentang Variabel Pelokalan , ini berpotensi menimbulkan masalah jika variabel tersebut secara tidak sengaja membagikan namanya dengan variabel global yang digunakan oleh program lain, atau ketika sebuah program sedang membuat daftar atau struktur data akulumatif lainnya dalam satu lingkaran.

Kecuali penggunaan variabel global diperlukan untuk pengoperasian program yang benar, saya sarankan untuk mendeklarasikan variabel-variabel tersebut secara lokal ke fungsi, misalnya:

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

    ;; ...

)

5. Memeriksa Keberadaan Blok

Memasok nama blok langsung ke INSERTperintah mengasumsikan bahwa baik definisi blok itu sudah ada dalam gambar aktif, atau bahwa gambar dengan nama file itu ada baik di dalam direktori kerja atau Jalur Pencarian File Dukungan AutoCAD - jika tidak ada kondisi yang terpenuhi, yang INSERTperintah akan error selama eksekusi program.

Oleh karena itu, Anda dapat menguji kondisi ini sebelumnya, memberi tahu pengguna jika blok tidak ditemukan, jika tidak melanjutkan untuk menjalankan operasi lainnya:

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

Anda juga dapat menggunakan condfungsi sebagai pengganti urutan if/elseekspresi.

6. Mengatur Ulang Lingkungan pada Kesalahan

Karena Anda mengubah nilai variabel sistem selama eksekusi program, Anda harus memastikan bahwa lingkungan AutoCAD pengguna diatur ulang ke keadaan semula jika terjadi kesalahan selama eksekusi program - mencatat bahwa pengguna menekan Escuntuk keluar dari program juga akan menghasilkan kesalahan.

Anda dapat melakukannya dengan menentukan penangan kesalahan lokal, seperti yang saya jelaskan dalam tutorial saya tentang Penanganan Kesalahan . Fungsi kesalahan lokal dievaluasi jika kesalahan ditemukan selama eksekusi program, dan sehingga Anda dapat menyertakan ekspresi dalam definisi fungsi ini untuk mengatur ulang lingkungan AutoCAD ke keadaan aslinya - dalam kasus Anda, ini akan melibatkan pengaturan ulang nilai asli dari ATTDIAvariabel sistem.

Menyatukan semuanya

;; 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

Ada kemungkinan perbaikan lain yang juga dapat diterapkan, seperti:

  • Menghapus ketergantungan pada panggilan ke perintah AutoCAD standar (dalam hal ini INSERTperintah) melalui penggunaan insertblockmetode ActiveX atau entmake/ entmakexfungsi untuk menulis data DXF langsung ke database gambar.

  • Mengisi atribut dengan mereferensikan nama tag atributnya untuk menghilangkan ketergantungan pada urutan di mana referensi atribut ditemukan dalam referensi blok (yang dapat dimodifikasi per gambar melalui penggunaan BATTMANperintah).

  • Menggunakan 'default dinamis' (seperti yang dijelaskan dalam tutorial saya ), dan berpotensi menyimpan nilai default di antara sesi menggambar.