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

* * *

Итак, теперь надо добиться того, чтобы программа могла обрабатывать не один документ, а сразу несколько. Если не идти сложным путем, то сделать это можно двумя способами: либо обрабатывать все нужные документы в одной папке, либо обработать все необходимые открытые документы. Лично я предпочел второй вариант: ведь тогда можно указать все действительно нужные документы, несмотря на их исходное расположение — пусть даже и не в одной папке. Как же это сделать? Замечу, что после обработки готовый документ закрывается и в окне Word активизируется следующий из открытых в редакторе. Значит, чтобы обеспечить повторение макроса, его надо запускать для всех документов. А вот для выполнения макроса сначала необходимо определить в Visual Basic for Applications переход в начало программы. Поищем в Предметном указателе справочной системы VBA по слову «переход» наличие какой-либо команды. Получаем список: «безусловные», «при ошибке», «условные».

Поиск в Предметном указателе по слову «переход»

Выбираем «безусловные» и далее «Инструкция GoTo», так как в нашей программе требуется обязательно перейти к обработке следующего документа.

Справка по «Инструкции GoTo»

Из справочной системы и примера узнаем, что инструкция (т. е. функция, не возвращающая никаких значений) GoTo указывает на переход к той строке, где мы установили метку. Внесем эту метку в начало программы:

Sub Макрос1()
?
? Макрос1 Макрос
? Макрос записан 27.01.00 
?
metka:
Selection.WholeStory
With Selection.Font
.Name = ?Times New Roman?
............

А в ее конец поставим инструкцию GoTo:

... ... ... ... 
ActiveDocument.SaveAs
 FileName:=ActiveDocument.Path + ?? + 
Left(ActiveDocument.Name,
 Len(ActiveDocument.Name) - 4),
 FileFormat:=wdFormatRTF
ActiveWindow.Close
Goto metka
End Sub

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

  • выполнить обработку активного документа, сохранить его и закрыть;
  • посмотреть, остались ли еще открытые документы; при положительном ответе нужно перейти к пункту 1, при отрицательном — завершить работу.

В Предметном указателе займемся поиском информации по слову If («Если»), а выбрав найденную строку «If-инструкция», получаем окно с различными сочетаниями слов If, Then, Else и др.

Выберем нужную справку...

С помощью справочной системы выясним синтаксис команды «Инструкция If...Then...Else»:

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

Какое же условие должно быть у нас? Наверное, подсчет числа открытых документов. Если оно не будет равняться 0, то продолжать работу, а если 0, то остановимся. А чтобы определить это число, проверим, имеется ли в Visual Basic for Applications соответствующая команда. Для этого введем в текст программы слово Documents, поставим точку и просмотрим появившийся список. Так и есть, в списке есть метод Count — скорее всего, это функция подсчета. Выберем ее и посмотрим по ней справку и пример — да, эта команда считает открытые документы. Итак, условие должно выглядеть следующим образом: «If Documents.Count > 0 Then...», а инструкции, или переход к метке, мы уже создали.

Часть команды Else можно опустить и просто написать после If нужные инструкции, к выполнению которых программа не переходит до тех пор, пока остаются открытые документы. Кроме того, стоит, наверное, поместить вызов сообщения, причем желательно со звуковым сигналом. Для этого выберем функцию MsgBox (о ее синтаксисе подробно рассказано в справочной системе): signal = MsgBox («Обработка закончена», vbInformation, «Обработка текстов»). Теперь программа будет выглядеть так:

Sub Макрос1()
?
? Макрос1 Макрос
? Макрос записан 13.01.00
?
metka:
Selection.WholeStory
With Selection.Font
.Name = ?Times New Roman?
.Size = 12
.ColorIndex = wdBlack
End With
With Selection.ParagraphFormat
.LeftIndent = CentimetersToPoints(0)
.RightIndent = CentimetersToPoints(0)
.SpaceBefore = 0
.SpaceAfter = 0
.LineSpacingRule = wdLine
SpaceSingle
.FirstLineIndent = Centimeters
ToPoints(1.27)
End With
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
ActiveDocument.Save
ActiveDocument.SaveAs
 FileName:=ActiveDocument.Path
 + ?? + Left(ActiveDocument.Name,
 Len(ActiveDocument.Name) - 4),
 FileFormat:=wdFormatRTF
ActiveWindow.Close
If Documents.Count > 0 Then GoTo metka
signal = MsgBox(?Обработка закончена?,
 vbInformation, ?Обработка текстов?)
End Sub

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

Чтобы отыскать нужную команду, приходится перебирать список встроенных диалоговых окон Word

В качестве метода вывода окна на экран установим «.Display», — при этом окно выводится на экран без каких-либо последующих действий. И если теперь в этом окне мы выделим файл и нажмем кнопку «Открыть», то хотя он и не откроется, его имя все равно можно будет записать в переменную:

With Dialogs(wdDialogFileOpen)
.Display
imya=.Name
End With

и впоследствии применять по своему усмотрению.

При использовании встроенных диалоговых окон Word требуется оператор With, иначе не будет «работать», казалось бы, эквивалентный фрагмент текста:

Dialogs(wdDialogFileOpen).Display
imya= Dialogs(wdDialogFileOpen).Name

Остановимся на окне Dialogs (wdDialogCopyFile) — копирование файла. Вызвав ссылку Built-in Dialog Box Argument Lists окна Displaying Built-in Word Dialog Boxes, получим список всех аргументов диалоговых окон (т. е. параметров, значения которых можно найти в окнах или задать в них). Нас интересует параметр Directory (папка, куда будет копироваться файл, указанный в параметре FileName при выполнении метода Show или Execute). Поработаем с этим окном, написав в экспериментальном модуле следующий текст:

Sub experience4()
With Dialogs(wdDialogCopyFile)
.Display
papka = .Directory
End With
MsgBox papka
End Sub

Запустив эту программу несколько раз, получаем, что в переменную papka записывается путь и имя папки, но, если в пути или имени были пробелы, то выражение окаймляется кавычками (например, «C:Program FilesMicrosoft OfficeШаблоны»), а если пробелов не было, то кавычки по краям не ставятся. Поэтому в возвращаемой переменной их следует убрать. Это можно выполнить с помощью уже известных нам команд Left, Rigth, Mid и Len: If Right(papka, 1) = Chr$(34) Then papka = Mid(papka, 2, Len(papka) - 2).

Команда Chr$(34) возвращает символ с ASCII-кодом 34, т. е. кавычку. (Каждый символ в среде DOS и Windows имеет свой идентификационный номер, иначе ASCII-код, по которому его можно вызвать на экран. С помощью команды MsgBox Asc(Selection.Text) можно узнать код выделенного символа.)

Кроме того, не мешало бы добиться того, чтобы при запуске программы в окне «Копирование файла» по умолчанию задавался путь на каталог с активным документом — не всегда же требуется сохранять все обрабатываемые документы в отдельной папке! Нет ничего проще: установим перед командой .Display параметр Directory как ActiveDocument.Name.

With Dialogs(wdDialogCopyFile)
.Directory = ActiveDocument.Path
.Display
papka = .Directory
End With
If Right(papka, 1) = Chr$(34)
 Then papka = Mid(papka, 2,
 Len(papka) - 2)

Это и есть текст, необходимый для отображения диалогового окна и получения пути к папке для сохранения обработанных документов. И наконец, сделаем так, чтобы при нажатии в диалоговом окне кнопки «Отмена» работа программы прекращалась. Обратившись к справочной системе, по слову .Display узнаем, что эта команда является функцией, т. е. в зависимости от того, какая кнопка была нажата, возвращает определенное значение. Добавим в программу условие выхода из программы и команду на это.

With Dialogs(wdDialogCopyFile)
.Directory = ActiveDocument.Path
If .Display = 0 Then Exit Sub
papka = .Directory
End With
If Right(papka, 1) = Chr$(34)
 Then papka = Mid(papka, 2,
 Len(papka) - 2)

Окончательный вид нашего макроса:

Sub Макрос1()
?
? Программа для обработки документов
?
With Dialogs(wdDialogCopyFile)
.Directory = ActiveDocument.Path
If .Display = 0 Then Exit Sub
papka = .Directory
End With
If Right(papka, 1) = Chr$(34)
 Then papka = Mid(papka, 2,
 Len(papka) - 2)
metka:
Selection.WholeStory
With Selection.Font
.Name = ?Times New Roman?
.Size = 12
.ColorIndex = wdBlack
End With
With Selection.ParagraphFormat
.LeftIndent = Centimeters
ToPoints(0)
.RightIndent = Centimeters
ToPoints(0)
.SpaceBefore = 0
.SpaceAfter = 0
.LineSpacingRule = wdLine
SpaceSingle
.FirstLineIndent = Centimeters
ToPoints(1.27)
End With
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
ActiveDocument.Save
ActiveDocument.SaveAs FileName
:=papka + Left(ActiveDocument.Name,
 Len(ActiveDocument.Name) - 4),
 FileFormat:=wdFormatRTF
ActiveWindow.Close
If Documents.Count > 0 Then GoTo metka
signal = MsgBox(?Обработка закончена?,
 vbInformation, ?Обработка текстов?)
End Sub
* * *

Показанный здесь подробный разбор написания первой из макрокоманд, надеюсь, поможет начинающим программистам яснее представить себе ход рассуждений и мыслей, необходимый для создания макрокоманд, а приведенные ниже некоторые приемы будут полезны для анализа текста программы и самостоятельного обучения программированию на Visual Basic for Applications.

Перед началом работы, а также для выяснения того, какая команда соответствует выбранному преобразованию текста, целесообразно пользоваться средством записи макросов. Его наличие и выделяет Visual Basic for Applications среди редакторов других языков программирования. Оно позволяет легко разобраться со всеми вопросами, возникающими при создании первой программы, а также «перевести» на язык Visual Basic for Applications какое-либо действие пользователя Word.

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

Справочная система Visual Basic for Applications — основной источник, откуда можно почерпнуть сведения об этом языке. При вызове справки клавишей выдается информация по той команде, на которой стоит курсор. Таким образом можно быстро узнать назначение и особенности любой команды, понять ее синтаксис. К сожалению, многие разделы справки не переведены на русский язык, поэтому англо-русский словарь (или какая-либо система машинного перевода) может стать вашим спутником на время освоения Visual Basic for Applications. Но потрудиться все же стоит: путешествия по справочной системе и чтение ее разделов, причем даже тех, что непосредственно не относятся к решаемой задаче, будут очень полезны, ведь это обогатит ваши знания в области программирования, кстати, не только в Word...

Примеры справочной системы Visual Basic for Applications — работа, сделанная за вас! Копируйте оттуда фрагменты текста в свою программу и модифицируйте их для себя.

Для тестирования и отладки небольшого фрагмента текста или даже одной команды временно вынесите выбранное в отдельный модуль, — так проще работать.

В принципе указанных приемов хватит, чтобы начать изучать Visual Basic for Applications, а вот дальнейшие успехи зависят уже от вас.

Антон Александрович Орлов,

antorlov@inbox.ru,

http://antorlov.chat.ru

Продолжение в следующем номере.