InfoCity
InfoCity - виртуальный город компьютерной документации
Реклама на сайте







Размещение сквозной ссылки

 

Макросы: один раз отмерь - семь раз отрежь


Антон Орлов, www.submarine.ru


У программы Microsoft Word есть огромное количество возможностей по работе с текстом, его замене и поиску; имеются средства помещения графики в документ, не уступающие аналогичным в современных издательских системах, возможность оформления документов красивыми шрифтами... Казалось бы, что еще надо, все необходимое уже учтено создателями Word... Однако иногда перед пользователями встают такие задачи, разрешить которые с помощью стандартных средств Word очень трудно, а то и вовсе невозможно. Но для этого в редакторе, как, впрочем, и во всех компонентах пакета Microsoft Office, есть очень мощное средство разрешения подобных проблем: встроенный язык программирования - для создания макросов.

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

Все документы на моем компьютере оформлены приблизительно одинаково - для удобства редактирования, переноса текста из одного документа в другой и т. п. Можно даже сказать, в чем заключаются мои предпочтения: шрифт - Times New Roman, 12 пунктов, выделения - жирным и курсивом, выравнивание по ширине, все отступы абзацев равны нулю, а табуляция - 1 см, формат документа - Rtf. Но вот из Internet я скачал, например, 90 файлов с интересующей меня информацией - скажем, рефератов. И все они были набраны разными людьми в соответствии с предпочтениями каждого: везде разный шрифт, его размеры, отступы абзацев, выравнивание - то влево, то по ширине. В общем, работы по приведению в нормальный вид - куча. Или вот такая ситуация: вы являетесь организатором конференции, на которую все заинтересованные лица прислали свои доклады, и их надо привести в однообразный вид для издания.

Можно, конечно, повозиться с каждым документом: открывать, ставить нужный шрифт, отступы, сохранять в формате Rtf... Если документов два, да пусть даже десять, то еще как-то можно справиться, а если их 100? Вот тут-то и придут на помощь макросы.

Но как написать программу, да-да, настоящую программу на настоящем языке программирования, ничего не зная о нем, кроме того, что он существует? Это действительно было бы очень трудно сделать на С++ или даже Delphi. Но для написания программ на Visual Basic for Applications (VBA) не надо особых знаний - они появятся в процессе работы. Важно лишь уметь думать. Для облегчения восприятия материала статья написана специально так, как будто я тоже первый раз работаю с этим языком программирования. Ведь, согласитесь, разбираться вместе всегда проще.

Итак, начав работу, я открыл пару документов из общей кучи и, включив запись макроса, стал обрабатывать документ. Word скрупулезно переводил мои действия на язык VBA. Сначала я выбрал "Правка" - "Выделить все", потом - "Формат" - "Шрифт", поставил шрифт Times New Roman, 12 пунктов, черный цвет. Затем выбрал "Формат" - "Абзац", обнулил все отступы и поставил одинарный межстрочный интервал. После этого перешел к команде "Правка" - "Заменить" и, указав в графе "Формат" - "Абзац" для заменяемого - выравнивание влево, а для заменяющего - выравнивание по ширине, а также "Везде" в графе "Направление". Провел замену во всем тексте, а потом сохранил документ командой "Файл" - "Сохранить". Затем я выбрал команду "Файл" - "Сохранить в формате Rtf" и сохранил документ и в этом формате, после чего закрыл его и выбрал на панели записи макроса кнопку "Остановить".

В принципе, назначив записанный макрос какой-нибудь кнопке или сочетанию клавиш, я мог бы на этом остановиться и обработать все документы, открыв их в Word и только нажимая на эту кнопку. Макрос бы просто выполнялся для каждого документа. Но нажимать на кнопку сорок-шестьдесят раз и сидеть около компьютера, ждать, пока все выполнится - не очень приятная перспектива. Хотелось бы, чтобы все было сделано автоматически. Да и поучиться писать макросы самому будет совсем не лишним.

Так что открываем редактор VBA (рис. 1).


Рис. 1. Редактор VBA.

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

Развернув содержимое папки Normal (т. е. макросов в шаблоне Normal.dot), выберем модуль NewMacros. Именно в этот модуль попадают все макросы, созданные пользователем. Поскольку записанный нами макрос первый, то он сразу и откроется. Вот его содержимое (рис. 2).


Рис. 2. Наш записанный макрос.

Разберем все его строки более подробно.

Sub Макрос1()

' Макрос записан 13.06.00

Как нетрудно догадаться, это заголовок макроса. Слово Sub означает начало программы. Название программы - в данном случае "Макрос1" - является уникальным именем, по которому эту программу можно запустить из других программ этого модуля.

Знак ' перед строчкой обозначает комментарии - т. е. все, что стоит в той же строке после него, никак не влияет на работу программы. В окне редактора VBA все комментарии отображаются зеленым цветом.

Selection.WholeStory

Скорее всего, это - переведенная на язык VBA команда "Выделить все". В самом деле, ведь первое действие, выполненное в процессе записи - именно выделение всего текста. Подтвердить это нетрудно, просто поставив курсор на слово WholeStory и нажав кнопку вызова справки F1 (рис. 3).


Рис. 3. Вот что показывает справка по слову WholeStory.

Справка VBA устроена очень удобно - при ее вызове из редактора VBA она "смотрит", не стоит ли курсор на одном из слов, являющихся командой VBA, и в этом случае выводится информация, относящаяся к этой команде.

(Структура команд VBA, а также основные понятия объектно-ориентированного программирования подробно рассматриваются в статье "Программирование в среде Microsoft Word", опубликованной в прошлом номере журнала).

With Selection.Font

.Name = "Times New Roman"

.Size = 12

.ColorIndex = wdBlack

End With

Очевидно, это все связано со шрифтом. В самом деле, ведь Font по-английски - шрифт, а Selection - выделение. Посмотрим справку по этим словам. Поставим курсор на слово Selection и нажмем F1. Используя англо-русский словарь, можно узнать, что Selection означает выделенный текст или точку ввода текста. После этого аналогичным образом узнаем про слово Font (рис. 4).


Рис. 4. Справка по слову Font.

Что-то маловато информации. Ну ясно, что шрифт, а как пишется команда, какие у нее могут быть еще параметры? Нажмем-ка на подчеркнутое слово Font в тексте - это выведет информацию об объекте Font (рис. 5).


Рис. 5. Справка об объекте Font.

Ну теперь все ясно. Даже примеры приведены и, кстати, очень похожие на наш макрос. Посмотрим ссылку Properties вверху окна справки - список свойств шрифта, которые можно задать в программе (рис. 6).


Рис. 6. Список свойств объекта Font.

Это такой же список, как и тот, что выпадает в качестве контекстной подсказки, если при наборе текста программы вручную поставить после слова Font точку. Видно, что там есть все свойства шрифта, задаваемые в макросе: и Name, и Size, и ColorIndex. Можно при желании почитать про каждое свойство подробно, но лучше сначала разобраться с командой With, которая встречается и в нашем макросе. Ставим на нее курсор и нажимаем F1 (рис. 7).


Рис. 7. Справка по слову With. Некоторые разделы справки VBA переведены на русский язык.

Прочтя справку, узнаем, что инструкция With позволяет выполнить последовательность инструкций над указанным объектом, не задавая еще раз имя объекта. Т. е. она позволяет сократить объем кода и облегчить ориентировку программиста в нем. Пойдем дальше.

With Selection.ParagraphFormat

.LeftIndent = CentimetersToPoints(0)

.RightIndent = CentimetersToPoints(0)

.SpaceBefore = 0

.SpaceAfter = 0

.LineSpacingRule = wdLineSpaceSingle

.FirstLineIndent = CentimetersToPoints(1.27)

End With

В первой строчке вы видите слово ParagraphFormat. Это команда установки параметров выделенных абзацев: отступов, межстрочного интервала, красной строки. Нетрудно получить эту информацию из справки (рис. 8) или просто догадаться, ведь Paragraph означает абзац.


Рис. 8. Справка по слову ParagraphFormat.

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

Но почему-то код, полученный при записи этого макроса, какой-то большой, и в нем есть много новых команд, которые не были записаны в первый раз... Сравним оба случая. В прошлый раз все абзацы в документе были сделаны по-разному, а на этот раз оформление обоих абзацев было одинаковым. Может, в этом дело? И действительно, поэкспериментировав еще, записав макросы при оформлении различных и одинаковых абзацев, можно прийти к выводу, что в текст написанного макроса попадают те свойства, которые после установки параметров абзацев через диалоговое окно "Формат" "Абзац" оказываются одинаковыми у всех обрабатываемых абзацев! И неважно, были ли эти свойства установлены такими именно сейчас или когда-то ранее.

Selection.Find.ClearFormatting

Selection.Find.ParagraphFormat.

Alignment = wdAlignParagraphLeft

Selection.Find.Replacement.ClearFormatting

Selection.Find.Replacement.ParagraphFormat.Alignment = wdAlignParagraphJustify

With Selection.Find

.Text = ""

.Replacement.Text = ""

.Forward = True

.Wrap = wdFindContinue

.Format = True

.MatchCase = False

.MatchWholeWord = False

.MatchWildcards = False

.MatchSoundsLike = False

.MatchAllWordForms = False

End With

Selection.Find.Execute Replace:=wdReplaceAll

Насколько помнится, при записи макроса мы вызывали функцию замены Word для изменения всего выравнивания абзацев по левому краю на выравнивание по ширине. И вот перед нами эта функция, вызов которой записан на языке VBA. По всей видимости, первая строчка означает очищение параметров форматирования в окне замены - эквивалент нажатию кнопки "Снять форматирование", а следующие три фразы - установка параметров того, что надо искать - выравнивания Left (т. е. по левому краю) и того, на что надо заменять - выравнивания Justify (по ширине). Оператор With нам уже знаком, так что в следующем фрагменте речь пойдет об окне "Найти и заменить" (рис. 9).


Рис. 9. Вызов функции этого окна на языке VBA описан в тексте.

Легко сообразить, что все параметры объекта Selection.Find (т. е. поиска в выделенной части текста или во всем тексте) соответствуют параметрам окна "Найти и заменить". Заметив повторения слов Selection.Find в первых четырех строчках, легко подсчитать, что и их содержимое можно включить в блок оператора With. Проверим-ка это. Чуть ниже последнего записанного нами макроса напишем строчку Sub experience1( ) (имя после Sub может быть любым, важно лишь, чтобы оно не совпадало с какой-либо командой VBA). Нажмем "Ввод" - парой строчек ниже редактор VBA напишет: End Sub. С помощью команд "Копировать" и "Вставить" перенесем из нашей программы в текст нового макроса блок With Selection.Find. А затем переместим все строчки, относящиеся к отражению в макросе работы окна "Найти и заменить", в этот блок, убрав слова Selection.Find.

Попробуем программу в деле. Откроем еще один документ из общего набора и запустим новый макрос на выполнение. Замена произошла так, как необходимо. Значит, ясно - так сокращать текст программы разрешается.

Осталось еще несколько интересных строчек, конкретное значение которых может вызвать вопросы.

.Forward = True

.Wrap = wdFindContinue

.Execute Replace:=wdReplaceAll.

Ну первая - направление поиска, вперед. Но что значит вторая? Напишем для выяснения этого еще макрос с такой же заменой выравнивания влево на выравнивание по ширине, но с разными параметрами направления поиска. Видно, что наличие или отсутствие согласия на продолжение поиска не влияет на записываемый текст. А как же тогда отказаться от запроса на продолжение? Откроем текст макроса и поставим после команды .Wrap еще один знак =. (рис. 10).


Рис. 10. Вот так определяются возможные значения параметра…

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

Осталось разобраться со строчкой .Execute Replace:=wdReplaceAll.

По логике вещей, это должна быть команда запуска поиска, тем более что и слово Execute означает "Запустить". Посмотрим в справке - по слову Execute. Так и есть - .Execute запускает команду поиска и замены на выполнение (рис. 11).


Рис. 11. Справка по команде Execute объекта Find.

ActiveDocument.Save

Вопросов, я думаю, не вызывает - это команда сохранения активного документа.

ActiveDocument.SaveAs FileName:="Доклад1.rtf"

FileFormat:=wdFormatRTF

LockComments:=False

Password:=""

AddToRecentFiles:=True

WritePassword:=""

ReadOnlyRecommended:=False

EmbedTrueTypeFonts:=False

SaveNativePictureFormat:=False

SaveFormsData:=False

SaveAsAOCELetter:= False

А вот здесь уже понадобится редактирование. Это команда "Сохранить как..." - поскольку соответствующая команда Word представляет собой диалоговое окно, то в текст макроса помещаются все возможные параметры. Нам надо, чтобы все обрабатываемые файлы сохранялись под своим именем и в формате, и с расширением Rtf. Попробуем для этого сначала программно получить имя активного документа. Создадим еще один макрос, напишем там ActiveDocument. и поставим точку (рис. 12). Мы видим, что среди возможных продолжений команды есть свойство Name.


Рис. 12. А так можно найти требующееся продолжение команды...

Поместим в экспериментальную процедуру строчку

MsgBox ActiveDocument.Name

и выполним ее. Это позволит нам вызвать окно сообщения со значением функции ActiveDocument.Name. Можно было бы написать Debug.Print ActiveDocument.Name, что отобразило бы значение этой функции в специальном Окне отладки (вызывается из меню редактора VBA "Вид"-"Окно отладки"). Но использовать окно сообщения как-то привычнее (рис. 13).


Рис. 13. Результат работы команды MsgBox ActiveDocument.Name.

Однако нам ведь нужно одно только имя, без расширения! Как же его получить? Проще всего убрать последние четыре символа .doc и воспользоваться справкой. Нажмем F1, в открывшемся окне - кнопку "Разделы", а там - "Предметный указатель" (рис. 14) - в нем все разделы справки классифицированы по смыслу, в то время как в разделе "Поиск" просто составлена база данных по всем словам, входящим в справочную систему VBA.


Рис. 14. Предметный указатель.

Наберем в строке поиска слово "строка". Из списка разделов справочной системы VBA выберем то, что нам надо - строчку "крайние левые символы" (их нам надо вырезать из имени документа). Дальше получаем справку по функции Left. Превосходно - она является именно той функцией, которая нам необходима. Но она требует значение количества символов во всей строке. Как это узнать? Через функцию Len. Нажмем ссылку "См. также" и выберем из списка строчку "Функция Len" (рис. 15).


Рис. 15. Справка по функции Len.

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

imyadoc = Left(ActiveDocument.Name, Len(ActiveDocument.Name) - 4)

Можно проверить. Создадим отдельный модуль с этой командой и запустим его. В окне сообщения - имя документа без расширения (рис. 16).


Рис. 16. Результат работы команды MsgBox Left(ActiveDocument.Name, Len(ActiveDocument.Name) - 4) .

Не мешало бы еще, чтобы новый документ в формате Rtf сохранялся в той же папке, что и исходный. Для этого добавим к параметру FileName информацию о пути к активному документу. Иначе Word будет сохранять документы в той папке, где последний раз был сохранен или открыт какой-нибудь документ с помощью диалоговых окон "Сохранить как..." и "Открыть...".

Итак, команда нашей программы ActiveDocument.SaveAs должна выглядеть так (уберем заодно все лишние параметры).

ActiveDocument.SaveAs FileName:=ActiveDocument.Path + "\" + Left(ActiveDocument.Name, Len(ActiveDocument.Name) - 4), FileFormat:=wdFormatRTF

И еще, последняя строчка.

ActiveWindow.Close

End Sub

Вот и конец программы - закрытие активного окна с документом.

Ну а теперь надо добиться того, чтобы программа могла обрабатывать не один документ, а сразу множество. Наиболее простой путь - обработать все открытые документы, предварительно открыв нужные. Заметим, что готовый документ закрывается после обработки, и в окне Word активизируется следующий документ из открытых. Следовательно, надо, чтобы после окончания работы макроса он был выполнен сначала. Для этого заставим VBA перейти в начало программы. Поищем в справке VBA, в предметном указателе по слову "переход" - есть ли какая команда для этого? (рис. 17) Получаем список - "безусловные", "при ошибке", "условные".


Рис. 17. Поиск в предметном указателе по слову "переход".

Выберем "безусловные" - ведь в нашей программе надо обязательно перейти к обработке следующего документа. Получаем выбор из двух функций. Выберем вторую - название короче и использование ее наверняка проще (рис. 18).


Рис. 18. Справка по инструкции Goto.

Из справки и примера узнаем, что инструкция (функция, которая не возвращает никаких значений) Goto указывает на необходимость перехода к строке, на которой находится установленная нами метка. Поставим метку в начало нашей программы.

...

metka:

Selection.WholeStory

...

а в ее конец - инструкцию Goto:

...

ActiveWindow.Close

Goto metka

...

Теперь наша программа обработает все открытые документы. Но... обработать-то она обработала, однако в конце выдала сообщение об ошибке. Можно, конечно, оставить и так, но программа, заканчивающая свою работу ошибкой, пусть и после выполнения всех необходимых действий, выглядит некрасиво. Поэтому нужно обеспечить остановку выполнения программы после того, как будут обработаны все документы. Алгоритм действий программы должен быть таков:

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

2. Посмотреть, есть ли еще открытые документы;

3. Если есть, то перейти к пункту 1, если нет, то завершить работу.

"Если" - по-английски If. Поищем это слово в предметном указателе справки. Получаем строчку: "Инструкция If", выбрав которую, выводится окно из различных сочетаний слов If, Then, Else и др.

Выберем "Инструкция If...Then...Else" - вроде первое слово понятнее. Получаем справку, из которой узнаем синтаксис команды:

If условие Then [инструкции] [Else инструкции_else]

Какое же условие должно быть у нас? Наверное, подсчет количества открытых документов - если не 0, то продолжать работу, а если 0, то нет. Посмотрим, нет ли в VBA команды для подсчета открытых документов. Напишем в тексте программы Documents, поставим точку и просмотрим выпавший список. Так и есть - в списке имеется метод Count: скорее всего, это функция подсчета. Выберем ее из списка, посмотрим по ней справку и пример. Да, эта команда считает открытые документы. т. е. условие должно выглядеть как If Documents.Count > 0 Then...

Часть команды Else... можно опустить, а просто написать нужные инструкции после команды If... - ведь все равно к их выполнению программа не перейдет до тех пор, пока останутся открытые документы. А поместить там, наверное, стоит вызов сообщения, желательно со звуковым сигналом, чтобы можно было поставить документы на обработку и отойти. Используем функцию MsgBox (о ее синтаксисе подробно написано в справке).

signal = MsgBox("Обработка закончена", vbInformation, "Обработка текстов").

Программа готова. Можно с помощью диалогового окна "Настройка" назначить ей кнопку, пункт меню или сочетание клавиш и запускать ее при необходимости.

Однако попробуем ее улучшить. Сделаем так, чтобы все обработанные документы сохранялись не в своих папках, а в отдельной, задаваемой пользователем, и чтобы пользователь мог выбрать эту папку из стандартного диалогового окна. Посмотрим справку по словам dialog boxes. В переводе ее текст означает, что с помощью команды Dialogs (имя диалога). Show можно вызвать на экран любое встроенное диалоговое окно Word, вроде диалога открытия файла. Попробуем найти окно, которое возвращало бы путь к какой-нибудь директории. Для этого создадим очередной экспериментальный модуль и будем перебирать в нем все возможные имена диалоговых окон (рис. 19).


Рис. 19. Для поиска нужной команды надо перебрать список встроенных диалоговых окон Word.

В качестве метода вывода окна на экран установим .Display - вывод окна на экран без каких-либо последующих действий: если с помощью команды Dialogs(wdDialogFileOpen). Show будет выведено окно открытия файла, то при нажатии кнопки "Открыть" в нем появится выбранный в окне файл, а если окно выводилось командой Dialogs(wdDialogFileOpen).Display, то открытия файла не произойдет, но имя выбранного файла можно будет записать в переменную и впоследствии использовать это имя по своему усмотрению. При использовании встроенных диалоговых окон Word обязательно использование оператора With.

После перебора остановимся на окне Dialogs(wdDialogCopyFile) - копирование файла. Посмотрев ссылку "Built-in dialog box argument lists" справки, получаем список всех возможных аргументов диалоговых окон (т. е. параметров, значения которых можно получить из окон или задать им). Нас интересует параметр Directory. Путем экспериментов получаем, что команда возвращает путь и имя папки, но, если в пути или имени были пробелы, то путь окаймляется кавычками. Поэтому возвращаемую переменную нужно обработать - убрать кавычки. Сделать это можно с помощью уже известных нам команд Left, Rigth, Mid и Len.

If Right(papka, 1) = Chr$(34) Then papka = Mid(papka, 2, Len(papka) - 2)

"Chr$(34)" - это команда, которая возвращает символ с ASCII-кодом 34 - кавычку.

Кроме того, не мешало бы сделать так, чтобы при запуске программы окно "Копирование файла" по умолчанию стояло бы на директории с активным документом - не всегда же нужно сохранять все обрабатываемые документы в отдельной папке! Нет ничего проще - установим параметр Directory как ActiveDocument.Name перед командой .Display и сделаем так, чтобы нажатие кнопки "Отмена" в диалоговом окне приводило бы к выходу из программы. Для этого в справке по слову .Display узнаем, что эта команда является функцией - т. е. возвращает определенное значение, в зависимости от того, какая кнопка была нажата. Добавим в программу условие и команду выхода из программы.

With Dialogs(wdDialogCopyFile)

.Directory = ActiveDocument.Path

.Display

If .Display = 0 Then Exit Sub

papka = .Directory

End With

If Right(papka, 1) = Chr$(34) Then papka = Mid(papka, 2, Len(papka) - 2)

Теперь при нажатии кнопки "Отмена" в диалоговом окне выбора папки произойдет выход из программы.

Все - программа готова.


Реклама на InfoCity

Яндекс цитирования



Финансы: форекс для тебя








1999-2009 © InfoCity.kiev.ua