AutoLISP is a great language for combining a few basic AutoCAD commands together or creating complex logic. To get the most out of AutoLISP, you will need to request input from the user and the type of input you need will depend on which AutoCAD commands or functions you are using.
This article is not about the individual input functions themselves, but how to handle the dreaded ESC key when the user is being prompted for input.
NOTE: This topic does apply to AutoCAD on Windows and Mac.
The following sample code shows the use of the INITGET and GETPOINT AutoLISP functions. If you load and run the code in AutoCAD it will allow you to pick a point or Line or Circle as a keyword. When being prompted, press ESC and the message "Completed successfully." is never displayed because the AutoLISP function was terminated.
(defun c:GetInputNoErrHandling( / returnPnt)
;; Define the valid keywords
(initget 128 "Line Circle")
;; Get the user input
(setq returnPnt (getpoint "Enter a point [Line/Circle]: "))
(if (/= returnPnt nil)
(cond
((= (type returnPnt) 'LIST)
(alert (strcat "User provided the point: "
(rtos (nth 0 returnPnt) 2) ", "
(rtos (nth 1 returnPnt) 2) ", "
(rtos (nth 2 returnPnt) 2)))
)
((= (type returnPnt) 'STR)
(alert (strcat "User selected the keyword: " returnPnt))
)
)
(alert "No point was picked.")
)
(alert "Completed sucessfully!")
)
For many, this is a deal breaker in their code as they often leave system variables changed or tasks uncompleted. To help clean this up, you can introduce an error handler block that helps to catch the error so you can make any changes as needed to end as graceful as possible. The error handler block is a new function that AutoCAD calls and is named *error*.The downside to this approach is that you have stepped out of the main execution of your code so there really is no easy way to pick up the pieces and continue on.
The following shows a very basic example of the error handler block. Now when the user presses ESC when being prompted for input, the GetPoint function ends but you get a message about the error that is generated indicating a point you could clean things up in as needed.
(defun c:GetInputErrHandlingBlock( / returnPnt)
(setq old_err *error*)
(defun *error* (err_msg)
(alert (strcat "Error: " err_msg))
(setq *error* old_err)
)
;; Define the valid keywords
(initget 128 "Line Circle")
;; Get the user input
(setq returnPnt (getpoint "Enter a point [Line/Circle]: "))
(if (/= returnPnt nil)
(cond
((= (type returnPnt) 'LIST)
(alert (strcat "User provided the point: "
(rtos (nth 0 returnPnt) 2) ", "
(rtos (nth 1 returnPnt) 2) ", "
(rtos (nth 2 returnPnt) 2)))
)
((= (type returnPnt) 'STR)
(alert (strcat "User selected the keyword: " returnPnt))
)
)
(alert "No point was picked.")
)
(alert "Completed sucessfully!")
(setq *error* old_err)
)
The final example is the best approach, but is the least commonly used approach from what I have seen among AutoLISp developers. This approach uses the VL-CATCH-ALL-APPLY and VL-CATCH-ALL-ERROR-MESSAGE functions. Instead of being forced out of your main function when the user presses ESC, you have the ability to trap the error and handle right there. You could still use the error handler block for truly unexpected errors, but you should always code for things you know a user might encounter or do. Pressing ESC is a common thing users do in AutoCAD, so you should handle it.
When the following code is loaded and executed, pressing ESC is caught and handled properly so the code can finish as expected.
(defun c:GetInputWithErrCatching( / returnPntOrErr)
;; Define the valid keywords
(initget 128 "Line Circle")
;; Get the user input
(setq returnPntOrErr (vl-catch-all-apply 'getpoint (list "Enter a point [Line/Circle]: ")))
(if (= (type returnPntOrErr) 'VL-CATCH-ALL-APPLY-ERROR)
(alert (strcat "Error: " (vl-catch-all-error-message returnPntOrErr)))
(cond
((= returnPntOrErr nil)
(alert "No point was picked.")
)
((= (type returnPntOrErr) 'LIST)
(alert (strcat "User provided the point: "
(rtos (nth 0 returnPntOrErr) 2) ", "
(rtos (nth 1 returnPntOrErr) 2) ", "
(rtos (nth 2 returnPntOrErr) 2)))
)
((= (type returnPntOrErr) 'STR)
(alert (strcat "User selected the keyword: " returnPntOrErr))
)
)
)
(alert "Completed sucessfully!")
)
Sincerely,
Lee
Comments