Тема: прерывание lisp программ по нажатию клавиши Esc

как организовать корректное прерывание программы, если пользователем нажата клавиша ESc. Т.е. вернуться к исходному состоянию чертежа  до запуска программы.

Re: прерывание lisp программ по нажатию клавиши Esc

Однажды я тоже пришёл сюда с таким же вопросом, но....!
Принцип:
1. делаешь функцию сохранения параметров
(defun STORE ()
   (setq OLDSNAP (getvar "osmode"))
   (setq OLDLR (getvar "clayer"))
   (setvar "osmode" 0)
   (setvar "cmdecho" 0)
) ;_ end of defun

2. делаешь функцию востановления параметров
(defun RESTORE ()
   (if OLDLR (setvar "clayer" OLDLR))
   (if OLDSNAP (setvar "osmode" OLDSNAP))
   (setvar "cmdecho" 1)
   (princ)
   )

3. создаёшь свой обработчик ошибок
(defun NNN_ERROR_HANDLER (MSG)
   (if
     (or
       (= MSG "завершить / выйти прервать")
       (= MSG "quit / exit abort")
     ) ;_ end of or
      (princ "Error!..................................")
      (princ MSG)
   ) ;_ end of if
   (command "_.UNDO" "_end")
   (command "_.U")
   (RESTORE)
   (setq *ERROR* OLDERROR)
   (princ)
) ;_ end of defun

4. В своей проге пишешь
(defun YOURPROG ()
(store)
(command "_.UNDO" "_begin")
(setq OLDERROR *ERROR*)
(setq *ERROR* NNN_ERROR_HANDLER)
.......
......
......
(command "_.UNDO" "_end")
(setq *ERROR* OLDERROR)
(restore)
)

5. Вот и всё

Re: прерывание lisp программ по нажатию клавиши Esc

спасибо. все получилось.

Re: прерывание lisp программ по нажатию клавиши Esc

А как сделать обработчик ошибок для
VLX приложения работающего в собственном
пространстве имён ?

Re: прерывание lisp программ по нажатию клавиши Esc

Неужели никто не знает.
Дайте хоть такой ответ - незнаю.

Re: прерывание lisp программ по нажатию клавиши Esc

А в чем собственно разница, VLX или исходный текст? Неужели предложенный вариант не работает?

Re: прерывание lisp программ по нажатию клавиши Esc

Насколько я понимаю VLX приложение с отдельным пространством имён не знает функции *ERROR*.
Недаром есть функция vl-exit-with-error,
и если в своей программе
(которая будет работать в отдельном пространстве имён) написать (setq OLDERROR *ERROR*) ничего не выйдет.

Re: прерывание lisp программ по нажатию клавиши Esc

Есть программа:

(defun c:a1 (/)
…
(b1)
(b2)
…)
(defun b1 (/)
…
(c1)
…)
(defun b2 (/)
…)
(defun c1 (/)
…)
(defun *error* (/)
…)

Так вот, когда ошибка\сбой происходят в команде а1  то функция *error* срабатывает, а когда ошибка\сбой происходят в функциях b1,b2,c1, то *error* не срабатывает.
На сколько возможно предотвратил появление ошибок IF-ами, WILE-ми на NIL и различными фильтрами, но от Esc это не спасает, что в принципе наверно тоже можно предусмотреть. Всё это усложняет код, да и кроме Esc бывют "чудеса техники"
Читал про vl-catch-all-appley – чувствую, что должна как-то помочь, а как не пойму?

Re: прерывание lisp программ по нажатию клавиши Esc

(setq res
  (vl-catch-all-apply
    (function
      (lambda ()
       ; здесь пишешь код точно так же, как и при создании любой функции через defun.
       ; В результате, будет создана безымянная функция (lambda)
       ; и тут же выполнена (vl-catch-all-apply). Результат последнего выражения окажется в res.
       ; При этом, в случае возникновения ошибки в переменную res будет помещен специальный объект,
       ; содержащий описание ошибки.
      )
    )
  )
);
; Прочитать информацию об ошибке можно так:
(if (vl-catch-all-error-p res) (setq msg (vl-catch-all-error-message res)));

Re: прерывание lisp программ по нажатию клавиши Esc

Пстух
Спасибо, что откликнулся.
1) Функция Lambda - безымянна и одноразового применения, а у меня в программе их(функций) много, и к половине из них я обращаюсь  неоднократно и из разных мест?
2)

Пастух пишет:

Прочитать информацию об ошибке можно так:
(if (vl-catch-all-error-p res) (setq msg (vl-catch-all-error-message res)));

т.е. при возникновении ошибки программа не прерывается, а работает дальше, даёт возможность проверить была-ли ошибка, и почему она возникла, выполняет мои операторы по восстановлению системных параметров, и тихо, корректно завершает работу программы?

Re: прерывание lisp программ по нажатию клавиши Esc

(defun _dwgru-error-catch (protected-function
                           on-error-function
                           /
                           catch_error_result
                           )
                          ;|
*** Функция взята из книжной версии ruCAD'a без каких бы то ни было переделок,
*** кроме переименования.
*    Оболочка отлова ошибок.
*    Параметры вызова:
*    protected-function    - "защищаемая" функция
*    on-error-function    - функция, выполняемая в случае ошибки
|;
  (setq catch_error_result (vl-catch-all-apply protected-function))
  (if (and (vl-catch-all-error-p catch_error_result)
           on-error-function
           ) ;_ end of and
    (apply on-error-function
           (list (vl-catch-all-error-message catch_error_result))
           ) ;_ end of apply
    catch_error_result
    ) ;_ end of if
  ) ;_ end of defun

Пример вызова:

(defun test (/ res)
  (_dwgru-error-catch
    (function
      (lambda ()
        (setq res (/ 5 0.))
        ) ;_ end of lambda
      ) ;_ end of function
    '(lambda (x) (princ (strcat "\n ** Ошибка : " x)))
    ) ;_ end of _dwgru-error-catch
  res
  ) ;_ end of defun

Re: прерывание lisp программ по нажатию клавиши Esc

Пусть имеется функция

(defun user-input (str) (getpoint str))

Данная функция приведет к сбою, если пользователь нажмет ESC во время запроса.
Чтобы этого не случилось, необходимо вызывать её через vl-catch-al-apply:

(setq res (vl-catch-all-apply 'user-input (list "Укажите точку: ")))

После чего анализировать res и принимать решение:

(cond
  ((vl-catch-all-error-p res); была нажата ESC:
    ; действия в ситуации, когда пользователь прервал ввод.
  )
  (T; функция успешно выполнена и res содержит список с координатами точки.
    ; Использование полученного результата
  )
)

В блок vl-catch-all-apply с помощью lambda-функции можно упаковать вызов сразу нескольких функций, потенциально генерирующих ошибки так, как я указал в первом посте.

(изменено: Disney, 3 апреля 2009г. 14:33:57)

Re: прерывание lisp программ по нажатию клавиши Esc

Спасибо!
Кулик Алексей aka kpblc - что подсказали
Пастух - что разжевали

Но, чуть-чуть не доходит, пожалуйста на моём примере покажите

;;;;;;
(defun c:test (/ s oldosm t1 t2)
  (setq oldosm (getvar "osmode"))
  (setvar "osmode" 41)
  (initget "Д Н")
  (princ)
  (setq s (getkword "\n Будем рисовать? [Да/Нет] <Д>:"))
  (If (or (= s "Д") (= s "д") (= s nil))
    (vvod)
  )
)
;;;;;;
(defun vvod (/)
  (while
    (and
      (setq t1 (getpoint "\nt1"))
      (setq t2 (getpoint "\nt2"))
      (ris)

    )
  )
)
;;;;;;
(defun ris (t1 t2 /)
  (entmakex
    (list
      '(0 . "LWPOLYLINE")
      '(100 . "AcDbEntity")
      '(370 . 0)
      '(100 . "AcDbPolyline")
      '(90 . 4)
      '(70 . 1)
      (cons 10 t1)
      (cons 10 t2)
    )
  )
)
;;;;;;
(defun *error* (msg)
  (princ msg)
  (setvar "OSMODE" oldosm)
  (princ)
)

)

(изменено: Кулик Алексей aka kpblc, 3 апреля 2009г. 15:12:13)

Re: прерывание lisp программ по нажатию клавиши Esc

Для моего варианта получается нечто типа:

(defun c:test (/ _dwgru-error-catch will_draw pt1 pt2)

  (defun _dwgru-error-catch (protected-function
                             on-error-function
                             /
                             catch_error_result
                             )
                            ;|
*** Функция взята из книжной версии ruCAD'a без каких бы то ни было переделок,
*** кроме переименования.
*    Оболочка отлова ошибок.
*    Параметры вызова:
*   protected-function   - "защищаемая" функция
*   on-error-function   - функция, выполняемая в случае ошибки
|;
    (setq catch_error_result (vl-catch-all-apply protected-function))
    (if (and (vl-catch-all-error-p catch_error_result)
             on-error-function
             ) ;_ end of and
      (apply on-error-function
             (list (vl-catch-all-error-message catch_error_result))
             ) ;_ end of apply
      catch_error_result
      ) ;_ end of if
    ) ;_ end of defun

  (_dwgru-error-catch
    (function
      (lambda ()
        (initget "Да Нет Yes No _ Y N Y N")
        (setq will_draw
               (cond
                 ((getkword "\nБудем рисовать [Да/Нет] <Да>? : "))
                 (t "Y")
                 ) ;_ end of cond
              ) ;_ end of setq
        ) ;_ end of lambda
      ) ;_ end of function
    '(lambda (x) (princ "\nРисование отменено"))
    ) ;_ end of _dwgru-error-catch
  (if (= will_draw "Y")
    (progn
      (while
        (and
          ((lambda ()
             (setq pt1 nil)
             (_dwgru-error-catch
               (function
                 (lambda ()
                   (setq pt1 (getpoint "\nPt1 <Cancel> : "))
                   ) ;_ end of lambda
                 ) ;_ end of function
               nil
               ) ;_ end of _dwgru-error-catch
             pt1
             ) ;_ end of lambda
           )
          ((lambda ()
             (setq pt2 nil)
             (_dwgru-error-catch
               (function (lambda ()
                           (setq pt2 (getpoint pt1 "\nPt2 <Cancel> : "))
                           ) ;_ end of lambda
                         ) ;_ end of function
               nil
               ) ;_ end of _dwgru-error-catch
             pt2
             ) ;_ end of lambda
           )
          ) ;_ end of and
         (entmakex
           (list
             '(0 . "LWPOLYLINE")
             '(100 . "AcDbEntity")
             '(370 . 0)
             '(100 . "AcDbPolyline")
             '(90 . 4)
             '(70 . 1)
             (cons 10 pt1)
             (cons 10 pt2)
             ) ;_ end of list
           ) ;_ end of entmakex
         ) ;_ end of while
      ) ;_ end of progn
    ) ;_ end of if
  (princ)
  ) ;_ end of defun

---
Добавлено:
Вариант без универсальности:

(defun c:test2 (/ will_draw pt1 pt2)
  (if (= "Y"
         (vl-catch-all-apply
           (function
             (lambda ()
               (initget "Да Нет Yes No _ Y N Y N")
               (setq will_draw (cond
                                 ((getkword "\nБудем рисовать [Да/Нет] <Да>? : "))
                                 (t "Y")
                                 ) ;_ end of cond
                     ) ;_ end of setq
               ) ;_ end of lambda
             ) ;_ end of function
           ) ;_ end of vl-catch-all-apply
         ) ;_ end of =
    (while (and (= (type (setq pt1 (vl-catch-all-apply
                                     (function
                                       (lambda ()
                                         (getpoint "\nPt1 <cancel> : ")
                                         ) ;_ end of lambda
                                       ) ;_ end of function
                                     ) ;_ end of vl-catch-all-apply
                               ) ;_ end of setq
                         ) ;_ end of type
                   'list
                   ) ;_ end of =
                (= (type (setq pt2 (vl-catch-all-apply
                                     (function
                                       (lambda ()
                                         (getpoint pt1 "\nPt2 <Cancel> : ")
                                         ) ;_ end of lambda
                                       ) ;_ end of function
                                     ) ;_ end of vl-catch-all-apply
                               ) ;_ end of setq
                         ) ;_ end of type
                   'list
                   ) ;_ end of =
                ) ;_ end of and
      (entmakex
        (list
          '(0 . "LWPOLYLINE")
          '(100 . "AcDbEntity")
          '(370 . 0)
          '(100 . "AcDbPolyline")
          '(90 . 4)
          '(70 . 1)
          (cons 10 pt1)
          (cons 10 pt2)
          ) ;_ end of list
        ) ;_ end of entmakex
      ) ;_ end of while
    ) ;_ end of if
  ) ;_ end of defun

Re: прерывание lisp программ по нажатию клавиши Esc

Необходимо внести изменения в c:test

(defun c:test (/ s oldosm t1 t2) 
  (setq oldosm (getvar "osmode")) 
  (setvar "osmode" 41)
  (initget "Д Н") 
  (vl-catch-all-apply
    (function 
      (lambda ()
        (setq s (getkword "\n Будем рисовать? [Да/Нет] <Д>:"))
        (if (or (= s "Д") (= s "д") (= s nil)) (vvod))
      )
    )
  )
  (setvar "osmode" oldosm)
); end defun.

В данном случае даже не требуется анализировать результат, возвращаемый vl-catch-all-apply.
Поэтому я его не присваиваю никакой переменной.
А функцию *error* переопределять не требуется. Переопределение *error* - это прием из прошлой жизни, когда в AutoLISP не было vl-catch-all-apply. Эта функция (*error*) не перехватывает ошибку и не предовращает "вылет", а всего лишь пост-фактум выполняет заложенные в неё действия, позволяющие сгладить последствия вылета, например восстановить системные переменные.

Re: прерывание lisp программ по нажатию клавиши Esc

Чтоб жизнь малиной не казалась
:D  :D  :D
Всю ночь разбирался, что да как работает в коде kpblcа (причём почему-то первого, а надо-то было сразу посмотреть "без универсальности"- почти всё понял(ваш стиль написания кода возможно очень высокого уровня, но трудно читаем для начинающих) , начал применять всё это дело к своему длинному, большому, запутанному (для меня) коду...
:D  :D  :D
И тут приходит и пишет Пастух - оказывается всё до ужаса просто и понятно, и в мой код надо добавить только в одном месте всего 3 строки.