Макросы - это просто и полезно. Пост первый, вступительный
Всем привет!
Я долго вынашивал идею писать посты на тему макросов VBA в AutoCAD и Office, и решил все-таки попробовать.
Несмотря на то, что Microsoft уже давно заявил, что перестал развивать Visual Basic, VBA все еще пользуется спросом, что нет-нет, да доказывают мне окружающие, в том числе и пикабушники (@genrix4444 и @Alex0STR, привет!).
Я предлагаю вам учиться со мной на примерах из реальных задач.
Пишите мне о своих проблемах, и мы будем их решать. Вы получите нужный макрос и навык, а я - идею для поста.
Начнем мы сегодня с того, что определимся, зачем вообще могут пригодиться макросы на VBA, как их запускать и писать самим, а пример сегодня возьмем из AutoCAD.
Но сначала кое-что важное:
Материалы данного поста созданы непрофессиональным программистом.
Я не претендую на гордое звание преподавателя, коуча или сенсея.
Я буду показывать решения, которые просто будут работать.
Критика и советы горячо приветствуются.
При, по крайней мере, написании поста ни один настоящий программист не пострадал.
А теперь поехали!
1. Что такое VBA? Зачем оно человечеству?
VBA - Visual Basic for Applications - очень простой язык программирования, на котором можно писать макросы. Макросы – это небольшие программы, которые будут делать скучные и нудные вещи за вас. Или хотя бы делать их не такими скучными и нудными.
Самые популярные программы, которые поддерживают макросы VBA сейчас - AutoCAD и MS Office (Excel, Word и т.д.). Если вы работаете в одной их них (или всех), то мои посты могут вам пригодиться.
2. Как понять, что вам нужен макрос?
Если вы заметили, что в вашей работе в офисе или автокаде больше механической, чем умственной работы – нужен макрос. Если какие-то манипуляции вы проводите раз за разом, и они очень похожи – нужен макрос.
Появление макроса сделает вашу работу проще, у вас освободится время, чтобы поспать работать быстрее или играть в танки работать более качественно.
3. Что нужно, чтобы использовать макросы в AutoCAD? А в Excel, Word и т.д.?
Нужно установить эти программы с поддержкой VBA, либо установить отдельно. Если у вас будут сложности, пишите в комментариях, и я сделаю подробную инструкцию в одном из следующих постов.
4. Мне прислали макрос для авткада VBA в формате .dvb. Как его запускать?
Для этого нужно загрузить макрос в автокад.
Это делается во вкладке «Управление» кнопкой «Загрузить приложение», вот тут:
Макрос будет работать пока вы не закроете автокад. Выбирать файл нужно тут:
Если вас это не устраивает, и вы хотите, чтобы все примочки из этого макроса были отныне с автокадом навсегда, пока форматирование не разлучит их, то добавьте его в список автозагрузки (кнопка «Приложения» под портфельчиком с надписью «Автозагрузка»).
Чтобы автокад не пугал, что макрос неизвестно откуда и что «может ну его?», лучше папку, в которой лежит dvb, добавить в «Доверенные местоположения», вот тут:
Теперь можно нажать кнопку «Запустить макрос VBA», выбрать, собственно, что запускать, и нажать «Выполнить»:
Как видно, в списке тут прописано, из какого файла запускается макрос, потом после «!» идет имя модуля (подробнее о них – ниже), чаще он один на файл, и название «команды».
В моем случае файл запускает «draw_XY» из Module1 файла UTILS.dvb.
Если кому интересно, оно просто подписывает координаты X и Y в точке, в которую пользователь тычет мышкой.
Так вот, все, что произойдет после нажатия кнопки «Выполнить», решается программным кодом. Ничего сложного там нет, смелее читайте дальше. Я смог, и вы сможете.
5. Как написать свой макрос для AutoCAD?
Для начала нужно создать новый проект. Для этого нужно в командной строке автокада ввести VBAMAN (вы стали свидетелем рождения нового супергероя), либо мышкой нажать на список открыть «Диспетчер VBA» вот тут:
В появившемся окне, нужно нажать кнопку «Новый», тогда у вас появится строка Global# (в моем случае Global10):
Это и есть наш новый проект. Пока он не сохранен в файл нигде, поэтому так странно называется и путь к нему не указан.
Теперь нажмем кнопку «Редактор Visual Basic», и увидим что у него, проекта, внутри.
А внутри – пустота. Есть только объект «ThisDrawing», который создается по умолчанию. Его даже не удалить (и не надо). Можно писать код прямо туда, но лучше делать отдельный модуль под отдельный набор функций (для чего – расскажу позже, когда это станет легче объяснить). Для этого на папку «AutoCAD Objects» нажимаем правой кнопной, выбираем «Insert – Module».
Теперь у нас есть отдельный модуль. Самое время разобраться целиком с окошком редактора VBA.
1 – Структура проекта. Там всегда будет объект «ThisDrawing» (он тоже своего рода модуль). Еще туда можно надобавлять модулей и форм. Формы – это привычные нам окошки с кнопками, галочками и всем подобным. Окошки – это основная фишка Visual Basic (он поэтому так и называется), с ними оно, конечно, интереснее, но будем разбираться в следующих постах (если хотите вообще).
2 – Свойства выбранного объекта. В нашем случае единственный объект – модуль. Его единственное свойство – его имя. По щучьему велению я переименовал его в EasyMacro1.
Все, что находится правее 1 и 2 – редактор самого программного кода. Считай блокнот, только специальный.
3 – Список объектов внутри модуля. У нас их там нет, поэтому у нас только строка «(General)». Если вы выберите объект «ThisDrawing» (два раза щелкаем левой кнопкой), то там у нас будет еще «AcadDocument».
4 – Список процедур, функций и событий (те же процедуры) этого объекта. У нас оптяь только «(Declarations)». И теперь самое время сказать:
СТОП!
Какие еще процедуры, какие еще функции? Вы бы еще про переменные написали тут!
Вот и приехали. Теперь начинается само программирование.
Для начала чуть-чуть теории, определимся с тем, кто как называется, а потом начнем писать сами, и станет понятно.
VBA – процедурный язык программирования. Все, что он делает – выполняет по порядку, строчка за строчкой, либо процедуру, либо функцию. Обе эти штуки – наборы команд, и единственная разница между ними в том, что процедура просто выполняет какие-то действия и уходит в закат, а функция еще и выдает какой-то результат (число или строку, например).
И внутри всего этого хаоса могут быть переменные – заранее застолбленные «имена», по которым компьютер будет хранить значения, например, числа, строки, опять-таки, или даты, например.
Теперь приступим.
Начнем с самой идеи макроса, обдумаем в голове, что он будет делать и для чего.
Вот есть у меня чертеж. Пусть это будет, условно, три электрических подземных кабеля, начерченных в плане (вид сверху) в миллиметрах.
Вот мы видим, что у одной из «веток» длина 52083.65 миллиметра, что, считай, 52 метра 8 сантиметров.
И представим, что кто-то мне сказал, что надо подписать длины этих кусочков. А мне лень. Или их очень много. Или и то, и другое.
Я подумал, попил кофейку, и решил написать макрос, который будет в начало каждой «ветки» вставлять текст, в который будет записывать строчку «L = X.XX м».
Для этого я создам процедуру (а мы помним, что она-то как раз что-то там делает), назову ее writeLengths, чтобы было понятно, что она делает.
Для этого я пишу Sub writeLengths() в редакторе кода, и жму Enter. А редактор сам за меня допишет End Sub.
Sub – это так в VBA обозначается процедура. Если бы мы хотели написать функцию, то у нас было бы
Function <имяФункции>() … End Function
Все, что мы напишем промеж строк
Sub writeLengths()
И
End Sub
и будет теми командами, которые будет выполнять процедура до своего ухода в закат.
В тех круглых скобках, при необходимости, пишут входные параметры. Когда появится в них необходимость, вы быстро поймете, как и зачем их использовать. Сегодня не будем.
А что нам надо? Да только свет в оконце. Нам надо, чтобы макрос брал все полилинии в чертеже (пускай пока вообще все полилинии, ок?), узнавал, какой они длины (ДАННЫЕ УДАЛЕНЫ) и вставлял в чертеж текст с ее значением.
Код будет очень простой, а он будет выглядеть вот так:
Первые две строки – это объявление переменных. Оно всегда начинается с ключевого слова Dim, потом идет имя переменной, затем ключевое слово As и ее тип.
Имена переменных не должны повторяться, не должны начинаться цифры, не должны содержать пробелов и не должны быть ключевыми словами. Еще хорошо бы, чтобы они были понятны хотя бы вам (а лучше всем, кто может увидеть ваш код).
Типов в VBA бывает не так много, какой когда использовать – отдельная микронаука. Для наших скромных целей давайте пока использовать:
Integer – целое число: 1, 42, -12, 0 и т.д. VBA ограничивает их значениями от -2 147 483 648 до 2 147 483 647. Нам хватит.
Double – дробное число: 3.14, 0.0, -0.124 и т.д. Диапазон значений у них очень большой, даже писать не буду. Вам хватит, можете поверить.
String – строка текста. Пишется всегда, обязательно в кавычках: “СТРОКА”.
Boolean – логическая переменная. Ее значение может быть только либо Труъ True либо False. Одно или другое, просто и понятно.
Теперь еще раз посмотрите на код и на меня. Сразу все не так пошло, правда?
У нас объявлена переменная point, ее тип – Double. Но что это за скобки, почему там пробелы?
Дело в том, что это point – это не одно значение Double, а целый их массив.
Массив – это целый набор значений какого-то конкретного типа, со своим размером.
В нашем случае в нем есть три элемента, первый начинается с нуля. В скобках написано (0 to 2), что значит что в массиве будут элементы от 0 до 2, то есть 0, 1, 2. Чтобы получить конкретное число, нужно написать его номер в массиве, например point(1). Если написать point(4), то произойдет апокалипсис ошибка после запуска макроса. Можете попробовать.
Массив (для примера из трех элементов) можно задать так:
<название массива>(0 to 2) as <тип>
или так
<название массива>(2) as <тип>
А можно так
<название массива>(1 to 3) as <тип>
тогда его элементы будут считаться от 1.
Мы сделали от 0, потому что по умолчанию делается так, и это поможет нам избежать путанницы. Ниже увидите в чём.
Дальше у нас идет цикл For each … Next.
Если знание английского языка позволяет, то можно понять, что там творится просто прочитав.
А творится вот что:
Для
каждого
объекта (это, кстати, тоже переменная, просто мы ее отдельно не объявляли вначале, потому что кроме как внутри цикла она нам больше нигде не нужна)
В
«этого чертежа» (имеется в виду тот, который был отрыт, когда мы запустили макрос)
пространстве модели (вы ведь знаете, что кроме модели еще есть листы в автокаде, да?)
выполняются какие-то действия.
Действия, как вы уже поняли, находятся между строк
For Each object In ThisDrawing.ModelSpace
и
Next
Так как в пространстве модели могут быть разные объекты: полилинии, круги, отрезки, текст, штриховки и т.д., нам нужно как-то определять, какой из них – полилиния. И если это полилиния, тогда уже с ней что-то делать.
Это можно сделать с помощью условного оператора:
If <условие> then … End if
В нашем случае берется object.ObjectName (это такое «внутреннее текстовое название» объектов в автокаде, для полилиний оно всегда будет равно «AcDbPolyline»). Если оно как раз равно «AcDbPolyline», то у нас полилиния.
Еще, кстати, условный оператор может выглядеть так:
If <условие> then
<действия1>
Else
<действия2>
End if
В этом случае действия1 выполнятся, если условие верно (то есть равно true, там как раз Boolean), а если не верно (равно false), то выполнятся действия2.
Теперь разберем, что будет происходить, если макрос нашел полилинию (то есть, условие выполнилось).
Мы хотим записать в массив point координаты X и Y первой точки найденной полилинии, чтобы туда вставлять текст.
object.Coordinate(0) – это как раз они - координаты первой точки объекта object (ага, масло масляное, соус сальса). Вершины полилинии тоже считаются с нуля, да. Про это я и говорил выше, когда объяснял, зачем я сделал массив, элементы которого начинается с нулевого. Так вот, эти координаты (X, Y) представлены тоже в виде массива Double (дробных чисел). И тоже считаются от нуля.
Поэтому мы берем первый элемент массива point – point(0) и приравниваем, присваиваем ему значение первого элемента массива object.Coordinate(0) - object.Coordinate(0)(0).
Еще раз: получить массив с координатами первой вершины мы смогли при помощи записи object.Coordinate(0), а уже потом дописываем опять (0), чтобы получить его первый элемент.
Далее уже второму элементу массива point присвоили значение второго элемента массива object.Coordinate(0) - point(1) = object.Coordinate(0)(1)
point(2) = 0,
потому что мы чертим в 2D и координата Z нас не волнует совсем.
А вот дальше – самое интересное.
С помощью ключевого слова Call мы вызываем метод (тоже, считай, процедура) AddText, который есть у пространства модели «этого чертежа».
То есть, получается
Call ThisDrawing.ModelSpace.AddText(...)
В скобках через запятую мы пишем параметры, с которыми оно вызывается:
значение текста, который надо написать (в нашем случае мы туда отправляем object.Length – длина объекта)
точка, в которую этот текст вставляется (наш массив point)
и высота текста (я выбрал 200 единиц, чтобы его было видно без микроскопа сильного приближения).
Теперь макрос можно запустить и посмотреть, что получилось.
Кстати, из окна редактора VBA можно запустить нажав зеленую стрелочку вверху (рядом с кнопками «Пауза» и «Стоп»).
А получилось вот что. Длина проставилась в первой точке. Но она проставилась в миллиметрах. И после запятой знаков слишком много.
Это можно исправить, если отформатировать строку со значением текста.
Делается это так:
Format(<выражение>, <формат выражения>)
Формат выражения – это тоже строка, но которая описывает, как должно выглядеть значение.
Например, если мы напишем “#”, то получим только целые части чисел. Было 1,23 стало 1.
Если написать “#.#”, то получим один знак после запятой.
Если вместо решетки писать нули, то они как бы занимают место. То есть с форматом “00.00” число 1.2 будет написано как "01.20". Причем если у нас было бы не 1.2, а 101.2, все рано получилось бы "101.2". До запятой знаки не отрезаются. Логично же, это уже совсем другое число получится.
Еще в формат можно дописывать другие символы, они просто пропишутся как есть. Можно, например, написать “L = 0.00 м”, и мы получим из числа 52083.6472… запись «L = 52083.65».
А это как раз то, что нам нужно, только нам нужно еще и в метрах это все. Для этого object.Length надо просто разделить на 1000.
В общем, исправим код вот так:
Call ThisDrawing.ModelSpace.AddText(Format(object.Length / 1000, "L = 0.00 м"), point, 200)
И результат получим такой:
Макрос в определенной мере готов, осталось его сохранить, нажав Ctrl+S, либо “File – Save Global#”.
Конечно, такой макрос дает не очень удобный результат.
Можно сделать так, чтобы текст разворачивался вдоль линии, и вставлялся в ее середину. И в отдельный слой. И другим цветом, например.
Но пост получился уже достаточно объемный из-за долгого вступления, поэтому на этом пока остановимся.
Следующий пост, наверное, напишу тоже на тему автокада, потому что придумать что-то простое, но полезное для Excel пока не удается.
Буду рад видеть в комментариях ваши мнения, просьбы и советы.
Если вы поняли все, но сели писать сами, и у вас ничего не получается - не переживайте. Просто практикуйтесь, ставьте цели и добивайтесь их, а я постараюсь помочь :)