Урок 6. Программирование диалоговых окон на языке DCL
1. Технология
программирования диалогов
2. Директивы
и элементы языка DCL
3. Функции
открытия и закрытия диалоговых окон
4. Функции
управления элементами диалога
5. Функции
для работы со списками
6. Функции
для работы с графическими элементами
В диалоговых окнах удобно вводить данные и настройки созданных LISP-приложений. Для создания диалоговых окон разработан специальный язык DCL (Dialog Control Language). Диалоговые окна описываются в текстовых DCL-файлах с расширением .dcl. Примерами DCL-файлов являются файлы с описанием стандартных диалогов acad.dcl и base.dcl, размещенные в папке C:\Documents and Settings\User\Application Data\Autodesk\AutoCAD 2007\R17.1\enu\Support. Работа с диалогами производится в интегрированной среде разработки Visual LISP.
В предыдущих уроках была составлена LISP-программа вычерчивания полого рога.
(defun c:qrog
(/ cenrt1 rad1 diam1 circle1 arc1 rog1 thick1 angle1 endp1 col1)
(setq centr1 '(0 0 0)) ;исходная базовая точка
(setq rad1 (getreal "Задайте радиус базовой окружности: "))
(setq diam1 (getreal "Задайте диаметр направляющей дуги: "))
(setq thick1 (getreal "Задайте толщину стенки рога: "))
(setq col1 (getint "Задайте индекс цвета: "))
(setq angle1 (* 55.0 (atan rad1 (*
diam1 (/ pi 2)))))
(command "_view" "_top") ;начинаем со стандартного вида
(command "_view" "_swiso");переходим к северо-западному виду
(command "_circle" centr1 rad1 "") ;строим базовую окружность
(setq circle1 (entlast));извлекаем имя сущности для базовой окружности
(command "_ucs"
"_x" "90" "");поворачиваем ПСК
(setq endp1 (list diam1 0.0))
(command "_arc" centr1
"e" endp1 "a" "-180" "")
(setq arc1 (entlast));извлекаем имя сущности для дуги и сохраняем его
(command
"_ucs" "_x" "-90");совмещаем плоскость окружности
с плоскостью XY
(command "extrude" circle1
"" "t" angle1 "p" arc1 "")
(setq rog1 (entlast));извлекаем имя сущности для рога и сохраняем его
(command "_zoom" "e" "");растягиваем изображение на весь экран
(command "_vscurrent" "_r" "");устанавливаем текущий визуальный стиль - realistic
(command "_chprop"
"_all" "" "_color" col1 "")
(command "_view"
"_bottom" "");устанавливаем вид снизу
(command "_solidedit" "_body"
"_shell" rog1 centr1 "" thick1 "" "")
(command "_erase" arc1 "");удаляем ненужную образующую дугу
(princ)
)
Внешний вид рога показан на рис.6.1.
Рис. 6.1. Рисунок рога
Рог строился путем экструзии базовой окружности вдоль дуги с раствором 180о. Угол сужения брался равным углу сужения подобного прямого конуса. Полость в роге выполнялась с помощью команды Shell.
При запуске функции qrog пользователь задавал требуемые параметры по запросам программы:
· радиус базовой окружности rad1;
· диаметр направляющей дуги diam1;
· толщину стенки рога thick1;
· индекс цвета col1.
Требуется вместо запросов создать диалоговое окно для одновременного ввода этих параметров.
Вначале напишем отдельную программу для открытия диалогового окна. В новом чертеже AutoCAD откройте среду Visual LISP по команде Tools — AutoLISP — Visual LISP Editor. По команде File — New File создайте новый файл. Наберите в нем следующий текст программы диалога «rog» на языке DCL. Учтите только, что элементы языка DCL чувствительны к регистру. Все ключевые слова, метки и коды элементов должны состоять только из латинских букв, цифр и символа подчеркивания. Начинаться служебные слова должны с латинской буквы.
//Диалоговое окно установки параметров рога
//
rog: dialog{label="Установка параметров рога";
:edit_box{label="Радиус окружности ";key="rad"
;value="0.00"; edit_width=8;}
:edit_box{label="Диаметр дуги, мм";key="diam";value="0.00";edit_width=8;}
:edit_box{label="Толщина стенки, мм";key="thick";value="0.00";edit_width=6;}
:spacer{height=1;}
:edit_box{label="Индекс цвета";key="col";value="0";edit_width=4;}
:spacer{height=1;}
ok_cancel;
}
Сохраните написанное в файле C:\Program Files\AutoCAD2007\Support\Rog.dcl. Папка Support принадлежит к маршрутам файлов поддержки. Проверьте это еще раз, выполнив команду Tools — Options — Files — Support File Search Path. Чтобы открыть диалоговое окно на экране, система должна загрузить DCL-файл. Эта загрузка будет выполнена автоматически, если DCL-файл помещен в данную папку. Иначе нужно указывать полный путь к файлу.
Вся написанная программа называется диалогом. В одном файле может быть несколько диалогов. Рассмотрим структуру программы-диалога.
За двойной чертой // до конца строки размещается комментарий. В нашей программе комментарий занимает первые две строки. Далее программа содержит логически законченные единицы — директивы. Каждая директива описывает один элемент (tile) или способ группировки элементов внутри диалогового окна. Директива должна заканчиваться фигурной скобкой или точкой с запятой. Количество открывающих скобок должно быть равно количеству закрывающих скобок. При описании элементов разделителем служит точка с запятой. Текстовые строки должны быть заключены в кавычки. Между ключевыми словами языка, разделительными символами, метками, числовыми и строковыми значениями может быть любое количество пробелов.
Директивы могут записываться в двух видах:
[<метка>]:<оператор>{<атрибуты>}
<метка>;
Здесь квадратные скобки обозначают необязательность размещенного внутри них элемента. Фигурные скобки и двоеточия являются обычными символами. Метка — идентификатор директивы. Она должна быть уникальной в данном файле.
В листинге программы мы сразу можем выделить директиву описания диалога в целом:
rog: dialog {label="Установка параметров рога";
…
ok_cancel;
}
rog — это метка, имя диалога;
dialog — это оператор, он вызывает свою подпрограмму, выполняющую действия;
label=”…”; — эта надпись будет заголовком диалогового окна;
ok_cancel — внизу окна будут размещены кнопки ОК и CANCEL (Отмена).
Внутри директивы dialog размещены четыре однотипные директивы, имеющие следующий вид:
:edit_box{label="Радиус окружности "; key="rad"; value="0.00";
edit_width=8;}
Элементы этих директив описывают следующие понятия:
edit_box — оператор редактируемого текстового поля;
label=”…”; — эта надпись будет размещена перед текстовым полем;
key="rad"; — код диалога;
value="0.00"; — значение, которое содержит текстовое поле по умолчанию;
edit_width=8; — ширина окна текстового поля в символах шрифта.
В листинге программы имеются еще две одинаковые директивы
:spacer{height=1;}
spacer — это пустой элемент, обозначающий пропуск строки;
height=1; — атрибут height показывает высоту пропущенной строки. Единицей измерения является стандартная высота строки текущего шрифта.
Итак, в сохраненном файле “Rog.dcl” описано диалоговое окно с именем диалога “rog”. Окно должно иметь четыре текстовых поля с видимыми в них значениями по умолчанию.
Составим теперь LISP-функцию, которая позволяла бы загружать (load_dialog) и выгружать (unload_dialog) DCL-файлы, открывать и закрывать окна загруженных диалогов. В редакторе Visual LISP создайте новый файл и наберите в нем следующий текст:
(defun c:show_rog ( / num)
(if (< (setq num (load_dialog
"rog.dcl")) 0)(exit))
(if (not (new_dialog "rog"
num)) (exit))
(start_dialog)
(unload_dialog num)
(princ)
);defun
В первой строке определена функция show_rog c локальной переменной num. В переменной num сохраняется внутренний номер открываемого диалогового окна. Обычно он присваивается всем вновь открываемым диалогам по порядку, начиная с единицы.
Во второй строке записана команда (load_dialog "rog.dcl"), загружающая файл rog.dcl. Если полный адрес файла не указан, то система ищет этот файл по стандартному алгоритму поиска файлов поддержки. Если загрузка прошла успешно, то функция load_dialog возвращает положительное целое число, которое присваивается переменной num. Если загрузка не выполнилась, то возвращается отрицательное число. В этом случае выполняется функция exit, прерывающая работу приложения.
В третьей строке проверяется, имеется ли в загруженном DCL-файле rog.dcl диалог с именем “rog”, имеющий номер num. Если такого диалога в файле нет, то программа завершается с помощью функции exit. Если такой диалог есть, то активируется диалоговое окно, управление передается функции start_dialog. Эта функция возвращает 1, если пользователь выйдет из диалогового окна с помощью кнопки OK или 0, если пользователь выйдет из диалогового окна с помощью кнопки Cancel.
В пятой строке функция unload_dialog num выгружает файл из оперативной памяти. Возвращаемое значение — nil.
Загрузите файл, перейдите в AutoCAD и наберите в командной строке show_rog. На экране появится диалоговое окно (рис. 6.2).
Рис. 6.2. Диалоговое окно
Установите параметры в текстовых полях. Щелкните по кнопке ОК. Окно исчезнет с экрана. Файл rog.dcl выгрузится из оперативной памяти. Чтобы воспользоваться результатами работы с окном, нужна программа, анализирующая введенные величины.
Исключим из программы черчения рога приглашения задать параметры рога и включим обращение к диалогу «rog». На время наладки программы введем печать четырех параметров в отдельных строках.
(defun c:qrog
(/ cenrt1 rad1 diam1 circle1 arc1 rog1 thick1 angle1 endp1 col1)
(setq centr1 '(0 0 0)) ;исходная базовая точка
(if (< (setq num (load_dialog
"rog.dcl")) 0) (exit))
(if (not (new_dialog "rog"
num)) (exit))
(action_tile "rad" "(setq rad1
(atof $value))")
(terpri)
(princ
rad1)
(action_tile "diam" "(setq diam1 (atof $value))")
(terpri)
(princ
diam1)
(action_tile "thick" "(setq
thick1 (atof $value))")
(terpri)
(princ
thick1)
(action_tile "col" "(setq col1
$value)")
(terpri)
(princ col1)
(terpri)
(start_dialog)
(unload_dialog num)
(setq angle1 (* 55.0 (atan rad1 (* diam1 (/
pi 2)))))
(command "_view" "_top") ;начинаем со стандартного вида
(command "_view" "_swiso");переходим к северо-западному виду
(command "_circle" centr1 rad1 "") ;строим базовую окружность
(setq circle1 (entlast));извлекаем имя сущности для базовой окружности
(command "_ucs"
"_x" "90" "");поворачиваем ПСК
(setq endp1 (list diam1 0.0))
(command "_arc" centr1
"e" endp1 "a" "-180" "")
(setq arc1 (entlast));извлекаем имя сущности для дуги и сохраняем его
(command "_ucs" "_x" "-90");совмещаем плоскость окружности с плоскостью XY
(command "extrude" circle1
"" "t" angle1 "p" arc1 "");создаем тело рога
(setq rog1 (entlast));извлекаем имя сущности для рога и сохраняем его
(command "_zoom" "e" "");растягиваем изображение на весь экран
(command "_vscurrent" "_r" "");устанавливаем текущий визуальный стиль realistic
(command "_chprop"
"_all" "" "_color" col1 "");закрашиваем цветом col1
(command "_view"
"_bottom" "");устанавливаем вид снизу
(command "_solidedit" "_body"
"_shell" rog1 centr1 "" thick1 "" "");делаем полость
(command "_erase" arc1 "");удаляем ненужную образующую дугу
(princ)
)
Для обработки данных, вводимых в текстовых полях диалогового окна, применена функция action_tile. Она помещена между функциями new_dialog и start_dialog. Функция имеет следующий синтаксис:
(action_tile <код> <выражение>)
<код> — это строка с кодом элемента;
<выражение> — строка с LISP-выражением действия, выполняемого при выборе данного элемента;
Возвращаемое значение Т.
Функция action_tile присваивает значения текстовых полей переменным функции qrog. Текстовые поля различаются по кодам этих полей. Значения полей сохраняются в глобальной переменной $value. Тип сохраненных величин — строковые константы. Чтобы обеспечить возможность дальнейших расчетов, применено преобразование строковых констант в вещественные числа с помощью функции atof.
Технология создания диалоговых окон изложена в предыдущем разделе. Сейчас разберем более подробно отдельные элементы и синтаксис языка DCL с использованием LISP-программ.
Директива описания диалога задает имя, по которому диалоговое окно вызывается из программы на экран. Директива использует ключевое слово dialog:
<имя>:dialog{<атрибуты><элементы>}
В качестве имени диалога может быть использован любой идентификатор, не совпадающий со служебными словами. Имена диалогов в одном сеансе AutoCAD не должны повторяться. Параметр <атрибуты> — это последовательность разделяемых точкой с запятой операций задания атрибутам значений:
<атрибут1>=<значение1>;<атрибут2>=<значение2>;…
Параметр <элементы> является набором директив описания элементов (текстовых полей, кнопок, списков, надписей, флажков и пр.).
Имена атрибутов и элементов должны быть стандартными ключевыми словами. Значения атрибутов могут быть числами или строками, — в зависимости от атрибута. Если директива описывает элемент диалогового окна, то параметр <атрибуты> — это описание атрибутов элемента и их значений, отличных от значений по умолчанию. Если директива является директивой группировки элементов, то она содержит внутри фигурных скобок директивы определения группируемых элементов.
Атрибуты диалога — это различные характеристики окна в целом или его отдельных элементов. В таблице приведены ключевые слова, которые могут быть использованы в качестве атрибутов в директиве описания диалога.
Атрибут |
Описание |
Допустимые
значения |
Значение
по умолчанию |
label |
Начальный текст заголовка диалогового окна |
Строка |
“ “ (пробел) |
value |
Текущий текст заголовка диалогового окна |
Строка |
Нет |
key |
Код диалога |
Строка |
Нет |
width |
Ширина окна |
Число |
Нет |
height |
Высота окна |
Число |
Нет |
initial_focus |
Код подсвеченного элемента в диалоговом окне |
Строка |
Нет |
children_alignment |
Способ выравнивания подчиненных элементов по умолчанию |
left, right, centered (для колонок), top, bottom, centered (для рядов) |
left (для колонок),
centered (для рядов) |
children_fixed_width |
Фиксация ширины подчиненных элементов по умолчанию |
true, false |
false |
children_fixed_height |
Фиксация высоты подчиненных элементов по умолчанию |
true, false |
false |
Атрибуты label и value близки по смыслу. Различие между ними состоит в том, что атрибут label влияет на размер окна, а значение атрибута value — не влияет. Атрибут key обеспечивает возможность изменить программно заголовок выводимого диалогового окна. В качестве значения кода диалога могут использоваться только строки.
Атрибут width задает минимальную ширину окна в условных символах. Ширина символа равна средней ширине символа латинского алфавита шрифта по умолчанию. Ширина окна вычисляется системой по размерам заголовка и элементов. Если она получилась меньше, чем задано в значении атрибута width, то она увеличивается. То же самое справедливо для атрибута height, только здесь задается высота окна в количестве условных высот символа шрифта.
Атрибут initial_focus указывает код элемента, который подсвечивается по умолчанию и выполняет действие при нажатии пользователем клавиши ENTER.
Три атрибута с префиксом children задают свойства не самого диалога, а входящих в него элементов. Атрибут children_alignment задает способ, которым система AutoCAD выравнивает элементы, размещенные в диалоговом окне. По умолчанию элементы диалога, расположенные в колонку, выравниваются влево, а элементы, расположенные в ряд, выравниваются по центру. На элементы, у которых задан свой атрибут alignment, значение атрибута children_alignment не влияет.
Атрибуты children_fixed_width и children_fixed_height обычно задают тогда, когда их значение равно true. Это означает, что по умолчанию размеры подчиненных элементов (например, кнопок) не изменяются при выводе диалогового окна. Система не будет растягивать кнопки, а будет лишь изменять расстояния между ними.
В среде Visual LISP имеется способ проверки внешнего вида диалогового окна без загрузки DCL-файла в память системы. Для этого нужно запустить команду Tools — Interface Tools — Preview DCL in Editor. Активизируется диалоговое окно, в котором нужно выбрать имя диалога. После этого диалоговое окно отобразится на экране.
Внутри директивы описания диалога размещены директивы описания элементов. Эти директивы записываются в форме:
[<метка>]:<оператор>{<атрибуты>}
Каждый элемент является либо элементом оформления (надписи, слайды и пр.), либо элементом управления (кнопки, текстовые поля, списки и пр.). К элементам управления пользователь имеет доступ с помощью клавиатуры или указателя мыши.
В директивах в качестве значения <оператор> могут использоваться следующие наименования элементов:
button — кнопка;
edit_box — редактируемое текстовое поле;
errtile — поле для отображения сообщений об ошибках;
image — поле с изображением;
image_button — кнопка с изображением;
list_box — список;
popup_list —раскрывающийся список;
radio_button — переключатель;
radio_column — вертикальная группа переключателей;
radio_row — горизонтальная группа переключателей;
boxed_radio_column — конка переключателей в рамке;
boxed_radio_row — ряд переключателей в рамке;
slider — скользящая шкала;
toggle — флажок;
column — колонка (средство объединения элементов);
row — ряд (средство объединения элементов);
text — нередактируемое текстовое поле;
text_part — часть текста, включаемая в элементы concatenation и paragraph;
concatenation — горизонтальное соединение элементов text_part;
paragraph — вертикальное соединение элементов text_part и concatenation;
spacer — пустой элемент ширины width и высоты height;
spacer_0 — элемент c нулевыми значениями ширины width и высоты height;
spacer_1 — элемент spacer c единичными значениями width и height.
В файле base.dcl определены следующие элементы, ссылки на которые очень часто применяются в пользовательских диалоговых окнах:
ok_button — элемент с одной кнопкой ОК;
ok_only — элемент в виде колонки с одной кнопкой ОК;
ok_cancel — элемент из кнопок OK и Cancel;
ok_cancel_help — элемент из кнопок OK, Cancel и Help;
ok_ cancel_err — элемент из кнопок OK и Cancel и полем сообщений об ошибках;
ok_cancel_help_errtile — элемент из кнопок OK, Cancel, Help и полем сообщений об ошибках;
ok_cancel_help_info — элемент из кнопок OK, Cancel, Help и
Info.
Все эти элементы содержат кнопку выхода из диалогового окна. Ниже приведены коды (keys) стандартных элементов, включенные в элементы с кнопкой выхода.
Элемент
(кнопка) |
Код
элемента |
OK |
“accept” |
Cancel |
“cancel” |
Help |
“help” |
Info |
“info” |
Поле
сообщений об ошибках |
“error” |
При описании элемента нет необходимости перечислять значения всех его атрибутов. Достаточно указать только те атрибуты, значения которых должны отличаться от значений по умолчанию. Большая часть атрибутов (например, label, value, key, width, height и др.) применяется во всех элементах. Однако смысл атрибута в разных элементах может быть различным.
Ниже приведены некоторые часто употребляемые атрибуты
Атрибут |
Описание |
Допустимые
значения |
Область
применения |
Значения
по умолчанию |
action |
Действия, выполняемые при выборе данного элемента |
Строка с текстом AutoLISP |
Элементы управления |
“ ” |
alignment |
Способ выравнивания |
left, right,
centered; top, bottom, centered |
Все элементы |
left, centered |
color |
Цвет |
0-256 или black, red, yellow, green,
cyan, blue, magenta |
image |
7 |
edit_width |
Количество видимых символов в редактируемом поле |
Целое число |
edit_box |
Максимально возможное |
is_cancel |
Признак срабатывания при нажатии ESC |
true, false |
button (только
один элемент) |
false |
is_default |
Признак срабатывания при нажатии ENTER |
true, false |
button (только один элемент) |
false |
key |
Код элемента |
Строка |
Все элементы |
Нет |
label |
Начальный заголовок |
Строка |
Все элементы |
“ “ |
list |
Начальное состояние списка |
Строка с элементами списка (разделитель \n) |
list_box,
popup_list |
Нет |
multiple_select |
Разрешение множественности выбора |
true, false |
list_box |
false |
password_char |
Символ, закрывающий текст вводимого пароля |
Символ |
Edit_box |
Нет |
value |
Начальное значение |
Строка |
Все элементы |
Нет |
Для того, чтобы вызвать на экран диалоговое окно, необходимо сначала загрузить DCL-файл, содержащий нужный диалог с описанием окна. Затем нужно открыть диалоговое окно. После завершения в окне всех установок оно должно быть закрыто. После закрытия диалогового окна DCL-файл выгружается из оперативной памяти. Все эти операции выполняются с помощью специальных функций.
Функция load_dialog загружает DCL-файл в оперативную память компьютера. Синтаксис функции:
(load_dialog <файл>)
Аргумент <файл> — текстовая строка (текст в кавычках) с именем файла. Возвращаемое значение — положительное целое число при успешной загрузке. Это число является порядковым номером DCL-файла, загруженного в данном сеансе работы с сиcтемой AutoCAD. Если загрузка не выполнена, то функция возвращает отрицательное число. Если в имени файла не указан полный путь, то система AutoCAD пытается найти файл, просматривая все маршруты файлов поддержки.
Функция unload_dialog выгружает DCL-файл из оперативной памяти компьютера. Синтаксис функции:
(unload_dialog <номер>)
Аргумент <номер> — положительное целое число, которое было возвращено при вызове функции load_dialog. Возвращаемое значение — nil.
Функция new_dialog открывает на экране диалоговое окно, если его диалог уже загружен в оперативную память в составе DCL-файла. Синтаксис функции:
(new_dialog <диалог> <номер> [<действие> [<положение>]])
Аргументы:
<диалог> — текстовая строка с именем диалога;
<номер> — положительное целое число, возвращаемое функцией load_dialog;
<действие> — строка с LISP-выражением (если нет действия, оставить “”);
<положение> — координаты левого верхнего угла диалогового окна.
Функция возвращает Т, если диалоговое окно открылось, и nil, если возникла ошибка открытия. Когда по условиям задачи аргумент <положение> должен быть задан, то должен быть задан и аргумент “действие”. Это действие будет выполнено только тогда, когда пользователь выбрал элемент, для которого не задано действие с помощью атрибута action или функции action-tile.
Пример:
(new_dialog “cone” num “” (list 111 222)) — открывает диалоговое окно с диалогом cone. Левый верхний угол помещен в точку (111,222). Функция возвращает T.
Функция start_dialog активизирует диалоговое окно и готовит систему AutoCAD к приему действий пользователя в этом окне. Синтаксис:
(start_dialog)
Возвращает целое число, которое было передано в качестве аргумента функции done_dialog. Если приложение закрывает диалоговое окно, а функции done_dialog при этом не передано никакого аргумента, то функция start_dialog возвратит:
1 — если пользователь выйдет из диалогового окна с помощью кнопки ОК;
0 — если пользователь выйдет из диалогового окна с помощью кнопки Cancel;
-1 — если работа всех диалоговых окон будет прервана с помощью функции term_dialog.
Функция done_dialog используется только внутри LISP-выражений в функции action-tile или атрибуте action. Она закрывает диалоговое окно и передает значение, которое будет возвращаемым значением функции start_dialog. Синтаксис:
(done_dialog [<число>])
Аргумент <число> — это положительное целое число, которое станет возвращаемым значением функции start_dialog. Возвращаемое значение — список из двух целых чисел с координатами левого верхнего угла диалогового окна в момент его закрытия.
Пример:
(done_dialog 92) — может вернуть список (220 180), а функция start_dialog при этом вернет 92.
Функция term_dialog закрывает все открытые диалоговые окна так, как будто пользователь вышел из каждого из них, нажимая кнопку Cancel. Синтаксис:
(term_dialog)
Возвращаемое значение — nil.
Если работа приложения прерывается по какой-то причине, а некоторые диалоговые окна остались незакрытыми, то система AutoCAD сама обеспечивает вызов функции term_dialog.
Несколько функций языка LISP управляют элементами и их действиями. Они позволяют выполнять следующие операции:
· задавать LISP-выражение, выполняемое при выборе элемента и нажатии клавиши ENTER или щелчке левой клавишей мыши (функция action_tile);
· отключать элемент и включать его (функция mode_tile);
· читать текущее содержимое элемента (функция get_tile);
· менять текущее содержимое элемента (функция set_tile);
· читать значение атрибута элемента (функция get_attr);
· связывать с элементом данные пользователя (функция client_data_tile).
Функция action_tile задает при помощи LISP-выражения действие, которое нужно выполнить системе AutoCAD при выборе элемента или редактировании его содержимого. Синтаксис функции:
(action_tile <код> <выражение>)
Аргументы: <код> — строка с кодом элемента, <выражение> — строка с LISP-выражением. Возвращаемое значение — Т.
Большинство элементов диалогового окна являются элементами управления. Для них должны быть описаны действия, выполняемые системой AutoCAD при выборе пользователем этого элемента. Под выбором элемента имеются в виду, в частности, такие события, вызванные пользователем:
· нажатие клавиши Enter;
· щелчок мышью по кнопке Button;
· редактирование содержимого поля edit_box;
· выбор элемента списка list_box или popup_box;
· движение шкалы элемента slider.
Отклик системы на события окна совершается тогда, когда после операции с одним элементом курсор перейдет к другому элементу или пользователь выйдет из диалогового окна с помощью кнопки выхода.
Такое действие для каждого элемента может быть задано с помощью атрибута action DCL-файла. Значением атрибута может быть строка с LISP-выражением (там не должно быть функции command). Другой вариант задания действия — указание LISP-выражения в строке, передаваемой в качестве аргумента функции action_tile. Обращение к этой функции должно быть записано между вызовами функций new_dialog и start_dialog.
Действие, заданное с помощью аргумента <выражение> функции action_tile аннулирует действие, заданное значением атрибута action этого элемента в DCL-файле. Действие всегда задается через код элемента. Значение атрибута key передается функции action_tile в качестве аргумента <код>.
LISP-выражение в функции action_tile может использовать значения зарезервированных глобальных переменных со следующими именами:
· $value — текущее значение рассматриваемого элемента;
· $key — код рассматриваемого элемента;
· $reason — тип действия, выполненного над элементом;
· $data — данные элемента, заданные функцией client_data_tile;
· $x и $y — координаты указанной точки внутри изображения.
Примеры:
(action_tile “accept” “(done_dialog)”) — действие кнопки выхода;
(action_tile “Test” (strcat “(if (<= (atoi $value) 0))” “(alert \”Отрицательные числа не допускаются!\”)”)) — проверка значения элемента на отрицательные числа или ноль;
В этом примере длинное LISP-выражение получено сцепкой двух строк. Обратите внимание на то, что внутренние двойные кавычки, необходимые для вызова функции alert, применяются с предшествующим слэшем.
(action_tile “Test” “(setq myTest 1) (saveVars) (done_dialog)”)
По событию с элементом “Test” выполняется три действия: переменной myTest присваивается значение 1, запускается функция saveVars и закрывается диалоговое окно. Обратите внимание, что и код и выражение всегда берутся в кавычки.
Функция mode_tile изменяет состояние элемента диалога. Синтаксис:
(mode_tile <код> <состояние>)
Аргументы: <код> — код элемента; <состояние> — целое число от 0 до 4 (см. таблицу). Возвращаемое значение — nil.
Значение |
Действие |
0 |
Включить элемент |
1 |
Выключить элемент (сделать недоступным) |
2 |
Выбрать элемент |
3 |
Подсветить содержимое элемента |
4 |
Включить/выключить подсветку изображения |
При выключении элемента его цвет приглушается. Он становится недоступным для пользователя. Чтобы сделать его вновь доступным, его надо включить.
Примеры:
(mode_tile “k1” 1) — выключает элемент с кодом k1;
(mode_tile “k1” 0) — включает элемент с кодом k1.
Функция set_tile позволяет менять содержание диалога, заданное атрибутом value.
(set_tile <код> <значение>)
Аргументы: <код> — код элемента; <значение> — строка с новым значением, присваиваемым атрибуту value данного элемента.
Возвращаемое значение — значение второго аргумента, переданного функции.
Функция get_tile читает содержимое элемента диалога (текущее значение атрибута value). Синтаксис:
(get_tile <код>)
Аргумент — строка с кодом элемента.
Возвращаемое значение — строка с текущим значением атрибута value.
Функция get_attr читает значение атрибута элемента текущего каталога:
(get_attr <код> <атрибут>)
Аргументы: <код> — строка с кодом элемента, <атрибут> — строка с именем атрибута. Возвращаемое значение — строка со значением атрибута элемента.
Пример:
(get_attr “user” “alignment”) — возвратит “centered”
Функция client_data_tile связывает с элементом диалогового окна строку с пользовательскими данными. Синтаксис:
(client_data_tile <код> <данные>)
Аргументы: <код> — строка с кодом элемента, <данные> — строка с пользовательскими данными. Возвращаемое значение — nil.
Чтобы обратиться к данным, присоединенным к элементу диалогового окна, нужно прочитать значение переменной $data в функции action_tile. Так можно изменять действие, присвоенное элементу, в зависимости от пользовательских данных.
Пример:
(client_data_tile “user” “2110”) — связывает строку 2110 с элементом “user”.
Во время работы диалогового окна система AutoCAD формирует значения глобальных переменных, которые называются переменными действия:
$key, $value, $reason,
$data, $x, $y.
В них сохраняются некоторые дополнительные данные о состоянии диалогового окна и выполненных в нем действиях пользователя. Переменные используются в LISP-выражениях, задаваемых в качестве второго аргумента функции action_tile. Вне этой функции значения переменных действия не определены.
Пользовательская программа не может изменять значения этих переменных и должна применять их только для чтения. В таблице рассматриваются различные варианты формирования значений переменных действия.
Переменная |
Значение |
$key |
Код элемента (во всех элементах) |
$value |
Значение атрибута value во всех элементах. Для поля edit_box — это введенная строка; Для toggle — “1” (включен) или “0” — выключен; Для list_box и popup_list — строка с номером (номерами) выбранных элементов списка или nil, если ни один элемент списка не выбран |
$data |
Строка с пользовательскими данными, привязанными к элементу |
Sreason |
Для элементов edit_box, list_box, image_button и slider — число с кодом причины прерывания работы с элементом (см. следующую таблицу) |
$x, $y |
Координаты в пикселях указанной пользователем точки внутри изображения для элемента image_button |
Примеры:
(action_tile
“user” “(setq nam (strcat \ “Пользователь: \” $value))”);
(action_tile
“cldat” “(setq tyg (read $data))”);
Таблица. Значения переменной $reason
Значение |
Описание |
1 |
Обычный вариант действия с
элементом, в том числе, пользователь выбрал элемент, нажата клавиша ENTER, а элемент имеет значение true атрибута is_default |
2 |
Для поля edit_box:
пользователь вышел из поля, но не завершил редактирование (например, нажал
клавишу TAB или выбрал другой элемент) |
3 |
Для элемента slider: пользователь изменил значение элемента с помощью
указателя шкалы, но не завершил ввода |
4 |
Для элементов list_box
и image_button: пользователь
выполнил двойной щелчок. Если multiple_selection=false, то это
должно означать окончательный выбор. Если multiple_selection=true, то это должно обрабатываться как обычный выбор
(значение 1). |
Функция start_list начинает операцию редактирования списка в элементах list_box и popup_list. Синтаксис функции:
(start_list <код>[<операция> [<номер>]])
Аргументы:
<код> — код элемента, список которого редактируется;
<операция> — целое число, обозначающее тип операции:
1 — изменить выбранные элементы;
2 — добавить новые элементы;
3 — удалить старый список и создать новый;
<номер> — номер элемента, начиная с которого вносятся изменения (операция=1);
По умолчанию для второго аргумента действующее значение равно 3, а для третьего аргумента — равно 0. Аргументы в списке нумеруются, начиная с нуля.
Возвращаемое значение — код элемента
Вызов функции start_list является отметкой начала операции формирования или редактирования списка. Вызов функции end_list является отметкой окончания операции. Изменения вносятся с помощью функции add_list и других функций, расположенных между start_list и end_list. Здесь нельзя использовать функцию set_tile.
Примеры:
(start_list “kr2”) — указывает начало операции формирования заново списка для элемента диалога с кодом “kr2”;
(start_list “kr2” 2) — указывает начало операции добавления новых элементов списка для элемента диалога с кодом “kr2”;
(start_list “kr2” 1 14) — указывает начало операции замены элементов списка, начиная с 14, для элемента диалога с кодом “kr2”.
Функция add_list выполняет операцию редактирования списка в элементах list_box и popup_list. Синтаксис функции:
(add_list <строка>)
Аргументы <строка> — строка, которая добавляется к списку или заменяет элемент списка. Возвращаемое значение — значение аргумента <строка>, если операция выполнена успешно. В случае сбоя возвращается nil.
Тип операции (изменение или добавление) определяется предшествующим вызовом функции start_list.
Пример: (add_list “Деталь 3217-06”)
Функция end_list завершает операцию редактирования списка в элементах list_box и popup_list. Синтаксис функции:
(end_list)
Возвращаемое значение nil.
Элементы image и image_button являются графическими полями с прямоугольной зоной. Зона может быть заполнена
· одним цветом;
· слайдом;
· отрезками разных цветов.
Открывает процесс заполнения функция start_image, а завершает процесс заполнения функция end_image. Между ними располагаются функции fill_image, slide_image, vector_image. Не допускается применять функцию set_tile. При указании координат в графическом окне предполагается, что левый верхний угол графического элемента находится в начале координат. Координаты правого нижнего угла могут быть получены с помощью функций dimx_tile и dimy_tile.
Функция start_image открывает процесс заполнения графического элемента. Синтаксис:
(start_image <код>)
Аргумент <код> — значение атрибута key графического элемента. Возвращаемое значение — строка со значением аргумента, если операция выполнена успешно. В случае сбоя возвращается nil.
Функция end_image завершает процесс формирования изображения. Синтаксис:
(end_image)
Возвращаемое значение — nil.
Вызову функции end_image должен обязательно предшествовать вызов функции start_image.
Функция fill_image заполняет прямоугольник внутри графического элемента одним цветом. Синтаксис:
(fill_image <x1> <y1> <ширина> <высота> <цвет>)
Аргументы:
<x1> <y1> — координаты верхнего левого угла заполняемого прямоугольника;
<ширина> <высота> — размеры заполняемого прямоугольника;
<цвет> — индекс цвета.
Возвращаемое значение — значение аргумента <цвет>.
Пример:
(fill_image 5 6 15 25 1) — заполняет красным (1) цветом прямоугольник с левым верхним углом в точке (5,6) и нижним правым углом в точке (15,25).
Функция slide_image заполняет графический элемент слайдом из отдельного SLD-файла или из библиотеки слайдов. Синтаксис:
(slide_image <x1> <y1> <ширина> <высота> <слайд>)
Аргументы <x1> <y1> <ширина> <высота> аналогичны таковым для функции fill_image. Аргумент <слайд> — строка с именем файла слайда (расширение .sld не указывается) или с именем библиотеки слайдов (имя слайда из библиотеки указывается в круглых скобках).
Возвращаемое значение — строка со значением аргумента <слайд>.
Примеры:
(slide_image 0 0 50 32 “ring1”) — заполняет графический элемент размером 50х30 слайдом из файла ring1.sld.
(slide_image 0 0 50 32 “lib23(nut8)”) — заполняет графический элемент размером 50х30 слайдом nut8 из библиотеки слайдов lib23.
Функция vector_image рисует отрезок заданного цвета внутри графического элемента диалогового окна. Синтаксис:
(vector_image <x1> <y1> <x2> <y2> <цвет>)
Аргументы:
<x1>, <y1> — координаты (в пикселях) начала отрезка;
<x2>, <y2> — координаты (в пикселях) конца отрезка;
<цвет> — индекс цвета
Пример:
(vector_image 5 11 33 11 2) — рисует отрезок желтого цвета из точки (5,11) в точку (33, 11).
Функция dimx_tile вычисляет горизонтальный размер графического элемента с данным кодом (точнее, размер элемента минус 1). Синтаксис:
(dimх_tile <код>)
Аргумент <код> — строка с кодом графического элемента. Возвращаемое значение — целое число с номером крайнего правого пикселя элемента (левый крайний пиксель имеет номер ноль).
Пример:
(dimx_tile “igp2”) — может вернуть 50 (всего по горизонтали 51 пиксель)
Функция dimy_tile вычисляет вертикальный размер графического элемента с данным кодом (точнее, размер элемента минус 1). Синтаксис:
(dimy_tile <код>)
Аргумент <код> — строка с кодом графического элемента. Возвращаемое значение — целое число с номером крайнего нижнего пикселя элемента (верхний крайний пиксель имеет номер ноль)
Пример:
(dimy_tile “igp2”) — может вернуть 32 (всего по вертикали будет 33 пикселя).
Установите элементы диалогового окна согласно следующей программе:
// Установки элементов диалогового окна
//
elements: dialog {label="Установка элементов диалогового окна";
:column{:row{:boxed_column{label="Элементы управления";
:row{:boxed_column{label="Поле и выпадающий список";
:edit_box
{label="Edit_box";key="txt";value="0.00";edit_width=8;}
:popup_list
{label="Popup_list";key="pop";width="8";list="Иванов\nПетров\nСидоров";}}
:boxed_column{label="Кнопка и
шкала";
:button
{label="Button";key="but";color="1";width="8";}
:slider {label="Slider";}}}
:spacer{height=1;}
:radio_row {label="Ряд переключателей (radio_row)";
:radio_button {label="Radio_button
1";value=1;}
:radio_button {label="Radio_button
2";value=0;}
}
}
:boxed_row{:column{label="Список и
флажок";
:list_box
{label="List_box";key="list";list="Иванов\nПетров\nСидоров";height="8";}
:toggle {label="Toggle";value=1;}
}
}}
:boxed_row{label="Стандартная кнопка закрытия окна";
ok_cancel_help_info;
}}}
Сохраните файл как
Elements.dcl в папке Support.
Создайте файл загрузки:
(defun
c:show_elements (/ num ddiag)
(if (< (setq num (load_dialog
"elements.dcl")) 0)
(prong
(alert "The Elements.dcl
file could not be loaded!") (exit))
)
(if (not (new_dialog "elements"
num))
(exit)
)
(start_dialog)
(unload_dialog num)
;;;--- If the
user pressed the Cancel button
(if (= ddiag 1)
(princ "\n Window cancelled!")
)
;;;--- If the
user pressed the Okay button
(if (= ddiag 2)
(progn
(princ "\n The user pressed
Okey!")
)
)
(princ)
) ;_defun
Сохраните файл загрузки как Elements.dcl.
Запустите функцию show_elements из командной строки AutoCAD. На экране должно появиться диалоговое окно (рис. 6.3).
Рис. 6.3. Элементы диалогового окна
Программа может различить в наших действиях лишь нажатие кнопок ОК и Cancel.
Измените описание диалогового окна в файле rog.dcl:
//Диалоговое окно установки параметров рога
rog: dialog{label="Установка параметров рога";
:edit_box{label="Радиус окружности ";key="rad" ;value="150.00";
edit_width=8;}
:edit_box{label="Диаметр дуги, мм";key="diam";value="300.00";edit_width=8;}
:edit_box{label="Толщина стенки, мм";key="thick";value="1.00";edit_width=6;}
:spacer{height=1;}
:edit_box{label="Индекс цвета";key="col";value="2";edit_width=4;}
:spacer{height=1;}
ok_cancel;
}
А теперь вернитесь к файлу rog.lsp. В функции qrog отклики на события в диалоговом окне описывались с помощью функции action_tile. Значения переменных сохранялись для каждого отдельного элемента. Опробуйте другой способ сохранения указанных данных — по нажатии кнопки ОК. В этом случае можно оставить значения величин по умолчанию, либо отредактировать их в текстовых полях диалогового окна.
Создайте в этом же файле новую функцию save_vars, которая будет вызываться после нажатия кнопки ОК. Содержимое текстовых полей прочитает функция get_tile.
Следует учесть, что в данном случае переменные rad1, diam1, thick1, col1 должны быть общими для функций qrog и save_vars, т.е. глобальными.
(defun save_vars
()
(setq rad1 (atof (get_tile “rad”)))
(setq diam1 (atof (get_tile “diam”)))
(setq thick1 (atof (get_tile “thick”)))
(setq col1 (get_tile “col”))
)
Программа построения рога будет выглядеть следующим образом:
(defun c:qrog (/
cenrt1 circle1 arc1 rog1 angle1 endp1 dial)
(setq centr1 '(0 0 0)) ;исходная базовая точка
(if (< (setq num (load_dialog
"rog.dcl")) 0)
(progn
(alert "Файл Rog.dcl не загружен!")
(exit)
))
(if (not (new_dialog "rog" num))
(progn
(alert "Диалог Rog не найден!")
(exit)
))
;;;If an action event occurs,
do this function
(action_tile
"accept" "(setq dial 2)(save_vars)(done_dialog)")
(action_tile
"cancel" "(setq dial 1)(done_dialog)")
(start_dialog)
(unload_dialog num)
(setq angle1 (* 55.0 (atan rad1 (* diam1 (/
pi 2)))))
(command "_view" "_top") ;начинаем со стандартного вида
(command "_view" "_swiso");переходим к северо-западному виду
(command "_circle" centr1 rad1 "") ;строим базовую окружность
(setq circle1 (entlast));извлекаем имя сущности для базовой окружности
(command "_ucs" "_x"
"90" "");поворачиваем ПСК
(setq endp1 (list diam1 0.0))
(command "_arc" centr1
"e" endp1 "a" "-180" "")
(setq arc1 (entlast));извлекаем имя сущности для дуги и сохраняем его
(command "_ucs"
"_x" "-90");совмещаем плоскость окружности с плоскостью XY
(command "extrude" circle1
"" "t" angle1 "p" arc1 "");создаем тело рога
(setq rog1 (entlast));извлекаем имя сущности для рога и сохраняем его
(command "_zoom" "e" "");растягиваем изображение на весь экран
(command "_vscurrent" "_r" "");устанавливаем текущий визуальный стиль realistic
(command "_chprop" "_all"
"" "_color" col1 "");закрашиваем цветом col1
(command "_view"
"_bottom" "");устанавливаем вид снизу
(command "_solidedit" "_body"
"_shell" rog1 centr1 "" thick1 "" "");делаем полость
(command "_erase" arc1 "");удаляем ненужную образующую дугу
;;;If the user
pressed the Okey Or Cancel button
(if(= dial 2)
(alert “Congratulations!"))
(if(= dial 1)
(alert “Alas!"))
(princ)
)
Введите операции сохранения значений переменных в функцию qrog. Сделайте все переменные локальными. Функция save_vars тогда не нужна.
Создадим DCL-файл описания диалогового окна с тремя кнопками Button и одной кнопкой Cancel. Каждая из трех кнопок должна выдать послание при нажатии.
Расположите кнопки в колонку друг под другом в две группы:
But:dialog
{label="Работа с кнопками Button";
:column{:boxed_column{
:button
{key="but1";label="Button1";is_default="false";}
:button
{key="but2";label="Button2";is_default="false";}
:button
{key="but3";label="Button3";is_default="false";}
}
:boxed_row{
ok_cancel;
}
}
}
Сохраните файл как
But.dcl в папке …\Support.
А теперь составьте файл But.lsp для загрузки dcl-файла и описания сценария отклика на события в диалоговом окне. Он будет состоять из двух функций:
(defun C:But1()
;;;--- Load the dcl file
(setq dcl_id
(load_dialog "But.dcl"))
;;;--- Load the
dialog definition if it is not already loaded
(if (not (new_dialog "But" dcl_id))
(progn
(alert "The But.dcl file could not be loaded!")(exit)
)
)
;;;--- If an action event occurs, do this function
(action_tile "but1" "(doButton 1)")
(action_tile "but2" "(doButton 2)")
(action_tile "but3" "(doButton 3)")
(action_tile
"cancel" "(done_dialog)")
;;;--- Display the dialog box
(start_dialog)
;;;--- Unload the
dialog box
(unload_dialog dcl_id)
;;;--- Suppress the last echo for a clean exit
(princ)
)
(defun
doButton(a)
(cond
((= a 1)(alert "Button 1 was
pressed!"))
((= a 2)(alert "Button 2 was
pressed!"))
((= a 3)(alert "Button 3 was
pressed!"))
)
)
На экране должна быть картинка, подобная рис. 6.4.
Рис. 6.4. Диалоговое окно с кнопками
Составьте файл List.dcl с описанием диалогового окна с двумя списками в верхнем ряду и кнопкой ОК и Cancel в нижнем ряду. Сохраните его в папке …\Support.
list: dialog {label = "Работа со списками list_box";
: column {
: boxed_row {:
text { key = "text1"; value = "Nothing selected"; }}
: boxed_row {
: list_box {key =
"mylist1"; label ="Choose Item"; height = 9; width = 8;
multiple_select = false; fixed_width_font = true;
list="Лимон\nЛист\nНебо\nСажа\nСнег\nЯблоко";}
: boxed_row {
: popup_list {
key = "mylist2"; label ="Choose Color"; width = 8;
multiple_select = false;
fixed_width_font
= true; list="red\nyellow\ngreen\ncyan\nwhite\nblack";}}}
: boxed_row {
: button { key =
"accept"; label = "Okey "; is_default = true; }
: button { key =
"cancel";label = "Cancel "; is_default = false; is_cancel =
true; }}
}
}
Заполнение спискoв здесь произведено с помощью атрибута list. Однако, если бы мы написали атрибуты value = "";, то списки были бы пустыми. В этом случае они заполняются при запуске файла List.lsp так, как это показано ниже.
Составьте теперь загрузочный файл List.lsp. Строки, относящиеся к загрузке списков, закомментированы. Если списки уже заполнены, то эти строки можно удалить. Если их раскомментировать, то старое содержимое в списках будет удалено, а новые записи установлены.
(defun C:list ()
;;; (setq myList1(list "Лимон" "Лист" "Небо"
" Сажа" "Снег" "Яблоко"))
;;; (setq myList2(list "red" "yellow"
"green" "cyan" "white" "black"))
;;;--- Load the dcl file
(setq dcl_id (load_dialog
"list.dcl"))
;;;--- Load the dialog definition if it is not already loaded
(if (not (new_dialog
"list" dcl_id))
(progn
(alert "The List.DCL file
could not be loaded!")
(exit)
)
)
;;; (start_list "mylist1" 3)
;;; (mapcar 'add_list myList1)
;;; (end_list)
;;; (start_list "mylist2" 3)
;;; (mapcar 'add_list myList2)
;;; (end_list)
;;;--- If an action event occurs,
do this function
(action_tile "mylist2" "(saveVars)")
(action_tile "accept"
"(setq ddiag 2)(done_dialog)")
(action_tile "cancel"
"(setq ddiag 1)(done_dialog)")
;;;--- Display the dialog box
(start_dialog)
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the user pressed the
Cancel button
(if(= ddiag 1)
(princ "\n List
cancelled!")
)
;;;--- If the user pressed the
Okay button
(if(= ddiag 2)
(progn
(princ "\n The user pressed
Okay!")
)
)
(princ)
)
(defun saveVars ()
(setq numstrlist (atoi (get_tile "mylist1")))
(princ numstrlist)
(setq word_list (cond
((= numstrlist 0) "Лимон")
((= numstrlist 1) "Лист")
((= numstrlist 2) "Небо")
((= numstrlist 3) "Сажа")
((= numstrlist 4) "Снег")
((= numstrlist 5) "Яблоко")
(Т "")
) ;_конец cond
) ;_ конец setq
(setq numstrpop (atoi (get_tile
"mylist2")))
(princ numstrpop)
(setq word_pop (cond
((= numstrpop 0) "red")
((= numstrpop 1) "yellow")
((= numstrpop 2) "green")
((= numstrpop 3) "cyan")
((= numstrpop 4) "white")
((= numstrpop 5) "black")
(Т "")
) ;_конец cond
) ;_ конец setq
(setq myStr (strcat word_list
" имеет цвет " word_pop))
(set_tile "text1" myStr)
)
В этот же файл занесена функция saveVars, которая определяет отклики на события диалогового окна. Событие состоит в выборе слова в левом списке и слова в правом списке. Оба выбранных слова занесем в строку text по щелчку в правом списке. Если щелкнуть по кнопке ОК, то окно закроется.
При чтении значения списка функция get_tile возвращает номер строки, которые нумеруются с нуля. Поэтому далее нужно в цикле или с помощью функции cond найти соответствие между номером строки и значением элемента.
Диалоговое окно списков показано на рис. 6.5. Выбранная запись отражена в нередактируемом текстовом поле text в верхней части окна.
Рис. 6.5. Окно с двумя списками
Составьте программу построения диалогового окна с колонкой флажков. Сохраните файл как …\Support\Toggle.dcl
Toggle: dialog { label = "Работа с элементами toggle";
: column {: column
{
: text { key = "text1"; value = "Nothing selected }
}
:
boxed_column { label =
"Choose your lucky charms:";
: toggle { key = "tog1"; label = "Hearts"; value =
"0";}
: toggle { key = "tog2";label = "Moons";value =
"0";}
: toggle key = "tog3";label = "Stars";value =
"0";}
: toggle { key = "tog4";label = "Clovers";value =
"0";}
}
: boxed_row {
: button {key =
"cancel";label = "Cancel";is_default = true; is_cancel =
true;}
}
}
Теперь составьте файл загрузки и обработки Toggle.lsp. В этом файле создано две функции: chkToggle и Toggle:
(defun
chkToggle()
(setq tog1(atoi(get_tile "tog1")))
// 0 = not chosen 1 = chosen
(setq tog2(atoi(get_tile
"tog2"))) // 0 = not chosen 1
= chosen
(setq tog3(atoi(get_tile
"tog3"))) // 0 = not chosen 1
= chosen
(setq tog4(atoi(get_tile
"tog4"))) // 0 = not chosen 1
= chosen
(setq myStr "")
(if(= tog1 1)(setq myStr(strcat myStr
" Hearts")))
(if(= tog2 1)(setq myStr(strcat myStr
" Moons")))
(if(= tog3 1)(setq myStr(strcat myStr
" Stars")))
(if(= tog4 1)(setq myStr(strcat myStr
" Clovers")))
;;;--- If nothing was selected...
(if(= myStr "")(setq myStr
"Nothing Selected!"))
;;;--- Now set the text control to display the
string
(set_tile "text1" myStr)
)
(defun
C:Toggle()
;;;--- Load the dcl file
(setq dcl_id (load_dialog "Toggle.dcl"))
;;;--- Load the dialog definition if it is not
already loaded
(if (not (new_dialog "Toggle"
dcl_id) ) (exit))
;;;--- If an action event occurs, do this
function
(action_tile "tog1"
"(chkToggle)")
(action_tile "tog2"
"(chkToggle)")
(action_tile "tog3"
"(chkToggle)")
(action_tile "tog4"
"(chkToggle)")
(action_tile "cancel"
"(done_dialog)")
;;;--- Display the dialog box
(start_dialog)
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- Suppress the last echo for a
clean exit
(princ))
Ha экране диалоговое окно выглядит так, как на рис. 6.6.
Рис. 6.6. Диалоговое окно с флажками
Постройте диалоговое окно с четырьмя переключателями. Из всей группы только один из переключателей может быть выделен. Он должен быть определен при нажатии кнопки ОК.
Составьте DCL-файл для колонки из четырех переключателей. Внизу окна поместите кнопки OK и Cancel. Сохраните файл как С:\Program Files\AutoCAD 2007\Support\Radio.dcl. Файл можно сохранить и в другом каталоге. Тогда загрузить его в чертеж нужно по команде Tools — AutoLISP — Load Application. Загрузить можно и непосредственно из среды Visual LISP.
Radio : dialog {
label = "Переключатели RadioButtons";
: column {
: radio_column {
key
= "mychoice";
: radio_button {
key
= "but1";
label
= "Apples";
value =1;
}
: radio_button {
key = "but2";
label = "Oranges";
}
: radio_button {
key = "but3";
label = "Bananas";
}
: radio_button {
key = "but4";
label = "Lemons";
}
}
: boxed_column {
: button {
key = "accept";
label = " Okay ";
is_default = true;
}
: button {
key = "cancel";
label = " Cancel ";
is_default = false;
is_cancel = true;
}
}
}
}
Далее создайте LSP-файл загрузки:
(defun C:Radio()
;;;--- Load the dcl file
(setq dcl_id (load_dialog "Radio.dcl"))
;;;--- Load the dialog definition if it is not already loaded
(if (not (new_dialog "Radio" dcl_id))
(progn
(alert "The Radio.DCL
file could not be loaded!")
(exit)
)
)
;;;--- If an action event occurs, do this function
(action_tile "accept" "(setq ddiag 2)(saveVars)(done_dialog)")
(action_tile "cancel" "(setq ddiag 1)(done_dialog)")
;;;--- Display the dialog box
(start_dialog)
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the user pressed the Cancel button
(if(= ddiag 1)
(princ "\n Radio
cancelled!")
)
;;;--- If the user pressed the Okay button
(if(= ddiag 2)
(progn
(princ "\n The user pressed Okay!")
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
Загрузите файлы и запустите команду “Radio”. На экране появится диалоговое окно, в котором работают лишь кнопки OK и Cancel (рис. 6.7):
Рис. 6.7. Макет диалогового окна “Radio Buttons”
При нажатии кнопки ОК вызывается функция saveVars, которая запускает сценарий отклика на событие выделения переключателя. Составим эту функцию и поместим ее в LSP-файл:
(defun saveVars()
;;;--- Get
the key of the choice made
;;; [ returns "but1" "but2"
"but3" or "but4" whichever is selected.]
(setq
myChoice(get_tile "mychoice"))
;;;--- Get
the value of each item
(setq choice1(atoi(get_tile "but1"))) // 0 = not chosen
1 = chosen
(setq choice2(atoi(get_tile "but2"))) // 0 = not chosen
1 = chosen
(setq choice3(atoi(get_tile "but3"))) // 0 = not chosen
1 = chosen
(setq choice4(atoi(get_tile "but4"))) // 0 = not chosen
1 = chosen
)
(defun C:Radio()
;;;--- Load the dcl file
(setq dcl_id (load_dialog "Radio.dcl"))
;;;--- Load the dialog definition if it is not already loaded
(if (not (new_dialog "Radio" dcl_id))
(progn
(alert "The Radio.DCL
file could not be loaded!")
(exit)
)
)
;;;--- If an action event occurs, do this function
(action_tile "accept" "(setq ddiag
2)(saveVars)(done_dialog)")
(action_tile "cancel" "(setq ddiag 1)(done_dialog)")
;;;--- Display the dialog box
(start_dialog)
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the user pressed the Cancel button
(if(= ddiag 1)
(princ "\n Radio cancelled!")
)
;;;--- If the user pressed the Okay button
;;;--- If the
user pressed the Okay button
(if(= ddiag 2)
(progn
;;;--- Inform the user of his selection using the radio_column data
(princ "\n Using
Radio_column data...You chose ")
(cond
((= myChoice "but1")(princ
"Apples!"))
((= myChoice "but2")(princ
"Oranges!"))
((= myChoice "but3")(princ
"Bananas!"))
((= myChoice "but4")(princ
"Lemons!"))
)
;;;--- Inform the user of his selection using the radio_buttons data
(princ "\n Using
Radio_buttons data...You chose ")
(cond
((= Choice1 1)(princ
"Apples!"))
((= Choice2 1)(princ
"Oranges!"))
((= Choice3 1)(princ
"Bananas!"))
((= Choice4 1)(princ
"Lemons!"))
)
)
)
;;;---
Suppress the last echo for a clean exit
(princ))
Сейчас попробуем соединить все изложенные выше отдельные сведения о программировании диалоговых окон. Необходимо построить такой DCL-файл, который позволил бы управлять большинством параметров чертежа.
Нарисуем многоугольник или окружность на выбранном нами слое. Выбранные нами опции должны быть сохранены как опции по умолчанию при следующем открытии программы. Если выбран многоугольник, нужно выбрать число сторон в popup_list. Список слоев должен быть помещен в list_box. Выбор фигуры должен производиться радиокнопкой radio_column. В элементе toggle нужно поставить флажки "Save Settings" сохранения опций. Наконец, нам будут нужны кнопки ОК и Cancel.
Список слоев, возможно, будет большим, — для него нужно отвести одну высокую колонку. Остальные элементы следует разместить во вторую колонку. В нижнем ряду будут помещены кнопки ОК и Cancel.
Скопируйте коды элементов из вышележащих материалов урока.
SAMPLE
: dialog {
label = "Sample Dialog
Box";
: column {
: row {
:
boxed_column {
: radio_column {
key = "radios";
: radio_button {
label = "Draw Circle";
key = "drawcir";
value = "1";
}
: radio_button {
label = "Draw Polygon";
key = "drawpol";
value = "0";
}
}
: popup_list {
key = "numsides";
label = "Number of Sides";
width = 25;
fixed_width_font = true;
}
: toggle {
key = "saveset";
label = "Save settings";
}
}
:
row {
: list_box {
label
="Select Layer";
key =
"layerList";
height = 12;
width = 10;
multiple_select = false;
fixed_width_font = true;
value =
"";
}
}
}
: row {
:
button {
key =
"accept";
label = " Okay
";
is_default = true;
}
:
button {
key =
"cancel";
label = " Cancel
";
is_default = false;
is_cancel = true;
}
}
}
}
Сохраните файл как
C:\Program Files\AutoCAD 2007\Support\Sample.dcl.
Скопируйте далее lsp-файл загрузки и обработки:
(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)
)
)
;;;--- 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)
)
Сохраните файл как
C:\Program Files\AutoCAD 2007\Support\Sample.lsp.
Загрузите файлы и запустите функция Sample. На экране должно появиться диалоговое окно (рис. 6.7)
Рис. 6.7. Предварительное построение диалогового окна
Обратите внимание, что списки отсутствуют, а переключатель Draw Circle выделен (значение value=1). В элементе Toggle флажок не установлен, так как не задано значение value. Если нажать кнопку Cancel, то окно закроется. Если же нажать кнопку ОК, то будет выдано сообщение об ошибке: функция saveVars не определена.
Прежде всего составим списки числа сторон многоугольника и добавим их к элементу popup_list. Далее составим список слоев и заполним элемент list_box.
Вместо того, чтобы создавать функцию, которая получала бы все имена слоев чертежа, можно просто составить список вручную. Первый путь длиннее, но он более строгий.
Чтение имен слоев чертежа:
;;;--- Set
up a list to hold the layer names
(setq layerList(list))
;;;--- Get the first layer name in the drawing
(setq layr(tblnext "LAYER" T))
;;;--- Add the layer name to the list
(setq layerList(append layerList (list(cdr(assoc 2 layr)))))
;;;--- Step though the layer table to get all layers
(while (setq layr(tblnext "LAYER"))
;;;--- Save each layer name in the list
(setq layerList(append layerList (list(cdr(assoc 2 layr)))))
)
Составление списка вручную:
(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.8):
Рис. 6.8. Диалоговое окно со списками
Создадим сценарий отклика на события в окне в описании функции 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)