Тема: Диалоговые окна и клавиша Esc

Понаваял я кучу диалоговых окон на DCL под управлением Autolisp. Кнопочки там есть типа accept, типа cancel. Все работает. Но только если при открытом диалоговом окне клавишу Esc нажать, то лисп-прога продолжает выполняться, пока еще раз Esc не нажьмешь. Что делать?

Re: Диалоговые окна и клавиша Esc

обработку выхода по ESC
По-моему, если я правильно помню есть фунцция what next

Re: Диалоговые окна и клавиша Esc

http://aco.ifmo.ru/~nadinet/html/lectures/index.html

Re: Диалоговые окна и клавиша Esc

Что-то не понял я там ничего. Тупой наверно...

Народ, а сами-то вы как эту проблему решаете?
Или никто диалоговых окон не пишет?

Re: Диалоговые окна и клавиша Esc

(exi)
 (quit)

ета фунцциа останавливает программу

Re: Диалоговые окна и клавиша Esc

Dear Leonid!
Это я наверно криво объяснил.
Еще раз:
Прерывание функции по (exit) у меня срабатывает при клике мышкой по кнопке (на экране) cancel
и НЕ срабатывает при нажатии (пальцем на клаве) клавиши Esc

Re: Диалоговые окна и клавиша Esc

Может я что-то не так понял, но скорее всего есть несколько кнопок, у которых есть атрибут
is_cancel = true;
Если кнопка с таким атрибутом единственная в данном диалоге, то, что кликнуть по ней мышкой, что нажать Esc, что кликнуть на "крестик" в правом верхнем углу не должно никак отличаться.
Если же кнопок с таким атрибутом несколько, то по нажатию Esc будет отрабатываться "последняя" кнопка с таким атрибутом. Какая является первой, какая последующей, можно вычислить последовательно нажимая <Tab> при загруженом диалоге.

Другими словами, если диалог заканчивается так:

     : row {
       : button {
         key = "cancel";
         label = "Выход";
         is_cancel = true;
       }
       : button {
         key = "accept";
         label = "OK";
         is_cancel = true;
       }
     }

то по Esc будет выполняться то, что выполняется по клику на кнопку "OK".
Если ты пользуешься кнопками, определенными в acad.dcl  или base.dcl, посмотри есть ли у них эти атрибуты.

Re: Диалоговые окна и клавиша Esc

Интересная мысль. Проверю.

Re: Диалоговые окна и клавиша Esc

Провел несколько экспериментов. Резалт:
При нажатии клавиши Esc всегда срабатывает самая первая (по файлу *.dcl) кнопка диалогового окна, имеющая атрибут is_cancel = true; Даже если она не имеет атрибута is_default=true;
Снова поднимаю вопрос: что делать чтобы этого избежать?

Re: Диалоговые окна и клавиша Esc

В Help сказано:
Only one button in a dialog box can have the is_cancel attribute set to true.
Собственно это и надо сделать: оставить этот атрибут только у одной единственной необходимой кнопки, и убрать у всех остальных.

Re: Диалоговые окна и клавиша Esc

если ничего не передавать в функцию done_dialog, то start_dialog вернет 1 при нажатии enter и 0 при esc.
Т. е. (setq select (start_dialog))  и далее прога работает в зависимости от значения select.

Re: Диалоговые окна и клавиша Esc

> S
(25.02.2003 в 09:27:44)
Опять таки, это справедливо только, если есть одна кнопка is_cancel = true. Если такой кнопки вообще нет, то сколько Esc не жми - диалог все время будет на экране. Если таких кнопок несколько, то все проблеммы останутся.

Например:

 cancel_test : dialog {
     label = "is_cancel";
     : spacer { height = 1; }
     : row {
        : button {
          key = "1";
          label = "1";
          is_default = true;
          //is_cancel = true;
        }
        : button {
          key = "2";
          label = "2";
          //is_cancel = true;
        }
        : button {
          key = "3";
          label = "3";
          //is_cancel = true;
        }
        : button {
          key = "4";
          label = "4";
          //is_cancel = true;
        }
        : button {
          key = "5";
          label = "5";
          is_cancel = true;
       }
    }
 }
 
 (defun cancel_test ( / dcl_id select)
   (setq dcl_id (load_dialog "tmp.dcl"))
   (new_dialog "cancel_test" dcl_id)
   (action_tile "1" "(alert \"1\")(done_dialog)")
   (action_tile "2" "(alert \"2\")(done_dialog)")
   (action_tile "3" "(alert \"3\")(done_dialog)")
   (action_tile "4" "(alert \"4\")(done_dialog)")
   (action_tile "5" "(alert \"5\")(done_dialog)")
   (setq select (start_dialog))
   (unload_dialog dcl_id)
   select
 );defun

В данном примере, что Esc, что Enter будет возвращать 0, а сообщения будут разные. Если во все done_dialog добавить 1, то возвращаться всегда будет 1, но сообщения все равно будут разные. Попробуйте в различных вариантах разремить is_cancel у разных кнопок, и все будет понятно.

В общем, верьте Help-у: Can Be Only One

Re: Диалоговые окна и клавиша Esc

leha > Если таких кнопок несколько?
Только одна кнопка в диалоге может иметь is_cancel = true;
Если в диалоге использовать ссылку ok_cancel, функцию (done_dialog) вызывать не нужно (если нет других баттонов для
временного закрытия окна).     Тогда

 (setq select (start_dialog))
 
 (if (= select 0)(exit))

Re: Диалоговые окна и клавиша Esc

Я, наверно, плохо умею объяснять. С самого начала и пытаюсь сказать, что такая кнопка ДОЛЖНА быть одна, но МОЖЕТ их быть и несколько. И судя по тому, как была описана проблема, именно это и происходит. Если таких кнопок СЛУЧАЙНО оказалось несколько, то никакой ошибки нигде не выскочит, но что при этом будет выполнятся по нажатию Esc, и что будет возвращать (start_dialog), зависит от данного конкретного диалога.

Например:

 cancel_test : dialog {
     label = "is_cancel";
     : spacer { height = 1; }
     : row {
        ok_only;
        : button {
          key = "cancel";
          label = "Выход";
          is_cancel = true;
        }
    }
 }
 
 (defun cancel_test ( / dcl_id select)
   (setq dcl_id (load_dialog "tmp.dcl"))
   (new_dialog "cancel_test" dcl_id)
   (action_tile "accept" "(alert \"OK\")")
   (action_tile "cancel" "(alert \"Cancel\")")
   (setq select (start_dialog))
   (unload_dialog dcl_id)
   select
 );defun

Всегда возвращает 0, а по Esc и по Enter выполняется разное. И внешне выглядит, что кнопка с is_cancel = true - всего одна.
Кончено именно так никто писать не будет, но в каком-то сложном диалоге, какая-либо подобная ситуация случайно возникнуть может.
И все, что нужно сделать - это внимательно просмотреть и свой диалог, и возможные ссылки на предопределения в других. И исключить ситуацию, чтобы было несколько is_cancel = true.

Re: Диалоговые окна и клавиша Esc

Внутри функции, вызываемой при нажатии кнопки по action_tile используй функцию (done_dialog <код>). В качестве кода задай любое число. Именно это число и возвратит функция (start_dialog).
Например, если на кнопку MyCancel навесить (done_dialog 55), то при нажатии на нее окно завершится с кодом 55. А по Escape-с кодом 0.

Re: Диалоговые окна и клавиша Esc

Может у меня почему-то не так, как у всех.

>Олег (25.02.2003 в 14:50:22)
В варианте >leha (25.02.2003 в 13:52:27)< замени
(action_tile "cancel" "(alert \"Cancel\")")
на
(action_tile "cancel" "(alert \"Cancel\")(done_dialog 55)")
Тогда (done_dialog) вернет:
При нажатии на кнопку OK или на клавишу <Enter> вернет 0.
При нажатии на кнопку Выход или на клавишу <Esc>, или на крестик - вернет 55.


А если при этом еще и поменять ok_only и button местами, то:
OK и <Enter> вернет 0.
Выход и <Esc> вернет 55.
А крестик уже вернет 0 и выдаст сообщение "OK".

Re: Диалоговые окна и клавиша Esc

Прошу прощения, опечатался. Все это вернет, конечно, не (done_dialog), а (start_dialog). Но вернет именно это.

Re: Диалоговые окна и клавиша Esc

[rus]Vot neznaiu chto u vas za problema - vnizu primer dialoga
nichego osobennogo kak vidite, ESCAPE key vse prerivaet tak zhe kak X (krestik) ili CANCEL knopka[/rus]

 dcl_settings : default_dcl_settings { audit_level = 3 ; }
 txt : dialog {
    key = "txt" ;
    label = "Text Settings" ;
    value = "Standard Text Settings" ;
    : text {
       label = "tx" ;
       value = "Current Text Style will be used for settings." ;
    }
    : text {
       key = "tx2" ;
       label = "tt" ;
       value = "Preset Higtht:" ;
    }
    : text {
       key = "tx4" ;
       label = "tttt" ;
       value = "Standartd Tex t - 1/8 (0.125)  Standard Subtitle - 3/16 (0.18)  Standard Title - 1/4 (0.25)" ;
    }
    : row {
       key = "r1" ;
       : button {
          fixed_width = true ;
          key = "bt1" ;
          label = "Standard Text" ;
          width = 30 ;
       }
       : button {
          fixed_width = true ;
          key = "bt2" ;
          label = "Standard Subtitle" ;
          width = 30 ;
       }
       : button {
          fixed_width = true ;
          key = "bt3" ;
          label = "Standard Title" ;
          width = 30 ;
       }
    }
    ok_cancel ;
 }
 
 a etot lisp vizivaet dialog
 (defun c:txtT (/ scl szx szs szt)
 
 (defun bt1()
 (setq pset "a")
 (done_dialog)
 )
 
 (defun bt2()
 (setq pset "b")
 (done_dialog)
 )
 
 (defun bt3()
 (setq pset "c")
 (done_dialog)
 )
 (setq pset nil)
 
    (setq dcl_id (load_dialog "txt.dcl"))
    (if (not (new_dialog "txt" dcl_id)) (exit))
 
    (action_tile "bt1" "(bt1)")
    (action_tile "bt2" "(bt2)")
    (action_tile "bt3" "(bt3)")
 
    (action_tile "accept" "(EXIT)")
    (action_tile "cancel" "(EXIT)")
 
    (start_dialog)
    (unload_dialog dcl_id)
    (princ)
 
   (setq scl (getvar "dimscale"))
   (setq szx (* 0.125 scl))
   (setq szs (* 0.18 scl))
   (setq szt (* 0.25 scl))
   (cond
     ((= pset "a")(setvar "textsize" szx)(COMMAND"STYLE" "STANDARD" "ROMANS" "" "" "" "" "" ""))
     ((= pset "b")(setvar "textsize" szs)(COMMAND"STYLE" "SUBTITLE" "ROMANS" "" "" "" "" "" ""))
     ((= pset "c")(setvar "textsize" szt)(COMMAND"STYLE" "TITLE" "ROMAND" "" "" "" "" "" ""))
   )
   (INITDIA)
   (command "mtext")
   (princ)
 )

Может иа чего непонимаиу - но в чем проблема не вижу :)

Re: Диалоговые окна и клавиша Esc

Nastoiatel'no sovetuiu posetit' www.cadgineering.com
home of PROTOBOX 2.2 eta programka imeet demo rabotaet dazhe demo horosho. Stoit $60 kolov.
Delaet DCL dialogi bistro i bezoshibochno. Ia ei pol'zuius' 5 let s
gakom.

Re: Диалоговые окна и клавиша Esc

Не могу согласиться с коллегами, утверждающими, что кнопка с is_cancelled=true; должна быть только одна.
Как раз чаще всего - две. Одна на выполнение с внесением изменений с других управляющих полей. Другая - прерывание программы с отменой изменений. Я частенько использую несколько кнопок типа OK для ветвления программы.

Насчет внедрения (done_dialog 55) в кнопку прерывания как-то лохмато получается. Пока не разобрался, но попробую.

Re: Диалоговые окна и клавиша Esc

Вот теперь, кажется, понятно в чем на самом деле проблема. Если я конечно не ошибаюсь, Pilot считает, что закрыть диалог (убрать его с экрана) можно только кнопкой, у которой есть атрибут is_cancel = true. А закрывать его хочет разными и несколькими кнопками, и к каждой из них вешает is_cancel = true.
На самом деле наличие у кнопки этого атрибута - это условие достаточное, но НЕ необходимое. Собственно закрывает диалог функция (done_dialog), которую можно прицепить к любой и к нескольким одновременно кнопкам (и не обязательно к кнопкам). А у кнопки с атрибутом is_cancel = true функцию (done_dialog) можно просто опустить.
Этот атрибут всего-лишь показывает какой именно ключ надо выполнить, если пользователь нажмет Esc. И так как на клавиатуре такая клавиша только одна, то и в диалоге такой атрибут должен быть один (и даже не обязательно у кнопки).
Вообще атрибуты типа is_cancel, is_default, is_tab_stop нужны для того, чтобы с диалогом можно было работать вообще не трогая мышь. И, в общем то, надо стараться диалоги писать именно так.
Что-то опять как-то путано получилось. Сейчас лучше какой-нибудь пример придумаю.

Re: Диалоговые окна и клавиша Esc

2 leha
Ооооочень полезная инфа! Я просто был не в курсе насчет (done_dialog). Будем пробовать. Но если получится, то мне придется модернизировать десятка полтора написанных диалогов smile

Re: Диалоговые окна и клавиша Esc

Хоть и все уже понятно, но все равно раз уж сделал.
Делает копии указанной окружности.
Специально все без проверок, чтобы было понятней.

Если нажать OK  окружность построится и диалог закроется,
если нажать Применить окружность построится и диалог опять появится,
если нажать Выход или Esc ничего не сделается и диалог закроется.
По полям ввода значений можно ходить с помощью клавиши Tab,
если в любом из этих полей нажать Enter, окружность построится и диалог опять появится (то же, что и по кнопке Применить).
С этим диалогом можно работать и с помощью мыши, а можно (после указания окружности) все сделать только клавиатурой:
клавиши Tab, Enter и Esc.

 copy_circle : dialog {
   label = "Окружность";
   : spacer {height = 1;}
   : column {
     fixed_width = true;
     alignment = centered;
     : edit_box {
       key = "rad";
       label = "Радиус (мм):";
       edit_width = 15;
       edit_limit = 255;
     }
     : edit_box {
       key = "xc";
       label = "Смещение X (мм):";
       edit_width = 15;
       edit_limit = 255;
     }
     : edit_box {
       key = "yc";
       label = "Смещение Y (мм):";
       edit_width = 15;
       edit_limit = 255;
     }
   }
   : spacer {height = 1;}
   : row {
     : button {
       key = "accept";
       label = "  OK  ";
       is_tab_stop = false;
     }
     : button {
       key = "apply";
       label = "Применить";
       is_tab_stop = false;
     }
     : spacer {width = 1;}
     : button {
       key = "cancel";
       label = "Выход";
       is_cancel = true;
       is_tab_stop = false;
     }
   }
 }
 
 
 (defun copy_circle ( / lstobj ptc rad xc yc old_osmode ptdia ckl dcl_id i)
   (setq lstobj (entget (car (entsel "\nУкажите окуржность:"))))
   (setq ptc (cdr (assoc 10 lstobj)))
   (setq rad (cdr (assoc 40 lstobj)))
   (setq xc 0.0 yc 0.0)
   (setq old_osmode (getvar "OSMODE"))
   (setvar "OSMODE" 0)
   (setq ptdia '(-1 -1))
   (setq dcl_id (load_dialog "tmp.dcl"))
   (setq ckl t)
   (while ckl
     (new_dialog "copy_circle" dcl_id "" ptdia)
     (set_tile "rad" (rtos rad 2 4))
     (set_tile "xc" (rtos xc 2 4))
     (set_tile "yc" (rtos yc 2 4))
     (mode_tile "apply" 1)
     (mode_tile "rad" 2)
 
     ;(foreach i '("rad" "xc" "yc")
     ;  (action_tile i (strcat "(setq " i " (atof $value))"
     ;    "(if (/= $reason 2)"
     ;      "(setq ptdia (done_dialog 1))"
     ;       "(mode_tile \"apply\" 0)"
     ;    ");if"
     ;    );strcat
     ;  );action_tile
     ;);foreach
     
     (action_tile "rad" "(setq rad (atof $value))
       (if (/= $reason 2)
         (setq ptdia (done_dialog 1))
         (mode_tile \"apply\" 0)
       );if
     ")
     (action_tile "xc" "(setq xc (atof $value))
       (if (/= $reason 2)
         (setq ptdia (done_dialog 1))
         (mode_tile \"apply\" 0)
       );if
     ")
     (action_tile "yc" "(setq yc (atof $value))
       (if (/= $reason 2)
         (setq ptdia (done_dialog 1))
         (mode_tile \"apply\" 0)
       );if
     ")
       
     (action_tile "accept" "(setq ckl nil)(done_dialog 1)")
     (action_tile "apply" "(setq ptdia (done_dialog 1))")
     (action_tile "cancel" "(setq ckl nil)")
       
     (if (= (start_dialog) 1)
       (command "_.circle" (setq ptc (list (+ (car ptc) xc) (+ (cadr ptc) yc))) rad)
     );if
   );while
   (unload_dialog dcl_id)
   (setvar "OSMODE" old_osmode)
   (princ)
 );defun

Вместо первых трех action_tile можно написать заремленный foreach, но так понятней будет.