Đến nội dung


Hình ảnh
- - - - -

[Thảo luận] - Kiểm soát lỗi (có thể) phát sinh khi người dùng nhấn Esc để thoát lệnh


  • Please log in to reply
44 replies to this topic

#1 ThuyLinh313

ThuyLinh313

    biết lệnh mtext

  • Members
  • PipPipPipPip
  • 288 Bài viết
Điểm đánh giá: 142 (tàm tạm)

Đã gửi 18 January 2013 - 10:37 AM

Vấn đề này không mới. Mình đã tìm thấy một vài đoạn code trong diễn đàn có sử dụng các phương pháp để kiểm soát lỗi và nhận thấy rằng: Tuy vấn đề này không khó nhưng không phải ai cũng làm tốt nó, kể cả là với một vài cái tên có tiếng tăm trong diễn đàn này. Bởi vậy mình nghĩ là topic này sẽ có ích không chỉ với các bạn mới học lisp. Nếu những bạn có kinh nghiệm viết lisp có phương pháp hay hơn xin hãy cùng thảo luận và chia sẻ để chúng ta có 1 phương pháp tối ưu cho tất cả.

(Nếu các bạn ngại đọc thì chỉ cần copy code ở phần 2 về và xem hướng dẫn dùng ở phần 3)

1) Hàm thông báo lỗi *Error*: Mình nói qua 1 chút về hàm này để các bạn mới viết lisp nắm được: *error* là 1 hàm đặc biệt, nói thật là mình cũng không biết phải gọi nó là 1 hàm hay 1 biến nữa, bởi nó có tính chất của cả 2. Hàm này được gọi ngay khi người dùng nhấn nút Esc tại bất cứ thời điểm nào trong khi thực hiện 1 lệnh lisp. Là 1 hàm hệ thống nhưng nó cho phép lập trình viên định nghĩa lại chính nó như cách chúng ta định nghĩa 1 hàm con bằng defun. Lợi dụng tính chất này chúng ta có thể điều khiển cách ứng xử của chương trình mỗi khi người dùng nhất Esc.
1 ví dụ đơn giản cho các bạn dễ hiểu: Nếu muốn thay thông báo lỗi khi Esc bằng 1 đoạn chuỗi "Cadviet.com" thì bạn định nghĩa lại *error* như sau:
(defun *error* (msg) (prompt "cadviet.com") (princ)). Trong đó: msg (messenger) là tham số bắt buộc khi định nghĩa *error*

2) Ứng dụng: Vì xây dựng 1 phương phát tổng quát nên dĩ nhiên là mình sẽ viết nó dưới dạng các hàm con để cho tiện sử dụng. Tất cả sẽ gói gọn vào 3 hàm:
Hàm thứ nhất: goback-defun - sẽ được gọi khi nhấn nút Esc

(defun goback-defun (msg / lst-var)
(redraw)
(command "undo" "end")
(command "undo" "")
(setq *error* (car lst-var)));end

Hàm thứ 2: start-defun - đặt vào đầu code lisp của bạn
đối số lst-var là danh sách biến hệ thống mà bạn sẽ thay đổi khi viết lisp. VD: '("Dimzin" "Osmode" "Textstyle"...)
(defun start-defun (lst-var / err)
(setvar "cmdecho" 0)
(command "undo" "begin")
(setq err *error* *error* goback-defun)
(list err (mapcar '(lambda (x) (list x (getvar x))) lst)));end

Hàm thứ 3: done-defun - đặt vào cuối code lisp của bạn
đối số lst-var là kết quả trả về của hàm start-defun
(defun done-defun (lst-var / )
(mapcar '(lambda (x) (setvar (car x) (cadr x))) (cadr lst-var))
(setq *error* (car lst-var))
(command "undo" "end")(princ));end


3) Cách dùng: Khi đã có 3 hàm trên trong thư viện hàm con thì khi viết code 1 bạn dùng nó như sau:

(defun C:Lenh (/ lst ...)
(setq lst (start-defun lst-var))
....code chương trình của bạn....
(done-defun lst));end defun

Với cách làm như trên thì bất kể khi nào người dùng nhất Esc hàm *error* sẽ trả lại trạng thái ban đầu trước khi gõ lệnh cho bạn (bao gồm tất cả biến hệ thống, trục tọa độ ucs, tọa độ màn hình ....)

 

Update: Code mới với thuật toán mới xịn hơn tại bài số #41 - Trang 3


  • 3

#2 ketxu

ketxu

    Copier - Paster - Editor

  • Moderator
  • PipPipPipPipPipPipPip
  • 5678 Bài viết
Điểm đánh giá: 2605 (tuyệt vời)

Đã gửi 18 January 2013 - 11:18 AM

Bạn TL hay quá ^^
Mình góp thêm 1 chút : một hàm con, hay 1 biến khi đã được định nghĩa là cục bộ, thì khi kết thúc hoặc ngắt lệnh (kể cả bình thường hay ESC), giá trị của biến/ hàm sẽ trả về như cũ (như trước khi chạy hàm mẹ)
Vì vậy bước lưu giữ trạng thái của hàm *error* là không cần thiết
  • 1

Thành viên nhóm CadMagic.
Mời bạn ghé thăm facebook nhóm - Page viết lisp theo yêu cầu  :
CAD MAGIC


#3 ThuyLinh313

ThuyLinh313

    biết lệnh mtext

  • Members
  • PipPipPipPip
  • 288 Bài viết
Điểm đánh giá: 142 (tàm tạm)

Đã gửi 18 January 2013 - 10:03 PM

Hiện giờ mình không có cad nên chưa có điều kiện kiểm tra lại. Nhưng theo ý của Ketxu thì để bỏ được bước lưu giữ trạng thái của *error* đi thì cần phải định nghĩa nó là hàm cục bộ. Theo đó thì mỗi khi dung ta cần phải khai báo nó là hàm cục bộ ở lisp chính. Như vậy có thể bỏ luôn hàm goback-defun, nhưng sẽ rườm rà hơn 1 chút vì sẽ cần khai báo thêm *error* là hàm cục bộ. Dù sao thế cũng hay hơn. Đê mai mình thử xem thế nào. Cảm ơn Ketxu về nhận xét trên của bạn ^^
  • 0

#4 Doan Van Ha

Doan Van Ha

    biết lệnh adcenter

  • CADViet Team
  • PipPipPipPipPipPipPip
  • 5447 Bài viết
Điểm đánh giá: 2624 (tuyệt vời)

Đã gửi 18 January 2013 - 10:12 PM

Cũng na ná là đây nữa:
http://www.cadviet.c...showtopic=68682
  • 0

* Chỉ nên yêu cầu Lisp khi bạn làm việc đó mất cả ngày nhưng họ chỉ viết 1 giờ. Đừng nêu yêu cầu Lisp khi bạn chỉ làm 1 giờ nhưng bắt họ phải mất cả ngày.

* Nhờ viết lisp cũng như đi khám bệnh. Chỉ gởi căn cước và than sắp chết thì không bác sỹ nào cứu sống được.


#5 ThuyLinh313

ThuyLinh313

    biết lệnh mtext

  • Members
  • PipPipPipPip
  • 288 Bài viết
Điểm đánh giá: 142 (tàm tạm)

Đã gửi 18 January 2013 - 11:09 PM

Bạn là người luôn có những quy tắc khắt khe và có phần kĩ tính, nhưng thật lòng mà nói thì lisp trong link đó bạn viết hơi tệ ĐVH ạ. Vì nó không gọn gàng cả trong code và trong khi sử dụng. Hi vọng bạn không tự ái vì nhận xét này của mình :)
  • 0

#6 ThuyLinh313

ThuyLinh313

    biết lệnh mtext

  • Members
  • PipPipPipPip
  • 288 Bài viết
Điểm đánh giá: 142 (tàm tạm)

Đã gửi 19 January 2013 - 09:03 AM

Phương pháp thứ 2 sửa theo ý kiến của bạn Ketxu: Chỉ cần 2 hàm con Start-defun và Done-defun là đủ. Thực chất vẫn là 3 hàm như phương pháp trên nhưng mình đưa hàm Goback-defun vào bên trong hàm Start-defun cho gọn.

(defun Start-defun (lst-var)
(defun *error* (msg)
(redraw)
(command "undo" "end")
(command "undo" "")
(princ));end
(command "undo" "begin")
(mapcar '(lambda(x) (list x (getvar x))) lst-var));end
;;;
(defun Done-defun (lst-var / )
(mapcar '(lambda (x) (setvar (car x) (cadr x))) lst-var)
(command "undo" "end")
(princ));end
Cách dùng thì vẫn như phương pháp trên nhưng bạn phải khai báo thêm hàm *error* là hàm cục bộ vào lisp của bạn:
(defun C:Lenh (/ lst *error*)
(setq lst (start-defun lst-var))
....code chương trình của bạn....
(done-defun lst));end defun
  • 0

#7 nhoclangbat

nhoclangbat

    Edu level: li10

  • Members
  • PipPipPipPipPipPipPip
  • 1409 Bài viết
Điểm đánh giá: 379 (khá)

Đã gửi 19 January 2013 - 10:15 AM

nhoc chưa hỉu cách use lắm chị linh có thể hướg dẫn cụ thể xíu đc ko ah ^^, vd trong cơ quan nhoc có lso test kích thước , trong đó người viết đã viết mà nhoc thấy đa số lsp khác cũng hay dùng, đó là lưu lại biến osmode hiện tại sau đó set biến mới cho nó ở lsp nhoc nói là người viết set osmode chỉ bắt điểm cuối trong quá trình use lsp khi kết thúc lệnh sẽ trả lại osmode ban đầu, nhưng có lúc đc có lúc ko, sau khi thoát lệnh nó mất lun các giá trị biến osmode ban đầu nghĩa là tắt lun bắt điểm ko còn bắt đc điểm nào, ở 1 topic khác bac Ha cũng có cho nhoc 1 đoạn code phục vụ mục đích này nhưng củg vậy, bac Ha nói nếu có lỗi thì phải dùng 1 cách khác. Vậy hàm chị Linh viết có khắc phục đc lỗi này ko ạ ^^
  • 0
"...................][)e\/i][_ /\/\@Y CrY....................."

(defun THỔ_DÂN_HỌC_CAD (xxxx) ...) ^_^








#8 ThuyLinh313

ThuyLinh313

    biết lệnh mtext

  • Members
  • PipPipPipPip
  • 288 Bài viết
Điểm đánh giá: 142 (tàm tạm)

Đã gửi 19 January 2013 - 10:57 AM

Một ví dụ đơn giản cho Nhóc hiểu nhé.
Giả sử Nhóc viết 1 lệnh vẽ line bằng command trong đó có thay đổi các biến hệ thống OSMODE (tắt bắt điểm) và ORTHOMODE (tắt vẽ chế độ vẽ theo trục tọa độ). Khi đó Nhóc viết thế này:
(defun C:VD (/ lst *error* p p1)
(setq lst (start-defun '("OSMODE" "ORTHOMODE")))
(setvar "osmode" 0)
(setvar "orthomode" 0)
(setq p (getpoint)) p1 (getpoint p))
(command "line" p p1"")
(done-defun lst));end vd
Giải thích:
- Việc lấy các giá trị ban đầu của các biến hệ thống OSMODE và ORTHOMODE do hàm start-defun đảm nhận và lưu giá trị vào biến lst
- Việc trả lại các giá trị ban đầu cho các biến trên sẽ do hàm done-defun đảm nhận khi kết thúc lệnh
- Nếu nhấn esc giữa chừng thì hàm con *error* (đã khai báo ben trong hàm start-defun) được gọi. nó sẽ thực hiện thao tác undo back về thời điểm trước khi gõ lệnh
* Về bản chất thì nó giống như cách ĐVH hướng dẫn nhóc, nhưng cách này gọn gàng hơn, sẽ khiến Nhóc đỡ cực hơn khi viết.
=================================================
PS: Thêm 1 chút cho các bạn chưa biết:
"Nếu có lỗi" như ĐVH nói thì TL chỉ biết 1 trường hợp duy nhất có thể sảy ra lỗi là do hàm *error* không được gọi khi nhấn Esc. Nguyên nhân do tại thời điểm nhấn Esc, Cad đang ở trạng thái Active command. (sự kiện vlr-commandWillStart). Như ở Mục 1 TL đã nói về hàm *error*, nó chỉ được gọi khi chạy lệnh lisp.
Vì vậy, nếu lỗi là do trường hợp này thì chỉ cần khắc phục như sau chứ không cần tìm cách khác: Nếu trong lisp có sử dụng command thì không nên cho hàm lisp vào trong command nữa. Như trong ví dụ trên thì không nên viết như thế này (command "Line" (getpoint) (getpoint) "")
Ngoài lỗi này thì TL chưa bao giờ gặp lỗi nào khác
  • 1

#9 LoveLisp

LoveLisp

    biết lệnh extend

  • Members
  • PipPipPip
  • 195 Bài viết
Điểm đánh giá: 20 (tàm tạm)

Đã gửi 19 January 2013 - 02:05 PM

Nếu đã biết rõ là do Active Command thì liệu có cách nào khắc phục triệt để không bạn (mà vẫn giữ nguyên hàm lisp trong dòng command) ?
  • 0

#10 ketxu

ketxu

    Copier - Paster - Editor

  • Moderator
  • PipPipPipPipPipPipPip
  • 5678 Bài viết
Điểm đánh giá: 2605 (tuyệt vời)

Đã gửi 19 January 2013 - 02:33 PM

Hãy dùng vl-cmdf để định giá thay vì command :)
Command cũng là một hàm lisp. Trong trường hợp ví dụ của TL nếu người dùng ESC thì hàm *error* vẫm được gọi, chỉ có điều sau đó nó tiếp tục chạy tiếp hàm command ^^
  • 1

Thành viên nhóm CadMagic.
Mời bạn ghé thăm facebook nhóm - Page viết lisp theo yêu cầu  :
CAD MAGIC


#11 quansla

quansla

    biết lệnh xclip

  • Members
  • PipPipPipPipPipPipPip
  • 641 Bài viết
Điểm đánh giá: 223 (khá)

Đã gửi 19 January 2013 - 03:01 PM

Các bác cho em hỏi, em hiểu rất lơ mơ về vấn đề hàm *error* này, chỉ toàn áp dụng thôi, kết quả thì vẫn OK là được, thấy các bác phân tích thảo luận, cảm thấy rất vui(thanks các bác nhiều) có điều vẫn chưa hiểu lắm.
Em có mấy câu hỏi thế này
  • Nếu dùng như bác chủ topic nói thì có nghĩa là với một lisp bất kỳ muốn bắt hủy lệnh ESC của người dùng thì dùng thêm Hàm start-defun ( một hàm định nghĩa lại hàm của *error*) cũng có nghĩa là nếu có 5,10,15,.. lisp phân biệt,khác nhau trong cùng một file .lsp thì trong đó tồn tại 5,10,15 lần định nghĩa lại cùng một hàm (start-defun) đúng không (vì em nghĩ nếu tách ra thì hàm nguyên bản *error* sẽ bị triệt tiêu mất
  • Nếu để hạn chế việc khai báo nhiều như vậy thì có cách nào khác không ?(khai báo một lần hàm (defun-error),(done-eror) và áp dụng cho các lisp tiếp sau). Trước nay thì em vẫn dùng các hàm của (ace-*) nhưng đã nghiên cứu thì cũng nên bỏ công tý, nên mong các bác giúp đỡ cho.
Xin cảm ơn các bác, chúc mọi người luôn khỏe, cống hiến nhiệt tình, gặp nhiều niềm vui,may mắn và hạnh phúc
  • 0

#12 ThuyLinh313

ThuyLinh313

    biết lệnh mtext

  • Members
  • PipPipPipPip
  • 288 Bài viết
Điểm đánh giá: 142 (tàm tạm)

Đã gửi 19 January 2013 - 03:18 PM

Ketxu nhận định chính xác! Mình quên mất rằng Command cũng là 1 hàm lisp ^^
Vậy xin đính chính là: *error* không được gọi khi đang sử dụng các command của cad (lệnh cad), nhưng vẫn được gọi nếu đang dùng hàm command.

@quansla:
1. Bạn đọc lại bài #2 của Ketxu nhé. Sau đó xem lại phần hướng dẫn trong #8 của mình. trong đó *error* đã định nghĩa là hàm cục bộ thì sau khi kết thúc lệnh *error* sẽ trở về nguyên trạng.
2. Bạn đang viết lisp "một cách rời rạc": nghĩa là mỗi ứng dụng bạn viết trên 1 file với tất cả hàm con cần thiết cho nó có thể chạy được nên mới thắc mắc như vậy. Bạn nên xây dựng cho mình 1 thư viện hàm con, thư viện hàm đó sẽ được tự động load khi khởi động Cad. khi đó không cần bận tâm có hay không các hàm trên trong file lisp của bạn, vì nó đã được tải sẵn vào bộ nhớ cho bạn dùng rồi.
  • 0

#13 nhoclangbat

nhoclangbat

    Edu level: li10

  • Members
  • PipPipPipPipPipPipPip
  • 1409 Bài viết
Điểm đánh giá: 379 (khá)

Đã gửi 19 January 2013 - 03:28 PM

nhoc thắc mắc tí nếu load sẵn bộ nhớ trong cad, vậy với mỗi file lsp, trong đó có nhiều ứng dụng thì khi sử dụng xong 1 ứng dụng (a) >> hàm error sẽ bị khử vì nó đc set trong biến cục bộ như anh Ket dạy vậy nếu nhoc đi lòng vòng đâu đó sử dụng các ứng dụng khác, sau đó lại sử dụng lại ứng dụng (a) đó >> hàm error theo lý thuyết sẽ ko còn tác dụng ^^, vậy trong trường hợp này thực tế hàm error đó còn sử dụng đc trong ứng dụng (a) đó ko chị Linh
Ps: Nhoc mới học bập bẹ nên có thể hỉu chưa tới đừng la nhoc hen :D
  • 0
"...................][)e\/i][_ /\/\@Y CrY....................."

(defun THỔ_DÂN_HỌC_CAD (xxxx) ...) ^_^








#14 ThuyLinh313

ThuyLinh313

    biết lệnh mtext

  • Members
  • PipPipPipPip
  • 288 Bài viết
Điểm đánh giá: 142 (tàm tạm)

Đã gửi 19 January 2013 - 03:36 PM

- Mỗi lần dùng ứng dụng (a) thì cũng là mỗi lần *error* được định nghĩa lại (thông qua hàm start-defun)
- Sau khi dùng xong ứng dụng (a) thì *error* được trả về nguyên trạng như trước khi chạy (a) chứ không phải bị khử (= nil) Nhóc nhé.
  • 1

#15 ketxu

ketxu

    Copier - Paster - Editor

  • Moderator
  • PipPipPipPipPipPipPip
  • 5678 Bài viết
Điểm đánh giá: 2605 (tuyệt vời)

Đã gửi 19 January 2013 - 06:19 PM

@TL : nếu quickcode thì OK, full thì tránh dùng command ngay trong hàm *error*, bạn sẽ gặp nó trong ví dụ ở #8 của bạn.
Lý do cũng tương tự như khi thiết lập một transparent command, đó là cad không nhận command trong command.
Bạn có thể thay bằng các method vla tương ứng
  • 1

Thành viên nhóm CadMagic.
Mời bạn ghé thăm facebook nhóm - Page viết lisp theo yêu cầu  :
CAD MAGIC


#16 Doan Van Ha

Doan Van Ha

    biết lệnh adcenter

  • CADViet Team
  • PipPipPipPipPipPipPip
  • 5447 Bài viết
Điểm đánh giá: 2624 (tuyệt vời)

Đã gửi 19 January 2013 - 06:39 PM

Bạn là người luôn có những quy tắc khắt khe và có phần kĩ tính, nhưng thật lòng mà nói thì lisp trong link đó bạn viết hơi tệ ĐVH ạ. Vì nó không gọn gàng cả trong code và trong khi sử dụng. Hi vọng bạn không tự ái vì nhận xét này của mình :)

Bạn TL thân mến!
Cái lisp đó tôi đọc ở đâu đó trên một trang web, của 1 tác giả nước ngoài, lâu quá không nhớ tên. Thấy dùng được thì đem về dùng. Sẵn bên topic kia hỏi thì tôi gởi lên để họ tham khảo, và sẵn bạn mở topic mới thì tôi cũng gởi để tham khảo luôn. Nó không phải là sáng tác của tôi. Tôi ít viết những lisp hàn lâm vì sợ không đủ sức.
Bạn đưa 1 vấn đề lên để thảo luận. Vâng, tôi chưa phê bạn 1 câu nào, mặc dầu như bạn đã thấy qua 1 loạt các góp ý thì chất lượng lisp của bạn như thế nào chắc bạn đã biết.
Tôi không nói thêm gì dài dòng, chỉ nói 1 điều này, là bạn đừng tự ái như bạn đã khuyên tôi đừng tự ái: bạn hãy suy nghĩ lại bản thân mình trước khi phán những câu xanh rờn với người khác nhé. Có như thế mới tiến bộ được.
  • 0

* Chỉ nên yêu cầu Lisp khi bạn làm việc đó mất cả ngày nhưng họ chỉ viết 1 giờ. Đừng nêu yêu cầu Lisp khi bạn chỉ làm 1 giờ nhưng bắt họ phải mất cả ngày.

* Nhờ viết lisp cũng như đi khám bệnh. Chỉ gởi căn cước và than sắp chết thì không bác sỹ nào cứu sống được.


#17 soluuhuong2903

soluuhuong2903

    biết vẽ rectang

  • Members
  • PipPip
  • 87 Bài viết
Điểm đánh giá: 22 (tàm tạm)

Đã gửi 19 January 2013 - 08:05 PM

cái này có phải hàm bẫy lỗi hok ta :)
  • 0

#18 ThuyLinh313

ThuyLinh313

    biết lệnh mtext

  • Members
  • PipPipPipPip
  • 288 Bài viết
Điểm đánh giá: 142 (tàm tạm)

Đã gửi 19 January 2013 - 10:36 PM

^^ Lại dỗi nữa rồi. Nói chuyện với bạn ĐVH hơi bị khó! có cảm giác như là bạn không bao giờ thích bị chê vậy. cứ mỗi lần mình nhận xét k tốt về code của bạn là i như rằng...(!) Thảo luận thì phải có khen và chê chứ, nịnh ngọt tai nhau sao được? ĐVH bình tĩnh đọc lai đi nhé, mình không có khuyên bạn đừng tự ái đâu. Về code trên, thì chất lượng code của mình và code sau đó mình sửa theo ý kiến của ketxu là như nhau bạn ạ, chỉ là thêm một sự lựa chọn thôi. còn nếu so với code của bạn post thì nó hơn hẳn. Lại phải hi vọng bạn nhìn nhận post này của mình với thái độ bình tĩnh và tích cực hơn
  • 0

#19 Doan Van Ha

Doan Van Ha

    biết lệnh adcenter

  • CADViet Team
  • PipPipPipPipPipPipPip
  • 5447 Bài viết
Điểm đánh giá: 2624 (tuyệt vời)

Đã gửi 19 January 2013 - 10:49 PM

Tôi không nói với bạn nhiều. Tôi chỉ có 1 nhận xét để bạn vui và 1 nhận xét để bạn buồn:
Vui trước: bạn là người giỏi nhất CV đấy.
Buồn sau: bạn là người tự cao tự đại nhất CV đấy.
Nhắc lại: code tôi post lên không phải là code của tôi để so sánh với bạn.
  • 2

* Chỉ nên yêu cầu Lisp khi bạn làm việc đó mất cả ngày nhưng họ chỉ viết 1 giờ. Đừng nêu yêu cầu Lisp khi bạn chỉ làm 1 giờ nhưng bắt họ phải mất cả ngày.

* Nhờ viết lisp cũng như đi khám bệnh. Chỉ gởi căn cước và than sắp chết thì không bác sỹ nào cứu sống được.


#20 ThuyLinh313

ThuyLinh313

    biết lệnh mtext

  • Members
  • PipPipPipPip
  • 288 Bài viết
Điểm đánh giá: 142 (tàm tạm)

Đã gửi 19 January 2013 - 11:02 PM

Trước: Dislike this!
Sau: Like this!
Nhắc: ok man ^^
  • 0