Программирование в AutoCAD

Программирование диалоговых окон на языке DCL

Разбить на страницы
Показывать лекцию целиком

Цель лекции: приобрести навыки работы в построении диалоговых окон.

Технология программирования диалогов

Постановка задачи

Рассмотрим пример программы вычерчивания полого рога с углом изгиба 180 градусов.

(defun c:qrog (/ cenrt1 rad1 diam1 circle1 arc1 rog1 thick1 angle1 endp1 col1)
  (setq centr1 '(0 0 0)) ;							исходная базовая точка
  (setq rad1 (getreal "Задайте радиус базовой окружности: "));	радиус рога (80)
  (setq diam1 (getreal "Задайте диаметр направляющей дуги: "));	диаметр изгиба рога (400)
  (setq thick1 (getreal "Задайте толщину стенки рога: "));		толщина стенки в мм (2)
  (setq col1 (getint "Задайте индекс цвета: "));				выбор: 0,1,2,3,4,5,6
  (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.
  • Требуется вместо запросов создать диалоговое окно для одновременного ввода этих параметров.

    Создание DCL-файла

    Вначале напишем отдельную программу для открытия диалогового окна. В новом чертеже 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));	загружаем в память файл "rog.dcl"
      (if (not (new_dialog "rog" num))  (exit))
    ;;функция new_dialog проверяет наличие в файле диалога "rog"
      (action_tile "rad" "(setq rad1 (atof $value))");		присваиваем значение переменной rad1
      	(terpri);						перевод строки
      	(princ rad1);					выводим на экран значение переменной rad1
      (action_tile   "diam"  "(setq diam1 (atof $value))");	присваиваем значение переменной diam1
      	(terpri);						перевод строки
      	(princ diam1);					выводим на экран значение переменной diam1
      (action_tile "thick" "(setq thick1 (atof $value))");	присваиваем значение переменной thick1
      	(terpri);						перевод строки
      	(princ thick1);					выводим на экран значение переменной thick1
      (action_tile "col" "(setq col1 $value)");		присваиваем значение переменной col1
      	(terpri) ;					перевод строки
     	 (princ col1);					выводим на экран значение переменной col1
      	(terpri);						перевод строки
      (start_dialog);						возвращает 1 или 0
      (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

    Технология создания диалоговых окон изложена в предыдущем разделе. Сейчас разберем более подробно отдельные элементы и синтаксис языка 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

    Функция load_dialog загружает DCL-файл в оперативную память компьютера. Синтаксис функции:

    (load_dialog <файл>)

    Аргумент <файл> - текстовая строка (текст в кавычках) с именем файла. Возвращаемое значение - положительное целое число при успешной загрузке. Это число является порядковым номером DCL-файла, загруженного в данном сеансе работы с сиcтемой AutoCAD. Если загрузка не выполнена, то функция возвращает отрицательное число. Если в имени файла не указан полный путь, то система AutoCAD пытается найти файл, просматривая все маршруты файлов поддержки.

    Функция unload_dialog

    Функция unload_dialog выгружает DCL-файл из оперативной памяти компьютера. Синтаксис функции:

    (unload_dialog <номер>)

    Аргумент <номер> - положительное целое число, которое было возвращено при вызове функции load_dialog. Возвращаемое значение - nil.

    Функция new_dialog

    Функция 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

    Функция start_dialog активизирует диалоговое окно и готовит систему AutoCAD к приему действий пользователя в этом окне. Синтаксис:

    (start_dialog)

    Возвращает целое число, которое было передано в качестве аргумента функции done_dialog. Если приложение закрывает диалоговое окно, а функции done_dialog при этом не передано никакого аргумента, то функция start_dialog возвратит:

  • 1 - если пользователь выйдет из диалогового окна с помощью кнопки ОК;
  • 0 - если пользователь выйдет из диалогового окна с помощью кнопки Cancel;
  • -1 - если работа всех диалоговых окон будет прервана с помощью функции term_dialog.
  • Функция done_dialog

    Функция done_dialog используется только внутри LISP-выражений в функции action-tile или атрибуте action. Она закрывает диалоговое окно и передает значение, которое будет возвращаемым значением функции start_dialog. Синтаксис:

    (done_dialog [<число>])

    Аргумент <число> - это положительное целое число, которое станет возвращаемым значением функции start_dialog. Возвращаемое значение - список из двух целых чисел с координатами левого верхнего угла диалогового окна в момент его закрытия.

    Пример:

    (done_dialog 92) - может вернуть список (220 180), а функция start_dialog при этом вернет 92.

    Функция term_dialog

    Функция 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

    Функция 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 изменяет состояние элемента диалога. Синтаксис:

    (mode_tile <код> <состояние>)

    Аргументы: <код> - код элемента; <состояние> - целое число от 0 до 4 (см. таблицу). Возвращаемое значение - nil.

    Значение Действие
    0 Включить элемент
    1 Выключить элемент (сделать недоступным)
    2 Выбрать элемент
    3 Подсветить содержимое элемента
    4 Включить/выключить подсветку изображения

    При выключении элемента его цвет приглушается. Он становится недоступным для пользователя. Чтобы сделать его вновь доступным, его надо включить.

    Примеры:

    (mode_tile "k1" 1) - выключает элемент с кодом k1;

    (mode_tile "k1" 0) - включает элемент с кодом k1.

    Функция set_tile

    Функция set_tile позволяет менять содержание диалога, заданное атрибутом value.

    (set_tile <код> <значение>)

    Аргументы: <код> - код элемента; <значение> - строка с новым значением, присваиваемым атрибуту value данного элемента.

    Возвращаемое значение - значение второго аргумента, переданного функции.

    Функция get_tile

    Функция get_tile читает содержимое элемента диалога (текущее значение атрибута value). Синтаксис:

    (get_tile <код>) 

    Аргумент - строка с кодом элемента.

    Возвращаемое значение - строка с текущим значением атрибута value.

    Функция get_attr

    Функция get_attr читает значение атрибута элемента текущего каталога:

    (get_attr <код> <атрибут>)

    Аргументы: <код> - строка с кодом элемента, <атрибут> - строка с именем атрибута. Возвращаемое значение - строка со значением атрибута элемента.

    Пример:

    (get_attr "user" "alignment") - возвратит "centered"

    Функция client_data_tile

    Функция 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

    Функция 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

    Функция add_list выполняет операцию редактирования списка в элементах list_box и popup_list. Синтаксис функции:

    (add_list <строка>)

    Аргументы <строка> - строка, которая добавляется к списку или заменяет элемент списка. Возвращаемое значение - значение аргумента <строка>, если операция выполнена успешно. В случае сбоя возвращается nil.

    Тип операции (изменение или добавление) определяется предшествующим вызовом функции start_list.

    Пример: (add_list "Деталь 3217-06")

    Функция end_list

    Функция 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 открывает процесс заполнения графического элемента. Синтаксис:

    (start_image <код>)

    Аргумент <код> - значение атрибута key графического элемента. Возвращаемое значение - строка со значением аргумента, если операция выполнена успешно. В случае сбоя возвращается nil.

    Функция end_image

    Функция end_image завершает процесс формирования изображения. Синтаксис:

    (end_image)

    Возвращаемое значение - nil.

    Вызову функции end_image должен обязательно предшествовать вызов функции start_image.

    Функция fill_image

    Функция fill_image заполняет прямоугольник внутри графического элемента одним цветом. Синтаксис:

    (fill_image <x1> <y1> <ширина> <высота> <цвет>)

    Аргументы:

  • <x1> <y1> - координаты верхнего левого угла заполняемого прямоугольника;
  • <ширина> <высота> - размеры заполняемого прямоугольника;
  • <цвет> - индекс цвета.
  • Возвращаемое значение - значение аргумента <цвет>.

    Пример: (fill_image 5 6 15 25 1) - заполняет красным (1) цветом прямоугольник с левым верхним углом в точке (5,6) и нижним правым углом в точке (15,25).

    Функция slide_image

    Функция 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 рисует отрезок заданного цвета внутри графического элемента диалогового окна. Синтаксис:

    (vector_image <x1> <y1> <x2> <y2> <цвет>)

    Аргументы:

  • <x1>, <y1> - координаты (в пикселях) начала отрезка;
  • <x2>, <y2> - координаты (в пикселях) конца отрезка;
  • <цвет> - индекс цвета
  • Пример:

    (vector_image 5 11 33 11 2) - рисует отрезок желтого цвета из точки (5,11) в точку (33, 11).

    Функция dimx_tile

    Функция dimx_tile вычисляет горизонтальный размер графического элемента с данным кодом (точнее, размер элемента минус 1). Синтаксис:

    (dimх_tile <код>)

    Аргумент <код> - строка с кодом графического элемента. Возвращаемое значение - целое число с номером крайнего правого пикселя элемента (левый крайний пиксель имеет номер ноль).

    Пример:

    (dimx_tile "igp2") - может вернуть 50 (всего по горизонтали 51 пиксель)

    Функция dimy_tile

    Функция 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.

    Текстовые поля Edit_Box

    Измените описание диалогового окна в файле rog.dcl:

    //Диалоговое окно установки параметров рога
    rog: dialog{label="Установка параметров рога";
      :edit_box{label="Радиус окружности ";key="rad" ;value="80.00"; edit_width=8;}
      :edit_box{label="Диаметр дуги, мм";key="diam";value="400.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);		загружаем в память файл "rog.dcl"
    (progn
      (alert "Файл Rog.dcl не загружен!");			сообщение о неудачной загрузке
      (exit)
      ))
      (if (not (new_dialog "rog" num));
    ;; ;;функция new_dialog проверяет наличие в файле диалога "rog"
      (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)");	действия при нажатии CANCEL
      (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 тогда не нужна.

    Рассмотрим теперь более подробно работу с отдельными элементами диалоговых окон: с кнопками, со списками, с флажками и с радиокнопками.

    Кнопки Button

    Создадим 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_box

    Составьте файл 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) Окно с двумя списками

    Работа с элементами toggle

    Составьте программу построения диалогового окна с колонкой флажков. Сохраните файл как …\Support\Toggle.dcl

    Toggle: dialog { label = "Работа с элементами toggle";
    : column {: boxed_row {
    : 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 = "accept"; label = "Okey "; is_default = true; }
    : button { key = "cancel";label = "Cancel "; is_default = false; 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) Диалоговое окно с флажками

    Переключатели Radio Buttons

    Постройте диалоговое окно с четырьмя переключателями. Из всей группы только один из переключателей может быть выделен. Он должен быть определен при нажатии кнопки ОК.

    Составьте DCL-файл для колонки из четырех переключателей. Внизу окна поместите кнопки OK и Cancel. Сохраните файл как С:\Program Files\AutoCAD 2010\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 = " Okey ";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 Okey 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 = " Okey "; 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.8)

    (рис 6.8) Предварительное построение диалогового окна

    Обратите внимание, что списки отсутствуют, а переключатель 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 layer(tblnext "LAYER" T))
    
      ;;;--- Add the layer name to the list
      (setq layerList(append layerList (list(cdr(assoc 2 layer)))))
    
      ;;;--- Step though the layer table to get all layers
      (while (setq layer(tblnext "LAYER"))
    
        ;;;--- Save each layer name in the list
        (setq layerList(append layerList (list(cdr(assoc 2 layer)))))
      )
    

    Составление списка вручную:

    (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):

    (рис 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-программы, которая запускает сценарий отклика на событие выделения радиокнопки в диалоговом окне.
  • Страницы:

    Цель лекции: приобрести навыки работы в построении диалоговых окон.

    Технология программирования диалогов

    Постановка задачи

    Рассмотрим пример программы вычерчивания полого рога с углом изгиба 180 градусов.

    (defun c:qrog (/ cenrt1 rad1 diam1 circle1 arc1 rog1 thick1 angle1 endp1 col1)
      (setq centr1 '(0 0 0)) ;							исходная базовая точка
      (setq rad1 (getreal "Задайте радиус базовой окружности: "));	радиус рога (80)
      (setq diam1 (getreal "Задайте диаметр направляющей дуги: "));	диаметр изгиба рога (400)
      (setq thick1 (getreal "Задайте толщину стенки рога: "));		толщина стенки в мм (2)
      (setq col1 (getint "Задайте индекс цвета: "));				выбор: 0,1,2,3,4,5,6
      (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.
  • Требуется вместо запросов создать диалоговое окно для одновременного ввода этих параметров.

    Создание DCL-файла

    Вначале напишем отдельную программу для открытия диалогового окна. В новом чертеже 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));	загружаем в память файл "rog.dcl"
      (if (not (new_dialog "rog" num))  (exit))
    ;;функция new_dialog проверяет наличие в файле диалога "rog"
      (action_tile "rad" "(setq rad1 (atof $value))");		присваиваем значение переменной rad1
      	(terpri);						перевод строки
      	(princ rad1);					выводим на экран значение переменной rad1
      (action_tile   "diam"  "(setq diam1 (atof $value))");	присваиваем значение переменной diam1
      	(terpri);						перевод строки
      	(princ diam1);					выводим на экран значение переменной diam1
      (action_tile "thick" "(setq thick1 (atof $value))");	присваиваем значение переменной thick1
      	(terpri);						перевод строки
      	(princ thick1);					выводим на экран значение переменной thick1
      (action_tile "col" "(setq col1 $value)");		присваиваем значение переменной col1
      	(terpri) ;					перевод строки
     	 (princ col1);					выводим на экран значение переменной col1
      	(terpri);						перевод строки
      (start_dialog);						возвращает 1 или 0
      (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

    Технология создания диалоговых окон изложена в предыдущем разделе. Сейчас разберем более подробно отдельные элементы и синтаксис языка 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

    Функция load_dialog загружает DCL-файл в оперативную память компьютера. Синтаксис функции:

    (load_dialog <файл>)

    Аргумент <файл> - текстовая строка (текст в кавычках) с именем файла. Возвращаемое значение - положительное целое число при успешной загрузке. Это число является порядковым номером DCL-файла, загруженного в данном сеансе работы с сиcтемой AutoCAD. Если загрузка не выполнена, то функция возвращает отрицательное число. Если в имени файла не указан полный путь, то система AutoCAD пытается найти файл, просматривая все маршруты файлов поддержки.

    Функция unload_dialog

    Функция unload_dialog выгружает DCL-файл из оперативной памяти компьютера. Синтаксис функции:

    (unload_dialog <номер>)

    Аргумент <номер> - положительное целое число, которое было возвращено при вызове функции load_dialog. Возвращаемое значение - nil.

    Функция new_dialog

    Функция 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

    Функция start_dialog активизирует диалоговое окно и готовит систему AutoCAD к приему действий пользователя в этом окне. Синтаксис:

    (start_dialog)

    Возвращает целое число, которое было передано в качестве аргумента функции done_dialog. Если приложение закрывает диалоговое окно, а функции done_dialog при этом не передано никакого аргумента, то функция start_dialog возвратит:

  • 1 - если пользователь выйдет из диалогового окна с помощью кнопки ОК;
  • 0 - если пользователь выйдет из диалогового окна с помощью кнопки Cancel;
  • -1 - если работа всех диалоговых окон будет прервана с помощью функции term_dialog.
  • Функция done_dialog

    Функция done_dialog используется только внутри LISP-выражений в функции action-tile или атрибуте action. Она закрывает диалоговое окно и передает значение, которое будет возвращаемым значением функции start_dialog. Синтаксис:

    (done_dialog [<число>])

    Аргумент <число> - это положительное целое число, которое станет возвращаемым значением функции start_dialog. Возвращаемое значение - список из двух целых чисел с координатами левого верхнего угла диалогового окна в момент его закрытия.

    Пример:

    (done_dialog 92) - может вернуть список (220 180), а функция start_dialog при этом вернет 92.

    Функция term_dialog

    Функция 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

    Функция 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 изменяет состояние элемента диалога. Синтаксис:

    (mode_tile <код> <состояние>)

    Аргументы: <код> - код элемента; <состояние> - целое число от 0 до 4 (см. таблицу). Возвращаемое значение - nil.

    Значение Действие
    0 Включить элемент
    1 Выключить элемент (сделать недоступным)
    2 Выбрать элемент
    3 Подсветить содержимое элемента
    4 Включить/выключить подсветку изображения

    При выключении элемента его цвет приглушается. Он становится недоступным для пользователя. Чтобы сделать его вновь доступным, его надо включить.

    Примеры:

    (mode_tile "k1" 1) - выключает элемент с кодом k1;

    (mode_tile "k1" 0) - включает элемент с кодом k1.

    Функция set_tile

    Функция set_tile позволяет менять содержание диалога, заданное атрибутом value.

    (set_tile <код> <значение>)

    Аргументы: <код> - код элемента; <значение> - строка с новым значением, присваиваемым атрибуту value данного элемента.

    Возвращаемое значение - значение второго аргумента, переданного функции.

    Функция get_tile

    Функция get_tile читает содержимое элемента диалога (текущее значение атрибута value). Синтаксис:

    (get_tile <код>) 

    Аргумент - строка с кодом элемента.

    Возвращаемое значение - строка с текущим значением атрибута value.

    Функция get_attr

    Функция get_attr читает значение атрибута элемента текущего каталога:

    (get_attr <код> <атрибут>)

    Аргументы: <код> - строка с кодом элемента, <атрибут> - строка с именем атрибута. Возвращаемое значение - строка со значением атрибута элемента.

    Пример:

    (get_attr "user" "alignment") - возвратит "centered"

    Функция client_data_tile

    Функция 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

    Функция 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

    Функция add_list выполняет операцию редактирования списка в элементах list_box и popup_list. Синтаксис функции:

    (add_list <строка>)

    Аргументы <строка> - строка, которая добавляется к списку или заменяет элемент списка. Возвращаемое значение - значение аргумента <строка>, если операция выполнена успешно. В случае сбоя возвращается nil.

    Тип операции (изменение или добавление) определяется предшествующим вызовом функции start_list.

    Пример: (add_list "Деталь 3217-06")

    Функция end_list

    Функция 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 открывает процесс заполнения графического элемента. Синтаксис:

    (start_image <код>)

    Аргумент <код> - значение атрибута key графического элемента. Возвращаемое значение - строка со значением аргумента, если операция выполнена успешно. В случае сбоя возвращается nil.

    Функция end_image

    Функция end_image завершает процесс формирования изображения. Синтаксис:

    (end_image)

    Возвращаемое значение - nil.

    Вызову функции end_image должен обязательно предшествовать вызов функции start_image.

    Функция fill_image

    Функция fill_image заполняет прямоугольник внутри графического элемента одним цветом. Синтаксис:

    (fill_image <x1> <y1> <ширина> <высота> <цвет>)

    Аргументы:

  • <x1> <y1> - координаты верхнего левого угла заполняемого прямоугольника;
  • <ширина> <высота> - размеры заполняемого прямоугольника;
  • <цвет> - индекс цвета.
  • Возвращаемое значение - значение аргумента <цвет>.

    Пример: (fill_image 5 6 15 25 1) - заполняет красным (1) цветом прямоугольник с левым верхним углом в точке (5,6) и нижним правым углом в точке (15,25).

    Функция slide_image

    Функция 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 рисует отрезок заданного цвета внутри графического элемента диалогового окна. Синтаксис:

    (vector_image <x1> <y1> <x2> <y2> <цвет>)

    Аргументы:

  • <x1>, <y1> - координаты (в пикселях) начала отрезка;
  • <x2>, <y2> - координаты (в пикселях) конца отрезка;
  • <цвет> - индекс цвета
  • Пример:

    (vector_image 5 11 33 11 2) - рисует отрезок желтого цвета из точки (5,11) в точку (33, 11).

    Функция dimx_tile

    Функция dimx_tile вычисляет горизонтальный размер графического элемента с данным кодом (точнее, размер элемента минус 1). Синтаксис:

    (dimх_tile <код>)

    Аргумент <код> - строка с кодом графического элемента. Возвращаемое значение - целое число с номером крайнего правого пикселя элемента (левый крайний пиксель имеет номер ноль).

    Пример:

    (dimx_tile "igp2") - может вернуть 50 (всего по горизонтали 51 пиксель)

    Функция dimy_tile

    Функция 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.

    Текстовые поля Edit_Box

    Измените описание диалогового окна в файле rog.dcl:

    //Диалоговое окно установки параметров рога
    rog: dialog{label="Установка параметров рога";
      :edit_box{label="Радиус окружности ";key="rad" ;value="80.00"; edit_width=8;}
      :edit_box{label="Диаметр дуги, мм";key="diam";value="400.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);		загружаем в память файл "rog.dcl"
    (progn
      (alert "Файл Rog.dcl не загружен!");			сообщение о неудачной загрузке
      (exit)
      ))
      (if (not (new_dialog "rog" num));
    ;; ;;функция new_dialog проверяет наличие в файле диалога "rog"
      (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)");	действия при нажатии CANCEL
      (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 тогда не нужна.

    Рассмотрим теперь более подробно работу с отдельными элементами диалоговых окон: с кнопками, со списками, с флажками и с радиокнопками.

    Кнопки Button

    Создадим 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_box

    Составьте файл 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) Окно с двумя списками

    Работа с элементами toggle

    Составьте программу построения диалогового окна с колонкой флажков. Сохраните файл как …\Support\Toggle.dcl

    Toggle: dialog { label = "Работа с элементами toggle";
    : column {: boxed_row {
    : 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 = "accept"; label = "Okey "; is_default = true; }
    : button { key = "cancel";label = "Cancel "; is_default = false; 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) Диалоговое окно с флажками

    Переключатели Radio Buttons

    Постройте диалоговое окно с четырьмя переключателями. Из всей группы только один из переключателей может быть выделен. Он должен быть определен при нажатии кнопки ОК.

    Составьте DCL-файл для колонки из четырех переключателей. Внизу окна поместите кнопки OK и Cancel. Сохраните файл как С:\Program Files\AutoCAD 2010\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 = " Okey ";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 Okey 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 = " Okey "; 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.8)

    (рис 6.8) Предварительное построение диалогового окна

    Обратите внимание, что списки отсутствуют, а переключатель 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 layer(tblnext "LAYER" T))
    
      ;;;--- Add the layer name to the list
      (setq layerList(append layerList (list(cdr(assoc 2 layer)))))
    
      ;;;--- Step though the layer table to get all layers
      (while (setq layer(tblnext "LAYER"))
    
        ;;;--- Save each layer name in the list
        (setq layerList(append layerList (list(cdr(assoc 2 layer)))))
      )
    

    Составление списка вручную:

    (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):

    (рис 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-программы, которая запускает сценарий отклика на событие выделения радиокнопки в диалоговом окне.
  • Вернуться к учебному плану