183

Макросы - это просто и полезно. Пост первый, вступительный

Всем привет!

Я долго вынашивал идею писать посты на тему макросов 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. Как его запускать?

Для этого нужно загрузить макрос в автокад.

Это делается во вкладке «Управление» кнопкой «Загрузить приложение», вот тут:

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

Макрос будет работать пока вы не закроете автокад. Выбирать файл нужно тут:

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

Если вас это не устраивает, и вы хотите, чтобы все примочки из этого макроса были отныне с автокадом навсегда, пока форматирование не разлучит их, то добавьте его в список автозагрузки (кнопка «Приложения» под портфельчиком с надписью «Автозагрузка»).


Чтобы автокад не пугал, что макрос неизвестно откуда и что «может ну его?», лучше папку, в которой лежит dvb, добавить в «Доверенные местоположения», вот тут:

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

Теперь можно нажать кнопку «Запустить макрос VBA», выбрать, собственно, что запускать, и нажать «Выполнить»:

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

Как видно, в списке тут прописано, из какого файла запускается макрос, потом после «!» идет имя модуля (подробнее о них – ниже), чаще он один на файл, и название «команды».

В моем случае файл запускает «draw_XY» из Module1 файла UTILS.dvb.

Если кому интересно, оно просто подписывает координаты X и Y в точке, в которую пользователь тычет мышкой.

Так вот, все, что произойдет после нажатия кнопки «Выполнить», решается программным кодом. Ничего сложного там нет, смелее читайте дальше. Я смог, и вы сможете.


5. Как написать свой макрос для AutoCAD?

Для начала нужно создать новый проект. Для этого нужно в командной строке автокада ввести VBAMAN (вы стали свидетелем рождения нового супергероя), либо мышкой нажать на список открыть «Диспетчер VBA» вот тут:

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

В появившемся окне, нужно нажать кнопку «Новый», тогда у вас появится строка Global# (в моем случае Global10):

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

Это и есть наш новый проект. Пока он не сохранен в файл нигде, поэтому так странно называется и путь к нему не указан.

Теперь нажмем кнопку «Редактор Visual Basic», и увидим что у него, проекта, внутри.

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

А внутри – пустота. Есть только объект «ThisDrawing», который создается по умолчанию. Его даже не удалить (и не надо). Можно писать код прямо туда, но лучше делать отдельный модуль под отдельный набор функций (для чего – расскажу позже, когда это станет легче объяснить). Для этого на папку «AutoCAD Objects» нажимаем правой кнопной, выбираем «Insert – Module».

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

Теперь у нас есть отдельный модуль. Самое время разобраться целиком с окошком редактора VBA.

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

1 – Структура проекта. Там всегда будет объект «ThisDrawing» (он тоже своего рода модуль). Еще туда можно надобавлять модулей и форм. Формы – это привычные нам окошки с кнопками, галочками и всем подобным. Окошки – это основная фишка Visual Basic (он поэтому так и называется), с ними оно, конечно, интереснее, но будем разбираться в следующих постах (если хотите вообще).

2 – Свойства выбранного объекта. В нашем случае единственный объект – модуль. Его единственное свойство – его имя. По щучьему велению я переименовал его в EasyMacro1.


Все, что находится правее 1 и 2 – редактор самого программного кода. Считай блокнот, только специальный.


3 – Список объектов внутри модуля. У нас их там нет, поэтому у нас только строка «(General)». Если вы выберите объект «ThisDrawing» (два раза щелкаем левой кнопкой), то там у нас будет еще «AcadDocument».

4 – Список процедур, функций и событий (те же процедуры) этого объекта. У нас оптяь только «(Declarations)». И теперь самое время сказать:


СТОП!

Какие еще процедуры, какие еще функции? Вы бы еще про переменные написали тут!

Вот и приехали. Теперь начинается само программирование.

Для начала чуть-чуть теории, определимся с тем, кто как называется, а потом начнем писать сами, и станет понятно.

VBA – процедурный язык программирования. Все, что он делает – выполняет по порядку, строчка за строчкой, либо процедуру, либо функцию. Обе эти штуки – наборы команд, и единственная разница между ними в том, что процедура просто выполняет какие-то действия и уходит в закат, а функция еще и выдает какой-то результат (число или строку, например).

И внутри всего этого хаоса могут быть переменные – заранее застолбленные «имена», по которым компьютер будет хранить значения, например, числа, строки, опять-таки, или даты, например.

Теперь приступим.

Начнем с самой идеи макроса, обдумаем в голове, что он будет делать и для чего.

Вот есть у меня чертеж. Пусть это будет, условно, три электрических подземных кабеля, начерченных в плане (вид сверху) в миллиметрах.

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

Вот мы видим, что у одной из «веток» длина 52083.65 миллиметра, что, считай, 52 метра 8 сантиметров.

И представим, что кто-то мне сказал, что надо подписать длины этих кусочков. А мне лень. Или их очень много. Или и то, и другое.

Я подумал, попил кофейку, и решил написать макрос, который будет в начало каждой «ветки» вставлять текст, в который будет записывать строчку «L = X.XX м».


Для этого я создам процедуру (а мы помним, что она-то как раз что-то там делает), назову ее writeLengths, чтобы было понятно, что она делает.

Для этого я пишу Sub writeLengths() в редакторе кода, и жму Enter. А редактор сам за меня допишет End Sub.

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

Sub – это так в VBA обозначается процедура. Если бы мы хотели написать функцию, то у нас было бы

Function <имяФункции>() … End Function


Все, что мы напишем промеж строк

Sub writeLengths()

И

End Sub

и будет теми командами, которые будет выполнять процедура до своего ухода в закат.

В тех круглых скобках, при необходимости, пишут входные параметры. Когда появится в них необходимость, вы быстро поймете, как и зачем их использовать. Сегодня не будем.


А что нам надо? Да только свет в оконце. Нам надо, чтобы макрос брал все полилинии в чертеже (пускай пока вообще все полилинии, ок?), узнавал, какой они длины (ДАННЫЕ УДАЛЕНЫ) и вставлял в чертеж текст с ее значением.

Код будет очень простой, а он будет выглядеть вот так:

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

Первые две строки – это объявление переменных. Оно всегда начинается с ключевого слова 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 можно запустить нажав зеленую стрелочку вверху (рядом с кнопками «Пауза» и «Стоп»).

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

А получилось вот что. Длина проставилась в первой точке. Но она проставилась в миллиметрах. И после запятой знаков слишком много.

Это можно исправить, если отформатировать строку со значением текста.


Делается это так:

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)


И результат получим такой:

Макросы - это просто и полезно. Пост первый, вступительный Макрос, Vba, AutoCAD, Microsoft Excel, Урок, Длиннопост

Макрос в определенной мере готов, осталось его сохранить, нажав Ctrl+S, либо “File – Save Global#”.


Конечно, такой макрос дает не очень удобный результат.

Можно сделать так, чтобы текст разворачивался вдоль линии, и вставлялся в ее середину. И в отдельный слой. И другим цветом, например.

Но пост получился уже достаточно объемный из-за долгого вступления, поэтому на этом пока остановимся.


Следующий пост, наверное, напишу тоже на тему автокада, потому что придумать что-то простое, но полезное для Excel пока не удается.


Буду рад видеть в комментариях ваши мнения, просьбы и советы.


Если вы поняли все, но сели писать сами, и у вас ничего не получается - не переживайте. Просто практикуйтесь, ставьте цели и добивайтесь их, а я постараюсь помочь :)

1
Автор поста оценил этот комментарий
Знающий vba и excel сейчас на вес ну не золота но серебра точно. Надо обучение с нуля начинать, с простых примеров и команд, например с задания переменных. Не думаю что тут много людей которым это интересно, но есть и начинающие и профи.
раскрыть ветку (1)
5
Автор поста оценил этот комментарий

Учебников, курсов и формул для обучения с нуля и без меня много, насколько беглое гугление мне показало.
Сидеть и подолгу вникать в теорию - это скучно и убивает все стремление.

Я изучал VBA на том, что мне реально было очень нужно по работе. Я делал глупейшие ошибки, набивал шишки, часами читал документацию и форумы, но в итоге все криво-косо, но работало.
И вот это чувство мини-всемогущества обязательно вместе с практической пользой - лучшая мотивация не бросать и учиться, по-моему.

Я хочу своими постами показать, во-первых, что все это легче, чем кажется.
А во-вторых помочь тем, кто все-таки решил попробовать, но у пока что-то не получается.
Либо просто сделать кому-нибудь макрос, а остальным интересующимся показать, из чего он сделан.

Буду надеяться, такие люди тут найдутся рано или поздно :)

показать ответы
0
Автор поста оценил этот комментарий

Статья конечно хорошая, и в принципе больше половины её я понял. Но после неё всё равно ничего не смогу написать. Потому что хрен знает как какие команды в автокаде реально называются. И тем более не знаю язык VBA, и как правильно на нём писать.

раскрыть ветку (1)
1
Автор поста оценил этот комментарий

Я могу вас уверить, что сможете, если будет надо. И могу пообещать, что я помогу.
А писать "правильно" - ИМХО, необязательно, если вы будете писать для себя. Вашей целью будет только то, чтобы макрос делал то, что вам надо. Можно и побыдлокодить в такой ситуации.

показать ответы
0
Автор поста оценил этот комментарий
Второй месяц пытаюсь освоить азы, ничего не легче оно. Постоянные ошибки, гугление которых выводит на зарубежные форумы, которые без знания английского мне не подсильны(
раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Знание английского очень сильно помогает, не поспорю.
Но я и с ним первое время очень часто спотыкался на частых ошибках. Просто нужно много практики.

Не стесняйтесь о своих трудностях писать в комментариях, буду стараться оперативно помочь.

0
Автор поста оценил этот комментарий

Текст такой. Надерган в основном из инета, некоторые его части я вообще не понимаю, а в блоке Дим комменты стоят методом тыка, чтобы оставшееся работало как надо. У меня есть предположение, что надо еще MailItem зацепить как критерий копирования, поскольку имя вкладки (если все же копировать на разные вкладки) совпадает с фамилией адресанта.


Sub OpenForEditing()

ActiveExplorer.Selection(3).Display

Dim xMailItem As MailItem

'Dim xTable As Word.Table

'Dim xDoc As Word.Document

Dim xExcel As Excel.Application

Dim xWb As Workbook

'Dim xWs As Worksheet

Dim I As Integer

Dim xRow As Integer

Dim Filename As String

'On Error Resume Next

Set xExcel = New Excel.Application

Set xWb = xExcel.Workbooks.Add

xExcel.Visible = True 'False

Set xWs = xWb.Sheets(1)

xRow = 1

For Each xMailItem In Application.ActiveExplorer.Selection

Set xDoc = xMailItem.GetInspector.WordEditor

For I = 1 To xDoc.Tables.Count

Set xTable = xDoc.Tables(I)

xTable.Range.Copy

xWs.Paste

xRow = xRow + xTable.Rows.Count + 2

xWs.Range("A" & CStr(xRow)).Select

Next

Next

xWs.SaveAs Filename:="C:\Users\123.xls"

'ActiveWorkbook.Close ' SaveChanges:=True

MsgBox "Файл успешно сохранен"

ActiveInspector = Outlook.ActiveInspector()

ActiveInspector.Close (0)

xExcel.Quit

' Set wkb = Nothing

' ActiveWorkbook.Close

End Sub

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

В свободное время разберусь и дам вам знать, когда получу результат.

показать ответы
0
Автор поста оценил этот комментарий
Рейтинг в Excel
Собственно сама задача. Ну и если есть интерес. Я могу ещё несколько подобных накинуть, именно по своду и ранжированию различных данных
раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Я подумаю о решении на днях. Если оно окажется простым и шустрым, то я либо сделаю о нем пост и позову оттуда, либо свяжусь с вами через комментарии.

Один вопрос: там же количество строк постоянно изменяется, я правильно понял?

показать ответы
0
Автор поста оценил этот комментарий

А у меня проблема с VBA в Outlook: есть код, который читает три письма (их надо вначале выделить руками), ищет в их теле таблицы и когда находит, копирует их последовательно согласно порядку выделения писем в новый файл эксель. Между таблицами заложено расстояние в 2 строки. Потом файл сохраняет и закрывает.


Проблема в том, что надо копировать эти таблицы не в новый, а в существующий файл, причём либо каждое письмо в свою вкладку согласно фамилии отправителя, либо в одну общую вкладку, но чтобы каждая таблица начиналась с 1й, 50й и 100й строки соответственно. Никак не могу это победить. Подскажете, в какую сторону копать?

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Я, честно говоря, никогда не пользовался Outlook (теперь думаю, что зря), тем более не писал к нему макросов.


По моему опыту, надо сделать переменную, которая будет ссылаться на само приложение "Excel.Application". Затем через нее вызвать Workbooks.Open(путь к файлу), сохранив результат тоже в переменную.  А потом с ее помощью оперировать листами и ячейками в них с помощью Worksheets и Range


Что со стороны Outlook надо будет сделать, сходу не скажу.

Если хотите, я разберусь. Но когда это будет я точно не скажу.

Если ваш действующий код - не секрет фирмы и вы мне его дадите, то это, скорее всего, ускорит процесс решения.

показать ответы
0
Автор поста оценил этот комментарий

А писать "правильно" - ИМХО, необязательно

В смысле необязательно? Если код писать не правильно, он не будет работать.

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Можно написать рабочий, но плохой код.
Он не будет понятен другим программистам со своим плохим оформлением и без комментариев. Его можно будет упростить и оптимизировать, потому что он может подтормаживать и в каких-то редких случаях выкидывать какую-нибудь ошибку.
Я имел в виду это.
Для себя можно писать что угодно и как угодно, лишь бы работало.

И по моему мнению, опыт уже исправит все перечисленное выше, потому что со временем оно начнет мешать.

показать ответы