Программирование диалоговых окон на языке DCL
Составление списка вручную:
(setq layerList(list "0" "Layer1" " Layer2" " Layer3" " Layer4" " Layer5" "Layer6" " Layer7" " Layer8" " Layer9"))
То же самое для числа сторон многоугольника:
(setq numSides(list "4" "6" "8" "12" "16"))
Добавим эти строки в описание диалога DCL-файла.
;;;--- Add the layer names to the dialog box (start_list "layerlist" 3) (mapcar 'add_list layerList) (end_list) ;;;--- Add the number of sides to the dialog box (start_list "numsides" 3) (mapcar 'add_list numSides) (end_list)
После этого добавление основная LISP-программа должна выглядеть так:
(defun C:SAMPLE ()
;;;--- Load the dcl file
(setq dcl_id (load_dialog "SAMPLE.dcl"))
;;;--- Load the dialog definition if it is not already loaded
(if (not (new_dialog "SAMPLE" dcl_id))
(progn
(alert "The SAMPLE.DCL file could not be loaded!")
(exit)
)
)
(setq layerList(list "0" "Layer1" " Layer2" " Layer3" " Layer4" " Layer5" "Layer6" " Layer7" " Layer8" " Layer9"))
(setq numSides(list "4" "6" "8" "12" "16"))
;;;--- Add the layer names to the dialog box
(start_list "layerList" 3)
(mapcar 'add_list layerList)
(end_list)
;;;--- Add the number of sides to the dialog box
(start_list "numsides" 3)
(mapcar 'add_list numSides)
(end_list)
;;;--- If an action event occurs, do this function
(action_tile "cancel" "(setq ddiag 1)(done_dialog)")
(action_tile "accept" "(setq ddiag 2)(saveVars)(done_dialog)")
;;;--- Display the dialog box
(start_dialog)
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the cancel button was pressed - display message
(if (= ddiag 1)
(princ "\n \n ...SAMPLE Cancelled. \n ")
)
;;;--- If the "Okay" button was pressed
(if (= ddiag 2)
(princ "\n \n ...SAMPLE Complete!")
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
Сохраните файлы, загрузите их и запустите команду Sample. На экране должно появиться диалоговое окно со списками (рис. 6.9):
Создадим сценарий отклика на события в окне в описании функции SaveVars LISP-файла. При выборе строки в списке функция чтения get_tile возвращает номер строки как строковую константу. На время отладки программы введем распечатки полученных значений переменных. В дальнейшем эти распечатки нужно убрать.
(defun saveVars() (setq radios(get_tile "radios")) ;;;--- Get the number of sides selected from the list (setq numStr(get_tile "numsides")) (if(= numStr "") (setq numSides nil) (setq numSides(nth (atoi numStr) numSides)) ) (princ numSides) (terpri) ;;;--- See if the user wants to save the settings (setq saveSet(atoi(get_tile "saveset"))) (princ saveSet) (terpri) ;;;--- Get the selected item from the layer list (setq sStr(get_tile "layerList")) ;;;--- If the index of the selected item is not "" then something was selected (if(/= sStr "") (progn ;;;--- Something is selected, so convert from string to integer (setq sIndex(atoi sStr)) ;;;--- And get the selected item from the list (setq layerName(nth sIndex layerList)) ) ;;;--- Else, nothing is selected (progn ;;;--- Set the index number to -1 (setq sIndex -1) ;;;--- And set the name of the selected item to nil (setq layerName nil) ) ) (princ layerName) (terpri) )
Если не выделить имя слоя в элементе list_box, то значение его будет nil. Иначе будет выдан примерно такой результат:
Command: sample 6 1 sStr5 sindex5 layerNameLayer5 ...SAMPLE Complete!
При вычерчивании окружности нужно сделать неработающим элемент "Number of Sides" popup_list. Для этого нужно запрограммировать события с радиокнопками таким образом:
;;;--- If an action event occurs, do this function (action_tile "drawcir" "( 1)") (action_tile "drawpol" "(toggleRadio 2)")
При выборе элемента drawcir вызывается функция toggleRadio 1, а при выборе элемента drawpol вызывается функция toggleRadio 2.
Создадим такую функцию с параметром (a) в AutoLisp-программе:
(defun toggleRadio(a) ;if circle is selected (if(= a 1) (mode_tile "numsides" 1) ;disable ;else (mode_tile "numsides" 0) ;enable ) )
По умолчанию в программе должна рисоваться окружность. Поэтому перед выражениями с функциями action_tile нужно добавить строку
(mode_tile "numsides" 1)
Таким образом, когда выделяем кнопку, чтобы нарисовать окружность, numSides popup_list недоступен. Когда же мы собираемся рисовать многоугольник, то элемент установки число сторон становится доступным.
А теперь можно изменить слой:
(setq oldLay(getvar "clayer")) (setvar "clayer" layerName)
Напишем также команды построения окружности и многоугольника
(if(= radios "drawcir") (progn (setq pt(getpoint "\n Center point: ")) (command "circle" pt pause) ) ;;;--- Else draw a polygon (progn (setq pt(getpoint "\n Center Point: ")) (command "polygon" numSides pt "C" pause) ) )
LISP-файл будет выглядеть следующим образом:
(defun C:SAMPLE ()
;;;--- Load the dcl file
(setq dcl_id (load_dialog "Sample.dcl"))
;;;--- Load the dialog definition if it is not already loaded
(if (not (new_dialog "sample" dcl_id))
(progn
(alert "The SAMPLE.DCL file could not be loaded!")
(exit)
)
)
(setq layerList (list "0" "Layer1" "Layer2" "Layer3"
"Layer4" "Layer5" "Layer6" " Layer7"
"Layer8" "Layer9"
)
)
(setq numSides (list "4" "6" "8" "12" "16"))
;;;--- Add the layer names to the dialog box
(start_list "layerList" 3)
(mapcar 'add_list layerList)
(end_list)
;;;--- Add the number of sides to the dialog box
(start_list "numsides" 3)
(mapcar 'add_list numSides)
(end_list)
(mode_tile "numsides" 1)
;;;--- If an action event occurs, do this function
(action_tile "drawcir" "(toggleRadio 1)")
(action_tile "drawpol" "(toggleRadio 2)")
(action_tile "cancel" "(setq ddiag 1)(done_dialog)")
(action_tile
"accept"
"(setq ddiag 2)(saveVars)(done_dialog)"
)
;;;--- Display the dialog box
(start_dialog)
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the cancel button was pressed - display message
(if (= ddiag 1)
(princ "\n \n ...SAMPLE Cancelled. \n ")
)
;;;--- If the "Okay" button was pressed
(if (= ddiag 2)
(princ "\n \n ...SAMPLE Complete!")
)
;;;--- Suppress the last echo for a clean exit
(princ)
(if(= radios "drawcir")
(progn
(setq pt(getpoint "\n Center point: "))
(command "circle" pt pause)
)
;;;--- Else draw a polygon
(progn
(setq pt(getpoint "\n Center Point: "))
(command "polygon" numSides pt "" pause)
)))
(defun saveVars ()
(setq radios (get_tile "radios"))
;;;--- Get the number of sides selected from the list
(setq numStr (get_tile "numsides"))
(if (= numStr "")
(setq numSides nil)
(setq numSides (nth (atoi numStr) numSides))
)
(princ numSides)
(terpri)
;;;--- See if the user wants to save the settings
(setq saveSet (atoi (get_tile "saveset")))
(princ saveSet)
(terpri)
;;;--- Get the selected item from the layer list
(setq sStr (get_tile "layerList"))
(princ "sStr")
(princ sStr)
(terpri)
;;;--- If the index of the selected item is not "" then something was selected
(if (/= sStr "")
(progn
;;;--- Something is selected, so convert from string to integer
(setq sIndex (atoi sStr))
(princ "sindex")
(princ sIndex)
(terpri)
;;;--- And get the selected item from the list
(setq layerName (nth sIndex layerList))
(princ "layerName")
(princ layerName)
(terpri)
)
;;;--- Else, nothing is selected
(progn
;;;--- Set the index number to -1
(setq sIndex -1)
;;;--- And set the name of the selected item to nil
(setq layerName nil)
) )
(setq oldLay(getvar "clayer"))
(setvar "clayer" layerName)
)
(defun toggleRadio(a)
;if circle is selected
(if(= a 1)
(mode_tile "numsides" 1) ;disable
;else
(mode_tile "numsides" 0) ;enable
)
)
И наконец, займемся кодом сохранения установок по умолчанию. В элементах диалога все значения переменных интерпретируются как строки. В AutoCAD поддерживается 15 пользовательских системных переменных сохранения данных. USERR1 - USERR5 используют действительные числа. USERI1 - USERI5 используют целые числа. USERS1 - USERS5 будут сохранять наши данные как строки. Все эти величины доступны в файле чертежа каждый раз при его открытии.
Первой переменной у нас появляется RADIOS, и она уже имеет строковый тип (setvar "USERS1" radios).
Второй переменной является NUMSIDES - целое число сторон многоугольника. Но при чтении значения (value) элемента нам возвращается номер строки типа string: (setvar "USERS2" numStr).
Третья переменная SAVESET имеет тип integer. Поэтому ее нужно конвертировать (setvar "USERS3" (itoa saveSet)) .
Индекс четвертой переменной LAYERNAME сохраним в виде строки:
(setvar "USERS4" sSTR)
Ключевые термины
Язык DCL (Dialog Control Language) - специальный язык для создания диалоговых окон.
Директива - логически законченная единица программы диалога.
Элементы управления - части интерфейса диалогового окна, к которым имеет доступ пользователь (кнопки, текстовые поля, списки и пр.).
Функции DCL - встроенные функции языка для проведения действий и операций.
Переменные действия - глобальные переменные, в которых сохраняются некоторые дополнительные данные о состоянии диалогового окна и выполненных в нем действий пользователя. Переменные используются в LISP-выражениях, задаваемых в качестве второго аргумента функции action-tile.
Краткие итоги
Программы вычерчивания фигур должны иметь возможность изменять значения переменных. Это можно сделать либо в коде, либо по запросам в командной строке в процессе выполнения программы. Но удобнее всего выполнять установки в специальных диалоговых окнах. Технология создания таких окон с помощью языка DCL описана в данной лекции.
Вопросы
- Где нужно сохранять DCL-файлы?
- Через какой атрибут директивы устанавливается связь диалога с LISP-файлом?
- Что возвращает функция загрузки dcl-файла load_dialog?
- Каково назначение функции action_tile?
- Какие функции производят операции редактирования списков в элементах list_box и popup_list?
- Составьте алгоритм работы LISP-программы, которая запускает сценарий отклика на событие выделения радиокнопки в диалоговом окне.
