Логотип сайта поддержки пользователей САПРО сайте поддержки пользователей САПР Translate to:

Cоздание утилиты для AutoCAD 2000 с помощью VBA

Автор: Mike Gunderloy
оригинал статьи находиться по здесь
Автор перевода: Виктор Ткаченко
http://www.cad.dp.ua/

С появлением AutoCAD 2000, VBA в AutoCAD достиг совершеннолетия. Новая версия избавилась от многих ограничений начальной реализации VBA в AutoCAD R14, и добавила реальные функциональные возможности непосредственно к AutoCAD.

Чтобы почуствовать, что Вы можете теперь делать с помощью VBA, эта статья, представляет простую утилиту MRU +. Эта утилита, показанная на рисунке 1, сохраняет список последних открытых чертежей, показывает Вам те, которые загружены в настоящее время, и позволяет Вам загружать и выгружать чертежы просто устанавливая галочку рядом с названием чертежа. Хотя это простая утилита, но MRU + демонстрирует многие из новых возможнстей VBA в AutoCAD, и должна помочь научить вас владеть средой VBA в AutoCAD.

Рис. 1 MRU+ - утилита, которая позволяет следить за недавно использоваными файлами AutoCAD
Рис. 1 MRU+ - утилита, которая позволяет следить за недавно использоваными файлами AutoCAD

Добро пожаловать в VBA AutoCAD.

Как уже было сказано, на примере MRU +, вы сможете увидеть многие из новых возможностей AutoCAD 2000. Эта статья не является обзором этого программного продукта, так что я не буду пытаться описать их всех; акцент ставится на предметах, которые важны разработчикам VBA. Однако, это отображает нескольких из основных усовершенствований в этой версии AutoCAD: Этот список показывает только несколько из усовершенствований в этой версии. Для полного описания , см. http://www.cad.dp.ua/stats/rev2000.php.

Два типа проектов в VBA

AutoCAD 2000 позволяет хранить VBA, проекты или как часть документа (указывается как внедренный проект), или как отдельный файл (указывается как Глобальный проект). Каждый загруженный рисунок может иметь единственный внедренный проект, или не иметь внедренного проекта вообще. Кроме того, Вы можете иметь любое число глобальных проектов, загруженных в AutoCAD. Чтобы управлять этими двумя типами проектов, AutoCAD включает Диспетчер VBA (в падающем меню - Tools | Macro | VBA Manager). Этот инструмент, показанный на Рис. 2, позволяет Вам выполнять следующие операции:
Рис. 1. Диалоговое окно  VBA Managerпозволяет Вам манипулировать внедренными и глобальными проектами VBA.
Рис. 2. Диалоговое окно VBA Managerпозволяет Вам манипулировать внедренными и глобальными проектами VBA.

Конечно, глобальный проект более предпочтителен для утилиты, разработанной, чтобы фиксировать информацию относительно множества чертежей. В случае MRU +, глобальный проект это фалй MRUPlus.dvb. Расширение "dvb" используется AutoCAD для глобальных проектов, сохраненных на диске.

Загрузка при запуске

AutoCAD 2000 автоматически не инициализирует VBA всякий раз, когда Вы его запускаете. Скорее, VBA загружается по требованию. Однако, имеются два способа когда Вы можете загружать и запускать код VBA при запуске. Во первых, Вы можете создавать глобальный проект VBA, с названием acad.dvb, и сохранять его в вашем каталоге AutoCAD. Любой проект с этим названием будет автоматически загружен при запуске AutoCAD. Далее, если это содержит макроc ( процедуру Sub ) с названием AcadStartup, эта макрокоманда будет автоматически выполняться, как только файл acad.dvb загружен.

Как вариант, Вы можете расположить команды AutoLisp в файле acad.lsp, который также должен быть в каталоге AutoCAD. Любая функция AutoLisp названая STARTUP в этом файле будет автоматически выполняться, когда файл загружен. Как вы будете видеть в этой статье, Autodesk сделала хорошую работу по созданию связи между старшим языком Lisp и более новым языком VBA, что бы стало возможно для кода Lisp, вызвать код VBA и наоборот.

Для приложения, хорошая мысль, модифицировать файл acad.lsp, чтобы загружать приложение при запуске. Большинство пользователей AutoCAD знакомы с изменением этого файла и с языком Autolisp, так что добавление строки кода, чтобы загрузить ваше приложение должно быть для них просто. Вы можете просто загружать приложение, или можете загружать приложение и запускать макрос из него в то же самое время.

Чтобы загрузить приложение, Вы можете использовать код Autolisp, чтобы вызвать команду AutoCAD vbaload:

(defun S::STARTUP()
   (command "_vbaload" "myproject.dvb")
)

Или, чтобы запустить процесс инициализации в приложении, Вы можете вызывать команду vbarun:

(defun S::STARTUP()
               (command "_-vbarun" "MRUPlus.dvb!basMRUPlus.LoadMRUPlus")
                  )

Аргумент команды vbarun может быть полностью квалифицирован в форме:

FileName!ModuleName.MacroName

Если указанный файл не загружен, он будет сначала загружен, и затем будет выполнен макрос. По умолчанию, команды vbarun или vbaload загружают файлы только из главного каталога AutoCAD. Если ваша утилита сохранена в другом месте, вы будете должны указать полный путь и имя файла в аргументе. В этом случае, Вы нуждаетесь в "escape" из знаков наклонной черты влево, удваивая их. Например, это имело силу бы в файле acad.lsp:

(defun S::STARTUP()
               (command "_vbaload" "c:\\Utilities\\myproject.dvb")
                  ) 

Управление Меню

Как часть своего загрузочного кода, MRU + добавляет себя к меню AutoCAD File, только выше встроенного списка последних использованных файлов. В предыдущих версиях AutoCAD, эта операция была полностью невозможна для кода VBA. Теперь новая ветвь объектной модели AutoCAD делает такие вещи тривиальными.

Рисунок 3 показывает новый объекты AutoCAD, доступные для манипулирования инструментальной панелью и меню. Объект MenuBar контролирует все меню, в настоящее время отображенные в главной строке меню AutoCAD. Вы можете вставилять и удалять меню, вызывая методы InsertInMenuBar и RemoveFromMenuBar объекта PopupMenu.

Рис. 3. Объекты для манипуляции меню и панелями инструментов.
Рис. 3. Объекты для манипуляции меню и панелями инструментов.

Объект PopupMenu представляет стандартное падающее меню, или меню вызываемое по правой кнопке мыши. Объект PopupMenuItem представляет единственный пункт меню.

Система MenuGroups содержит набор объектов MenuGroup. Каждый MenuGroup может содержать меню и панели инструментов. Вы можете загружать группы меню из файла на диске. После того, как вы загрузили группу меню, ее содержание станет доступным, чтобы загрузиться в MenuBar или сокращенные меню.

Система Toolbars содержит объекты Toolbar, каждый из которых представляет панель инструментов. Индивидуальные кнопки панели представлены объектами ToolbarItem.

Утилита MRU + делает самую простую возможную операцию с этими объектами: Она прибавляет пункт меню, который отображает интерфейс пользователя к файловому меню. Это делается одной строкой кода:

Application.MenuBar(0).AddMenuItem 19, "MRU+", _
                    "_-vbarun ShowMRUPlus "

Этот код добавляет новый пункт к 20-й позиции (считая с нуля) системы PopupMenuItems на крайнем левом PopupMenu в установленному по умолчанию MenuBar (другими словами, к меню File). Второй аргумент - текст, который будет отображаться в меню, и третий аргумент - макрос меню AutoCAD, который вызывается, когда этот пункт меню выбран.

Использование макросов меню AutoCAD имеет почти тот же самый синтаксис как команды AutoCAD, но и имеет некоторые различия. Один из них - вызов команды vbarun, используя синтаксис подчеркивания и черты чтобы подавить показ диалогового окна, которое это обычно вызвало бы. Заметьте присутствие пробела после имени макроса VBA, для выполнения. В макросах меню, конечные пробелы интерпретируется как конец фрагмента входа. Без этого, название макрокоманды VBA было бы внесено в командную строку AutoCAD, но не выполненно.

Использование ThisDrawing

Хотя можно иметь несколько одновременно загруженных глобальных проектов VBA, они все используют единственный объект названный ThisDrawing. Этот объект представляет собой активный документ в интерфейсе пользователя AutoCAD, и имеет класс AcadDocument. (В отличие от многих других объектных моделей, в модели AutoCAD имена всех объектов начинаються с префикса "Acad", чтобы гарантировать однозначность в операциях). Если несколько проектов VBA включают обработчики для событий для объекта ThisDrawing, каждый из обработчиков событий вызывается по очереди.

Использование событий ThisDrawing просто. Каждый глобальный проект VBA, который Вы создаете автоматически, содержит пример объекта ThisDrawing который не может быть удален. В приложении MRU + событие ThisDrawing.BeginClose используется, чтобы сообщить главной форме, когда рисунок выгружается из пользовательского интерфейса. Это событие содержит минимум кода, чтобы вызвать метод public формы интерфейса пользователя, чтобы расположить соответствующий ListItem в ListView и не контролировать это.

Таблица ниже содержит списки событий, поддерживаемые ThisDrawing. Как Вы можете видеть, многие из этих событий - новые в AutoCAD. В частности события BeginShortcutMenu, BeginLisp, и Object позволяют осуществлять новые способы взаимодействия с другими языками программирования в AutoCAD.

События объекта AcadDocument
Имя события Новое Исполняется когда:
Activate Да Окно чертежа выбирается
BeginClose Да Пользователь или программа пытается закрыть чертеж
BeginCommand Да Запущена команда
BeginDoubleClick Да Пользователь осуществляет двойной щелчек мышью на любом объекте чертежа
BeginLisp Нет Lisp-выражение посылается на исполнение
BeginPlot Да Начинается операция печати
BeginRightClick Да Пользователей нажимает правую кнопку мыши на любом объекте в черетеже
BeginSave Да Пользователь начинает сохранять чертеж
BeginShortcutMenuCommand Да Пользователь выдает сокращенного меню коммандного режима
BeginShortcutMenuDefault Да Пользователь выдает сокращенное меню по умолчанию
BeginShortcutMenuEdit Да Пользователь выдает сокращенное меню EDIT
BeginShortcutMenuGrip Да Пользователь выдает сокращенное меню GRIP
BeginShortcutMenuOsnap Да Пользователь выдает сокращенное меню OSNAP
Deactivate Да Окно чертежа становиться не активным
EndCommand Нет Завершается выполнение команды
EndLisp Да Завершается вычисление Lisp-выражения
EndPlot Да Завершается операция печати
EndSave Да Завершается операция записи
EndShortcutMenu Да Любое сокращенное меню фактически появляется.
LayoutSwitched Да Пользователь переключатеся на другой layout
LispCancelled Да Выполнение lisp-выражения прервано
ObjectAdded Да Любой объект добавлен к чертежу
ObjectErased Да Любой объект удален из чертежа
ObjectModified Да Любой объект модифицирован
SelectionChanged Да Текущий набор выбора изменен
WindowChanged Да Окно максимизируется или минимизируется
WindowMovedOrResized Да Окно перемещается или изменяется его размер

Зацепление объекта Application

Помимо наличия ThisDrawing, который представляет активный документ, утилита MRU + также должна контролировать события объекта AcadApplication (представляющего непосредственно AutoCAD) чтобы знать, когда новый рисунок был открыт. В отличие от объекта ThisDrawing, однако, глобальные VBA объекты не получают автоматически образец объекта AcadApplication. К счастью, Вы можете использовать в VBA ключевое слово WithEvents, чтобы создать ваш собственный. Последовательность событий, что использует MRU+, чтобы зацепить cобытие EndOpen объекта AcadApplication, который испольняется всякий раз, когда открывается новый рисунок, выделенный в следующих абзацах.

Файл acad.lsp, как Вы уже видели, содержит код вызова процедуры LoadMRUPlus в basMRUPlus. Наряду с другим загрузочным кодом, эта процедура устанавливает образец частного класса называемого CApp и устанавливает одно из его свойств:

' Private class used to grab the application events. 
                  Private mApp As CApp
                    
                  Public Sub LoadMRUPlus()
                    ...
                     ' Get our event hook into the Application. 
                     Set mApp = New CApp
                     Set mApp.App = ThisDrawing.Application

Класс CApp существует исключительно как оболочка для объекта AcadApplication. Встроенный объект ThisDrawing содержит свойство Application что указывает на единственный образец объекта AcadApplication, что позволяет просто коду запуска находить это. Ниже показан код для класса CApp. Важным является здесь - то, что частная переменная типа AcadApplication объявлена WithEvents. Это специальное ключевое слово делает события AcadApplication доступными для кодирования в модули класса. Распечатка кода для утилиты MRU + в конце статьи.

Option Explicit
                    
                  ' This object will let us intercept events
                  ' for the Application object. 
                  Private WithEvents mApp As AcadApplication
                    
                  Private Sub mapp_EndOpen(ByVal FileName As String)
                     ' When a drawing is opened, add it to our MRU list. 
                    frmMRUPlus.AddFile FileName, Now, True
                  End Sub
                    
                  Public Property Set App(NewApp As AcadApplication)
                     ' This property must be set to hook things up. 
                     Set mApp = NewApp
                  End Property
                  FIGURE 5: The CApp class module.

События объекта AcadApplication полностью новые в AutoCAD 2000. В таблице ниже показан список новыех событий предмета AcadApplication.

События объекта AcadApplication
Имя события Когда исполняется
AppActivate AutoCAD получает фокус
AppDeactivate AutoCAD теряет фокус
ARXLoaded приложение ObjectARX загружается
ARXUnloaded приложение ObjectARX выгружается
BeginCommand Команда запущена из командной строки AutoCAD
BeginFileDrop Файл положен на рабочее пространство AutoCAD
BeginLisp Вычисляется Lisp-выражение
BeginModal Модальное диалоговое окно собирается отобразиться.
BeginOpen Чертеж собирается открыться
BeginPlot Чертеж отправляется на печать
BeginQuit Сессия AutoCAD собирается завершиться
BeginSave Документ отправле на сохранение
EndCommand Команда завершает исполнение
EndLisp Lisp-выражение вычислено
EndModal Модальный диалог отклонен.
EndOpen Чертеж открыт
EndPlot Чертеж напечатан
EndSave Чертеж сохранен
LispCancelled Вычисление Lisp-выражения прервано
NewDrawing Создан новый чертеж
SysVarChanged Изменено значение системной переменной
WindowChanged Окно минимизировано или максимизировано
WindowMovedOrResized Окно перемещено или изменен его размер

Заключение

С AutoCAD 2000, VBA в AutoCAD перестал быть являющийся интересным "доказательство концепции", и стал довольно полезным средством. Добавление структурированной объектной модели, способность загружать несколько VBA-проектов и выполнять код при загрузке, а так же интегрирование с Lisp, командной строкой, меню, и панелями инструментов - все это делает возможным писать полезные утилиты, объединенные со стандартным интерфейсом AutoCAD.

Хотя MRU + утилита, показанная здесь только как доказательство концепции, она демонстрирует все схемы, которые вы были бы должны делать с любой утилитой для AutoCAD. Autodesk вложил много усилия в создании VBA как первоклассной средой окружения для AutoCAD.

Код MRU+

                  ' *********************************************************
                  Option Explicit
                    
                  Private Sub AcadDocument_BeginClose()
                     ' Whenever the user closes a drawing, uncheck
                     ' its name on the MRU form. 
                    frmMRUPlus.UnCheck ThisDrawing.FullName
                  End Sub
                    
                  ' *********************************************************
                  ' Code attached to frmMRUPlus.
                  ' *********************************************************
                  Option Explicit
                    
                  ' Arbitrary counter for generating unique
                  ' keys for ListItems. 
                  Private mintDoc As Integer
                    
                  Public Property Let Entries(NewEntries As Integer)
                     ' Set the maximum number of entries to display. 
                    txtEntries.Text = NewEntries
                    sbEntries.Value = NewEntries
                  End Property
                    
                  Public Sub AddFile(strFileName As String, _
                    dblTime As Double, fChecked As Boolean)
                    
                     ' Add a file to the MRU list. Specifies the file name, 
                    ' time, and whether it should be checked. If there are
                    ' more than the specified number of entries on the list, 
                    ' drops the oldest entry. 
                     Dim li As ListItem
                     Dim intI As Integer
                    
                     ' Check for a few common errors and fix 'em up. 
                     If Len(strFileName) = 0 Then
                       Exit Sub
                     End If
                     If Val(txtEntries.Text) < 1 Then
                      txtEntries.Text = 10
                     End If
                    
                     ' Look for an existing item with this name. 
                     For intI = 1 To lvwMRU.ListItems.Count
                       If lvwMRU.ListItems(intI).Text = strFileName Then
                         Set li = lvwMRU.ListItems(intI)
                         Exit For
                       End If
                     Next intI
                    
                     ' If there is no such item, we need to add one. 
                     If li Is Nothing Then
                       ' Check first to see whether we need to drop an item. 
                       If lvwMRU.ListItems.Count >= txtEntries.Text Then
                         Set li = lvwMRU.ListItems(1)
                           ' Find the oldest item to drop. 
                           For intI = 2 To lvwMRU.ListItems.Count
                             If CDate(lvwMRU.ListItems(intI).SubItems(1)) < _
                                CDate(li.SubItems(1)) Then
                               Set li = lvwMRU.ListItems(intI)
                               End If
                             Next intI
                            lvwMRU.ListItems.Remove li.Index
                       End If
                       ' Add the new item with an arbitrary key. 
                       Set li = lvwMRU.ListItems.Add(, "K" & mintDoc, _
                                                     strFileName)
                      li.SubItems(1) = CDate(dblTime)
                      mintDoc = mintDoc + 1
                     End If
                     ' Whether the item was new or existed already, check it
                     ' if it wasn't checked and should be checked. 
                     If Not li.Checked Then
                      li.Checked = fChecked
                     End If
                  End Sub
                    
                  Public Sub UnCheck(strFileName As String)
                     ' Clears the checkmark next to an item. 
                     Dim intI As Integer
                     Dim li As ListItem
                    
                     ' Find the item to clear by comparing names. 
                     For intI = 1 To lvwMRU.ListItems.Count
                       If lvwMRU.ListItems(intI).Text = strFileName Then
                         Set li = lvwMRU.ListItems(intI)
                         Exit For
                       End If
                     Next intI
                    
                     ' And if we found it, uncheck it. 
                     If Not li Is Nothing Then
                      li.Checked = False
                     End If
                  End Sub
                    
                  Private Sub cmdClose_Click()
                     ' This form stays resident, just hide it. 
                    Me.Hide
                  End Sub
                    
                  Private Sub lvwMRU_ItemCheck( _
                     ByVal Item As MSComctlLib.ListItem)
                     ' When the user checks or unchecks an item, load or
                     ' unload the corresponding drawing. 
                     Dim doc As AcadDocument
                    
                     If Not Item Is Nothing Then
                       If Item.Checked Then
                         ' Opening is a method of the Documents collection. 
                        Application.Documents.Open Item.Text
                       Else
                         ' Closing is a method of the document. 
                         For Each doc In Application.Documents
                           If doc.FullName = Item.Text Then
                            doc.Close
                             Exit For
                           End If
                         Next doc
                       End If
                     End If
                  End Sub
                    
                  Private Sub sbEntries_Change()
                     ' Tie together the textbox and the spin button. 
                    txtEntries.Text = sbEntries.Value
                  End Sub
                    
                  Private Sub txtEntries_Change()
                     ' Tie together the textbox and the spin button. 
                    sbEntries.Value = txtEntries.Text
                  End Sub
                    
                  Private Sub UserForm_Terminate()
                     ' Write changes in settings to the registry. 
                     Dim li As ListItem
                     Dim intI As Integer
                    
                    SaveSetting "MRUPlus", "Options", "Entries", _
                                txtEntries.Text
                     For intI = 1 To lvwMRU.ListItems.Count
                       Set li = lvwMRU.ListItems(intI)
                      SaveSetting "MRUPlus", "Files", _
                                  "FileName" & intI, li.Text
                      SaveSetting "MRUPlus", "Files", _
                                   "FileTime" & intI, li.SubItems(1)
                     Next intI
                    
                  End Sub
                    
                  ' *********************************************************
                  ' Code attached to basMRUPlus.
                  ' *********************************************************
                  Option Explicit
                    
                  ' Private class used to grab the application events. 
                  Private mApp As CApp
                    
                  Public Sub LoadMRUPlus()
                     ' Startup code, meant to be called from acad.lsp. 
                     Dim doc As AcadDocument
                     Dim intI As Integer
                     Dim intEntries As Integer
                     Dim strName As String
                    
                     ' Get our event hook into the Application. 
                     Set mApp = New CApp
                     Set mApp.App = ThisDrawing.Application
                    
                     ' Add our menu item, ignoring error if it already exists. 
                     On Error Resume Next
                    
                    Application.MenuBar(0).AddMenuItem 19, "MRU+", _
                      "_-vbarun ShowMRUPlus "
                     On Error GoTo 0
                    
                     ' Load the form. 
                    Load frmMRUPlus
                     ' Load any open drawings. 
                     For Each doc In Application.Documents
                      frmMRUPlus.AddFile doc.FullName, Now, True
                     Next doc
                    
                     ' And load any names we saved in the registry from a
                     ' previous session. 
                     On Error Resume Next
                    
                    intEntries = GetSetting("MRUPlus", "Options", _
                                            "Entries", "10")
                     If Err.Number <> 0 Then
                      intEntries = 10
                     End If
                     On Error GoTo 0
                    frmMRUPlus.Entries = intEntries
                     For intI = 1 To intEntries
                      strName = GetSetting("MRUPlus", "Files", _
                                           "FileName" & intI)
                       If Len(strName) > 0 Then
                        frmMRUPlus.AddFile strName, CDate(GetSetting( _
                          "MRUPlus", "Files", "FileTime" & intI)), False
                       End If
                     Next intI
                  End Sub
                    
                  Public Sub ShowMRUPlus()
                     ' Make the form visible. 
                    frmMRUPlus.show
                  End SubCApp
                    
                  Option Explicit
                    
                  ' This object will let us intercept events
                  ' for the Application object. 
                  Private WithEvents mApp As AcadApplication
                    
                  Private Sub mapp_EndOpen(ByVal FileName As String)
                     ' When a drawing is opened, add it to our MRU list. 
                    frmMRUPlus.AddFile FileName, Now, True
                  End Sub
                    
                  Public Property Set App(NewApp As AcadApplication)
                     ' This property must be set to hook things up. 
                     Set mApp = NewApp
                  End Property
				  



Copyright © Сайт поддержки пользователей САПР by Victor Tkachenko