Урок 9. Работа с элементами ActiveX

 

1.    Объектная модель AutoCAD

 

Объектная модель AutoCAD основана на концепции COM (Component Object Model). Это спецификация метода создания компонентов, из которых строятся приложения. Система AutoCAD поддерживает технологию ActiveX Automation, которая реализует принципы объектно-ориентированного программирования. В этой технологии модель работающего приложения представляется совокупностью объектов, свойств, методов и событий. Для каждого из этих элементов имеется свой алгоритм реализации в виде операций и данных, которые обеспечивают взаимодействие с пользователем.

Объекты ActiveX в системе AutoCAD рассматриваются как иерархия, содержащая примитивы, символьные таблицы, словари и пр. Однотипные объекты объединяются в семейства (collections).

Высшим элементом в иерархии является объект Application (AcadApplication). Этот объект является родительским для следующих объектов:

·         Preferences (Настройки);

·         VBE (объект интегрированной среды VBA-приложений);

·         Documents (Документы);

·         MenuBar (Строка меню);

·         MenuGroups (Группы меню).

Эти объекты, в свою очередь, являются родительскими для объектов более низких уровней. Семейство Documents включает в себя объекты Document — открытые документы или рисунки. В семейство MenuGroups входят объекты типа MenuGroup (Группа меню или Группа адптации). В семейство MenuBar входят объекты типа PopupMenu (Падающие меню, загруженные в строку меню).

Наиболее важным для практики является объект Document. Он включает в себя, в частности, такие семейства:

·         Blocks (Блоки);

·         ModelSpase (Пространство модели);

·         PaperSpace (Пространство листа);

·         Dictionaries (Словари);

·         DimStyles (Размерные стили);

·         Groups (Группы);

·         Layers (Слои);

·         Layouts (Листы);

·         Linetypes (Типы линий);

·         Plot (Печать);

·         PlotConfigurations (Конфигурации печати);

·         Preferences (Настройки чертежа);

·         RegisteredApplications (Зарегистрированные приложения);

·         SummaryInfo (Свойства чертежа);

·         SelectionSets (Выделенные наборы);

·         TextStyles(Текстовые стили);

·         UCSs (Пользовательские системы координат);

·         Utility (Утилита);

·         Viewports (Видовые экраны);

·         Views (Виды).

 

В семейства Blocks, ModelSpase и PaperSpace входят объекты, которые соответствуют графическим примитивам.

Полностью список объектов показан на рис.9.1. Рисунок взят из справочной службы AutoCAD: ActiveX and VBA Reference — Object Model.

 

 

 

Рис. 9.1. Список объектов AutoCAD

 

Для реализации базовых инструментов объектной технологии в модели предусмотрены компоненты, называемые интерфейсами. В базовом интерфейсе описываются все типичные свойства и методы. Например, базовым интерфейсом всех графических примитивов является IAcadEntity. Он является родительским для интерфейса IAcadLine. С помощью этого интерфейса создаются объекты семейства AcDLine, представителем которого является объект Line.

Каждый объект в технологии ObjectX имеет свои свойства и методы. Свойства можно читать или изменять с помощью соответствующих функций. Функции, соответствующие методам, реализуются в командах с соответствующими параметрами. Элементами объектной модели являются также события. Они возникают в результате действий пользователя (Click) или при изменениях в программе (onLoad). Программа может отслеживать события и реализовать сценарий отклика на события.

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

 

2.    Функции и типы данных

 

Функции, реализующие технологию ActiveX в Visual LISP, имеют префиксы vla-, vlax-, vlr. Доступ к этим функциям можно получить только после выполнения в данном сеансе AutoCAD функции vl-load-com.

Работа с каждым из объектов в технологии ActiveX ведется на уровне указателей. Они носят название VLA-объекты. VLA-объектами являются указатели не только графических примитивов, но и документов, пространства модели и приложений.

Практически обязательной для всех приложений, использующих ActiveX, является следующая структура функций:

 

(defun begin_activex ( / )

(vl-load-com)

(setq acad_app (vlax-get-acad-object))

(setq active_doc (vla-get-activedocument acad_app))

(setq model_space (vla-get-modelspace active_doc))

(setq paper_space (vla-get-paperspace active_doc))

); defun

 

В результате выполнения функции begin_activex будут получены следующие VLA-объекты:

·         acad_app        приложение AutoCAD;

·         active_doc      активный документ;

·         model_space   пространство модели;

·         paper_space    пространство листа.

После получения основных VLA-объектов можно через них обращаться к другим элементам иерархии системы AutoCAD (примитивам, таблицам и пр.) для получения или модификации их свойств и методов. Основным средством получения VLA-объекта для примитива является функция vlax-ename->vla-object. Обратная функция vlax-vla-object->ename.

Кроме VLA-объектов, в ActiveX используют новые типы данных: безопасные массивы и варианты.

 

Безопасные массивы являются массивами однотипных объектов. Они создаются с помощью функций

·         vlax-make-safearray;

·         vlax-safearray-put-element;

·         vlax-safearray-fill.

Для извлечения данных из безопасных массивов с целью использования обычных LISP-функций применяются функции:

vlax-safearray-get-dim;

vlax-safearray-get-l-bound;

vlax-safearray-get-u-bound;

vlax-safearray-get-element;

vlax-safearray-type.

Для преобразования массива в список используют функцию

vlax-safearray->list.

 

Варианты — это структуры, которые могут хранить однотипные данные. Тип данных является типом варианта. Создание варианта выполняется с помощью функции (vlax-make-variant [<данное> [<целое>]]).

В качестве второго аргумента передается целое число, задающее тип варианта. Если оно опущено, то тип варианта определяется по типу первого аргумента. В качестве значения аргумента <целое> используются зарезервированные константы.

 

Константа

Значение

Описание

Vlax-vbEmpty

0

Неинициализированный (значение по умолчанию)

Vlax-vbNull

1

Пустой (без данных)

Vlax-vbInteger

2

Короткое целое число

Vlax-vbLong

3

Длинное целое число

Vlax-vbSingle

4

Вещественное число

Vlax-vbDouble

5

Вещественное число с двойной точностью

Vlax-vbString

8

Строка

Vlax-vbObject

9

Объект

Vlax-vbBoolean

11

Булево значение

Vlax-vbArray

8192

Массив

 

Примеры функций, выполняющих операции с вариантами:

·         vlax-variant-type — получение типа варианта;

·         vlax-variant-value — получение значения варианта;

·         vlax-variant-change-type — изменение типа варианта;

·         vlax-variant-type — оформление трехмерной точки как варианта.

 

 

3.    Использование элементов ActiveX в Visual LISP

 

Элементы ActiveX — это программный интерфейс, который используется в поддерживающих его языках программирования. Элементы ActiveX обеспечивают взаимодействие между объектами, с одной стороны, и пользователем или приложением, с другой стороны. Технология ActiveX позволяет получать информацию об объектах чертежа с помощью функций доступа (get functions) и модифицировать объекты с помощью функций модификации (put functions).

 

Выше было рассмотрено, как извлекать и модифицировать информацию об объектах с помощью функций-интерфейсов на языке AutoLISP. Элементы ActiveX обеспечивают аналогичный способ получения и модификации информации. Однако для этого необходима определенная подготовка.

AutoCAD предоставляет все свои объекты, включая функции доступа и модификации, в распоряжение элементов ActiveX. Вначале в Visual LISP необходимо перед началом сеанса работы загрузить все функции ActiveX с помощью функции

(vl-load-com)Ã

При этом все функции-интерфейсы ActiveX станут доступными. Загрузив интерфейс ActiveX, можно выполнить необходимые действия над созданным ранее отрезком. Но вначале нужно преобразовать имя сущности в объект vla. Этот объект ActiveX практически ничем не отличается от имени сущности, но содержит ряд свойств, которые отсутствуют в его аналоге в языке AutoLISP. Для преобразования используется функция vlax-ename->vla-object. Пример обращения к этой фунции:

(setq vla-line (vlax-ename->vla-object (entlast)))Ã

Среда Visual LISP возвратит следующее выражение:

#<VLA-OBJECT IAcadLine 03612b14>

 

Протокол операций будет выглядеть следующим образом:

 

Command: _line Specify first point: 5,5,0

Specify next point or [Undo]: 15,-5,0

Specify next point or [Undo]: *Cancel*

Command: '_.zoom _e

Command: (vl-load-com)

Command: (setq vla-line (vlax-ename->vla-object (entlast)))

#<VLA-OBJECT IAcadLine 01f1bb4c>

 

Возвращаемое значение переменной есть объект vla. Теперь можно визуально отслеживать значения этой переменной, выделив ее и выбрав команду VIEW — INSPECT. То же самое можно сделать в окне CONSOLE, запустив функцию

(vlax-dump-object vla-line)Ã

Возникающее окно инспектора показано на рис. 9.2.

 

 

Рис. 9.2. Окно инспектора объекта VLA

 

Для получения начальной точки объекта используется функция VLA-GET-STARTPOINT. В рассматриваемом примере отрезок был преобразован в объект vla, свойства которого содержит переменная vla-line. Для получения начальной точки можно ввести следующее выражение:

(setq Starting (vla-get-startpoint vla-line))Ã

В ответ будет выдано сообщение:

#<variant 8197 …>

Чтобы преобразовать координаты начальной точки из типа данных variant к координатному формату, введите следующую строку кода:

(safe-array-value (vlax-variant-value Starting))Ã

Теперь Visual LISP возвратит координаты начальной точки отрезка:

(5.0 5.0 0)

Чтобы изменить значение свойства StartPoint на (0,0,0), напишите выражение:

(vla-put-startpoint vla-line (vlax-3d-point ‘(0 0 0)))Ã

Проверьте отрезок в окне AutoCAD. Для проверки значения свойства StartPoint можно также воспользоваться функцией VLA-GET-STARTPOINT.

(safe-array-value (vlax-variant-value (vla-get-startpoint vla-line)))Ã

Теперь Visual LISP возвратит такое значение:

1.    0.0 0.0

 

Задание 9.1

Получение и модификация свойств объектов

 

2.    На новом чертеже постройте отрезок (5,5,0)-(15,5,0).

3.    В окне CONSOLE редактора AutoLISP введите команду загрузки функции ActiveX (vl-load-com)Ã

4.    Для преобразования имени сущности в объект vla введите:

(setq vla-line (vlax-ename->vla-object (entlast)))Ã

5.    Чтобы просмотреть свойства объекта введите (vlax-dump-object vla-line)

6.    Для получения начальной точки отрезка введите:

(setq Starting (vla-get-startpoint vla-line))Ã

7.    Для преобразования координат начальной точки из типа данных variant к формату отображения координат введите:

(safearray-value (vlax-variant-value Starting))Ã

8.    Чтобы изменить координаты начальной точки отрезка на 0,0,0, введите:

(vla-put-startpoint vla-line (vlax-3d-point ‘(0 0 0)))Ã

9.    Проверьте отрезок — его начальная точка находится в начале координат.

 

4.    Создание объектов с помощью функций ActiveX

 

При работе с интерфейсом ActiveX объекты можно извлекать только в порядке, соответствующем их иерархии. Прежде чем получить объект, необходимо извлечь следующие элементы:

·         Acad-object — представляет программу AutoCAD;

·         ActiveDocumentпредставляет активный чертеж;

·         ModelSpace/PaperSpace — представляет рабочее пространство AutoCAD.

В AutoLISP вначале извлекается тип пространства, затем чертеж и последним — объект AutoCAD. Возьмем простую программу создания отрезка и модифицируем ее с использованием функций ActiveX.

;;; Эта функция создает отрезок с использованием Visual LISP и ActiveX

;;; и возвращает отрезок в виде объекта vla

(defun ax-make-aline ()

(vla-addLine

            (vla-get-ModelSpace;извлечение объекта пространства модели;

            (vla-get-ActiveDocument;извлечение текущего документа;

            (vla-get-Acad-object) ; извлечение объекта AutoCAD;

            ))

            (vlax-3d-point) ‘(5 5 0);_начальная точка

            (vlax-3d-point) ‘(15 5 0);_конечная точка

            )

)

Введите этот код в окне редактора Visual LISP и загрузите его в чертеж. Чтобы посмотреть, как работает функция, введите в окно Console команду

(ax-make-aLine)Ã

Visual LISP возвратит выражение #<VLA-OBJECT IAcadLine 03614934>

 

Ознакомиться с другими функциями ActiveX, предназначенными для создания объектов, можно в справочной системе Visual LISP: HELP — Visual LISP HELP TOPICS — CONTENT — ACTIVEX and VBA REFERENCE — METHODS. Чтобы создать функцию Visual LISP, добавьте к имени метода префикс vla-. Например, для добавления окружности используйте функцию vla-AddCircle.

 

5.    Доступ к документам

 

Работа с примитивами возможна как в активном документе, так и в других открытых чертежах. Некоторые программы выполняют операции не с одним чертежом, а с несколькими. Тогда при выполнении программы активным должен оставаться один и тот же документ. LISP-программа загружается в пространство имен текущего чертежа.

В следующем примере функция opendocs_name возвращает список с именами открытых в данный момент чертежей.

 

(defun opendocs_names ( / _OpenDocs _nlist _d)

(vl-load-com)

; Семейство открытых документов

(setq _OpenDocs (vla-get-documents (vlax-get-acad-object)))

; _nlist - пустой список (nil) как локальная переменная

(vlax-for _d _OpenDocs

  (setq _nlist

    (append _nlist (list (strcat (vla-get-path _d) "\\"  (vla-get-name _d))))

  );setq

);vlax-for

);defun

 

VLA-объект приложения AutoCAD, получаемый с помощью функции vlax-get-acad-object, имеет свойство Documents. Оно возвращает VLA-объект семейства открытых документов.

Для того, чтобы использовать это свойство Documents, нужно вызвать функцию с таким же именем, но прибавить префикс vla-get-. Поэтому с помощью выражения

(setq _OpenDocs (vla-get-documents (vlax-get-acad-object)))

Переменной _OpenDocs присваивается VLA-объект семейства открытых в данном сеансе документов.

Для перебора элементов запускается цикл, выполняемый функцией vlax-for. В этом цикле рабочая переменная  _d используется как обозначение текущего из перебираемых элементов семейства. Строки с именами открытых чертежей накапливаются в списке _nlist. Начальное значение этой  локальной переменной равно нулю. Для добавления к списку нового элемента использована функция append.

Функция vla-get-fullname соответствует свойству FullName. Она возвращает полное имя открытого dwg-файла. Однако если новый чертеж не сохранялся, то вместо имени будет возвращена пустая строка, хотя в заголовке окна стоит имя Drawing1.dwg. Поэтому в примере полное имя файла получается с помощью свойств Path и Name.

 

Когда одновременно открыто несколько чертежей, то с помощью LISP-программы, запущенной в активном чертеже, можно получить доступ ко всем другим документам. Нельзя только активизировать другой документ, так как выполнение программы прервется. Все семейства имеют метод Item, который предоставляет доступ к элементам по номеру или по имени. Нумерация элементов начинается с нуля.

Для примера рассмотрим текст функции, которая для открытого документа с номером N возвращает имя его текущего слоя.

 

(defun anydoc_clayer (N / _OpenDocs)

(vl-load-com)

; Семейство открытых документов

(setq _OpenDocs (vla-get-documents (vlax-get-acad-object)))

; Проверка номера документа и возврат имени текущего слоя

(if (and (= 'INT (type N)) (>= N 0) (< N (vla-get-count _OpenDocs)))

  (vla-get-name (vla-get-ActiveLayer (vla-item _OpenDocs N)))

);if

);defun

 

После получения семейства открытых документов проверяется тип аргумента N (он должен быть целым) и правильность значения. Значение должно быть положительным и меньше количества элементов семейства (свойство семейства count). В случае ошибки программа возвращает ноль, иначе — имя текущего слоя указанного документа.

 

6.    Создание реакторов

 

VLR-объекты или реакторы — особые объекты ActiveX. Они задают отклик системы на события. Выполняемые действия описываются функциями на языке AutoLISP, которые имеют префикс vlr-. Для того, чтобы эти функции были доступны, необходимо выполнить функцию vl-load-com. Она загружает расширение языка LISP.

 

Основные типы реакторов приведены в таблице:

 

Обозначение

Название

Описание

:VLR-AcDb-Reactor

Реактор базы

Отслеживают изменения базы объектов

:VLR-DocManager-Reactor

Реактор документа

Действия с документом

:VLR-Linker-Reactor

Реактор связи

Загрузка и выгрузка ARX-приложений

:VLR-Object-Reactor

Реакторобъекта

Состояние объектов

:VLR-Editor-Reactor

Реактор редактирования

 

 

Реакторы редактирования могут быть заменены на реакторы, приведенные в нижеследующей таблице:

 

Обозначение

Название

:VLR-Command-Reactor

Реакторы команд

:VLR-DeepClone-Reactor

Реакторы клон7ирования

:VLR-DWG-Reactor

DWG-реакторы

:VLR-DXF-Reactor

DXF-реакторы

:VLR-Insert-Reactor

Реакторы команды INSERT

:VLR-Lisp-Reactor

Реакторы LISP-событий

:VLR-Miscellaneous-Reactor

Реакторы других событий редактирования

:VLR-Mouse-Reactor

Реакторы действий мышью

:VLR-Sysvar-Reactor

Реакторы изменения системных переменных

:VLR-Toolbar-Reactor

Реакторы изменения размеров кнопок панелей инструментов

:VLR-Undo-Reactor

Реакторы команды UNDO

:VLR-Wblock-Reactor

Реакторы команды WBLOCK

:VLR-Window-Reactor

Реакторы изменения формы и размеров окна AutoCAD

:VLR-XREF-Reactor

Реакторы вставки и редактирования внешних ссылок

Реакторы создаются по такой схеме. Вначале нужно выполнить функцию вида:

(vlr-<тип>-reactor <данные> <реакции>)

Тип реактора указан в таблицах (acdb, docmanager). У реакторов объекта (тип Object) перед аргументом <данные> присутствует аргумент <владелец>, по которому определяется, какой объект вызвал реактор.

Аргумент <данные> — это LISP-данное любого вида (число, список, строка, nil и пр.). При срабатывании реактора это данное передается функции действия. Она может получить это данное из реактора с помощью специальной функции vlr-data.

Аргумент <реакции> — это список, в котором задаются события, отслеживаемые реактором, и функции, вызываемые в качестве реакции при получении уведомления о совершении события. Список должен иметь такой вид:

(list ‘(<событие1>. <функция1>) ‘(<событие2>.< функция2>)…)

Здесь для каждого из отслеживаемых событий создается точечная пара. Вторым элементом этой пары является соответствующая функция действия. Например, для реактора базы рисунка

(list (:vlr-objectAppended. funA) ‘((:vlr-objectModified. funM))

 

Пример

Запретить удаление примитивов по команде ERASE (Стереть).

 

(defun cmsr ( / )

; Создание реактора команд

(setq commandr (vlr-command-reactor "Реактор команд: "

  (list '(:vlr-commandEnded . cme)))

);setq

);defun cmsr

 

(defun cme (reac cname / _ad)

(princ (strcat "\n" (vlr-data reac) " контролирую "))

(princ cname)

(setq _ad (vla-get-activedocument (vlax-get-acad-object)))

; Проверка имени команды

(if (member (getcname (car cname)) (list "ERASE" "_ERASE"))

  (progn

    (vla-sendcommand _ad "_.undo ")

    (vla-sendcommand _ad "1 ")

  )

);if

);defun cme

 

Программа содержит две функции: cmsr, cme. Первая создает в чертеже реактор команд, вторая является функцией действия, которую запускает реактор. Формирование реактора выполняется с помощью выражения

(setq commandr (vlr-command-reactor "Реактор команд:" (list '(:vlr-commandEnded . cme)))

Здесь <данные> — это строка, а <реакции> — это список. В списке указано только одно событие: :vlr-commandEnded, которое генерируется при окончании команды. В ответ на это событие должна запускаться функция cme.

Функция cme имеет два аргумента: reac и cname. Первый из них — это VLR-объект реактора (т.е. значение глобальной переменной commandr из функции cmsr). Второй — список с именем команды, которую только что выполнила система AutoCAD.

Функция действия с помощью выражения (vlr-data reac) извлекает данные, записанные в реактор (строка “Реактор команд”). Эта строка используется затем функцией princ при печати.

При окончании каждой команды AutoCAD в чертеже происходит событие :vlr-commandEnded. Функция действия cme извлекает имя этой команды из списка cname и проверяет, является ли команда заданной (ERASE). При совпадении выполняется команда UNDO с опцией 1, которая отменяет последнее действие. Поэтому удаленные объекты сразу же восстанавливаются.

Hosted by uCoz