Обмен данными с Microsoft Word в системе автоматизации
В настоящем разделе будут рассмотрены несколько примеров управления объектами Microsoft Word из процедур VBA: открытие и печать документа, слияние документов для почтовых рассылок и заполнение полей в документе Word данными из БД Microsoft Access.
Иерархия объектов VBA приложения Microsoft Word
Так же как и при использовании объектной модели Microsoft Excel, познакомимся сначала с некоторыми объектами объектной модели Microsoft Word.
- Объект Application — ссылается на активное приложение Microsoft Word. Через этот объект можно получить доступ ко всем остальным объектам модели. Объект Application имеет свойства ActiveDocument и ActiveWindow, которые представляют собой активный документ и активное окно соответственно. Можно указать Word.Application в качестве значения аргумента <класс> функций CreateObject() и GetObject() И В операторе Dim <объектнаяПеременная> As New <класс>.
- Объект Document — является глобальным объектом и, так же как и объект Application, может использоваться в коде автоматизации в качестве значения аргумента <класс> функций CreateObject() и GetObject() и в операторе Dim <объектнаяПеременная> As New <класс>. Семейство Documents представляет собой набор всех документов, открытых в Word.
- Объект Selection — представляет собой выделенную область в окне документа Word или точку вставки. Каждый документ может иметь только одну область выделения, и только одна область выделения открытых документов может быть активна в некоторый момент времени. Это означает, что всегда существует только один объект Selection. Объект Selection подчинен объекту Application, a создается при применении метода Select к объекту Document.
- Семейство windows объекта Application представляет собой набор всех окон приложения Word.
- Семейство Bookmarks подчинено объекту Document, и каждый объект этого семейства представляет собой закладку в документе.
- Объект Range представляет собой непрерывную область текста в документе Word. Диапазоны, как и закладки, используются для идентификации текста в документе, однако, в отличие от закладок, диапазоны существуют только во время выполнения процедур VBA. Диапазоны не зависят от области выделения в документе. Можно работать с диапазоном, не затрагивая области выделения. Диапазонов в документе может быть несколько.
Открытие документа Word
Для того чтобы открыть документ Word, можно использовать любой из перечисленных ранее способов создания экземпляров класса объекта автоматизации. Ниже приводятся примеры процедур VBA для открытия документа. В первой используется функция CreateObject (), а во второй — GetObject(). Для проверки кода этих процедур вы можете, так же как и при работе с объектами приложения Excel, использовать окно отладки.
Sub OpenDocument() Dim wda As Word.Application Set wda = CreateObject("Word.Application") With wda .Visible = True .Documents.Open "C:\Doc\Letter.doc" End With 'операции над документом wda.Quit Wda.Nothing End Sub
В данном случае независимо от того, запущен ли уже Word, программа запустит еще один его экземпляр и в нем откроет файл Letter.doc. После того как все операции с документом закончены, нужно закрыть Word, для чего используйте метод Quit. Если при этом документ был изменен, то приложение Word выдаст сообщение, спрашивающее о том, нужно ли сохранить изменения. При этом программа приостанавливает выполнение и ждет указания пользователя. Таких ситуаций следует избегать.
Если все изменения делались программно, то лучше сначала закрыть документ, выполнив команду
wda.ActiveDocuments.Close False
Окно документа будет закрыто, при этом все изменения будут сохранены. Если же нужно, чтобы пользователь мог посмотреть сделанные программой изменения и при необходимости что-то откорректировать, можно не закрывать приложение в программе, а предоставить сделать это пользователю.
В следующей процедуре для открытия документа используется функция Getobject (). То есть сначала делается попытка проверить, не запущен ли уже Word. Если он еще не запущен, будет сгенерирована ошибка (код ошибки: 429). Программа перехватит эту ошибку и использует функцию CreateObject(), чтобы запустить Word. Если Word уже запущен, то новый документ будет открыт в этом же экземпляре приложения. Затем документ выводится на печать, после чего закрывается либо документ, либо приложение в зависимости от значения флага (modeFlag). Значение флага показывает, запускался ли экземпляр Word, или документ был добавлен к другим открытым документам:
Sub OpenPrintDocument() Dim wda As Word.Application Dim modeFlag As Boolean On Error GoTo ErrStartWord modeFlag = True 'устанавливаем флаг операции Set wda = GetObjectf, "Word.Application") With wda .Visible = True .Documents.Open "C:\Doc\Letter.doc" .ActiveDocument.Printout Do While .BackgroundPrintingStatus <> 0 DoEvents "ждем, пока документ напечатается Loop If modeFlag Then .ActiveDocument.Close 'закрываем только документ Else .Quit 'закрываем все приложение End If End With Set wda = Nothing Exit Sub ErrStartWord: If Err.Number = 429 Then ' Word не запущен Set wda = CreateObject("Word.Application") modeFlag = False 'сбрасываем флаг Resume Next 'возвращаемся к оператору, следующему за 'тем, который вызвал ошибку Else 'выдаем диалоговое окно с сообщением и номером ошибки MsgBox Err.Description & " " & Err.Number, vblnformation Exit Sub ' выходим из процедуры End If End Sub
Вывод данных из таблицы Access в документ Word
Такая операция может быть полезна, когда требуется автоматически внести данные в один из типовых документов: служебную записку, письмо, договор и т. д. Не всегда такие документы можно сформировать, используя отчеты Access. Например:
- требуется оформить договор, который, как правило, представляет собой довольно длинный текстовый документ, в который нужно вставить несколько чисел или строк;
- нужно обеспечить возможность ручного редактирования текста документа;
- документ должен быть сохранен в виде текстового файла (отчет Access может быть только напечатан).
В качестве примера рассмотрим документ Word, который находится в файле Contract.doc на компакт-диске. Документ представляет собой текст договора и содержит несколько полей формы, которые должны быть заполнены данными из таблицы Access. (Подробно о полях формы можно пропитать, например, в кн.: Ф. Новиков, А. Яценко. Microsoft Office 2000 в целом. "БХВ—Санкт-Петербург", 1999.) Откройте этот файл, запустив Word. На рис. 15.32 показаны начало документа и поля, которые должны быть заполнены. Кроме того, представлена стандартная панель инструментов Формы (Forms), с помощью которой эти поля были созданы.
Замечание
Чтобы вывести на экран эту панель инструментов, щелкните правой кнопкой мыши в области панелей инструментов и выберите из списка элемент Формы (Forms).
Чтобы вставить такое поле в документ, нужно:
- Установить курсор (точку ввода) в то место, где должно начинаться поле, и нажать кнопку Текстовое поле (Text Form Field). Поле будет вставлено в документ в точке ввода.
- Дважды щелкнуть на этом поле. Откроется диалоговое окно Параметры текстового поля (Text Form Field Options), в котором требуется заполнить, по крайней мере, одно поле: Закладка (Bookmark).
- Ввести имя закладки и нажать кнопку ОК.
Рис. 15.32. Документ Word, содержащий поля для вставки
Рассмотрим программу, которая открывает файл Contract.doc и автоматически заполняет поля договора. Такая программа может быть связана, например, с кнопкой в форме "Заказы клиентов" (Customer Orders) и обрабатывает нажатие данной кнопки. При нажатии на кнопку должен сформироваться договор с тем клиентом, который отображается в текущей записи формы. Для простоты будем считать, что номер договора будет равен номеру текущего заказа (выделенного в подчиненной форме).
Private Sub CreateContract_Click() Dim wda As Word.Application Dim wdd As Word.Document Dim intPrint As Integer On Error GoTo ErrStartWord Set wdd = GetObject("C:\Doc\Contract.doc") Set wda = wdd.Parent wda.Visible = True wdd.Bookmarks("ContractNumber").Select wda.Selection.TypeText Text:=[Подчиненная форма заказов 1].Form![КодЗаказа] wdd.Bookmarks("ContractDate").Select With wda .Selection.TypeText Text:=Date .Selection.GoTo Name:="CustemerName" .Selection.TypeText Text:=[Название] .Selection.GoTo Name:="CustomerAddress" .Selection.TypeText Text:=[Страна] ' заполнение остальных полей intPrint = MsgBox("Печатать договор?", vbYesNo + vbQuestion) If intPrint = vbYes Then wdd.Printout Do While .BackgroundPrintingStatus <> 0 DoEvents Loop End If .ActiveDocument.Close False If .Windows.Count = 0 Then .Quit End If End With Set wdd = Nothing Set wda = Nothing Exit Sub ErrStartWord: MsgBox Err.Description & " " & Err.Number, vblnformation Exit Sub End Sub
В данной программе с помощью функции Getobject() создается объект Document. Если при этом Word не запущен, то одновременно создается скрытый экземпляр объекта Application Word. Если Word уже запущен, то новый документ добавляется к уже открытым документам.
Далее показаны два способа нахождения нужной закладки в документе. В первом случае используется семейство Bookmarks. Вызвав метод Select нужного элемента этого семейства, можно создать объект Selection, а в документе при этом выделяется требуемое поле.
Во втором случае к объекту Selection (вспомните, что он может означать не только выделенную область, но и точку ввода) применяется метод Goto, которому в качестве значения аргумента Name передается имя нужной закладки.
После того как все поля заполнены, договор выводится на печать. Но предварительно пользователь получает сообщение, требующее подтвердить необходимость печати. Документ печатается только если пользователь подтвердит это.
Потом документ закрывается и далее проверяется, открыты ли еще какие-либо документы (используется свойство Count семейства windows). Если других открытых документов нет, то приложение тоже закрывается. В конце процедуры освобождаются обе объектные переменные.
Если в организации отсутствует приложение Access для автоматизации различных деловых процедур, то создавать типовые бланки документов можно более простыми средствами, например, умело используя средства самого редактора Microsoft Word. Однако, когда такое приложение имеется и в базе данных Access хранится большинство нужной информации, было бы просто нерационально вводить вручную в текст документа значения полей. Рассмотренный пример объясняет, как можно этого избежать.
Слияние документов для почтовых рассылок
Следующий пример связан с эффектным решением еще одной типовой задачи — созданием серийных документов. Это могут быть письма с одинаковым содержанием, но адресованные разным лицам, или типовые бланки, которые должны оформляться в большом количестве. Задача сводится к тому, что должны существовать шаблон такого документа и некоторая база данных. Требуется создать необходимое количество экземпляров такого документа, вставив в каждый экземпляр существующие данные. Если источником данных является таблица Access или запрос, задача решается просто — достаточно выделить эту таблицу (запрос) в списке в окне базы данных и выполнить команду меню Сервис, Связи с Office, Слияние с MS Word (Tools, Office Links, Merge it With MS Word). Однако может оказаться, что данные для вставки в бланк или письмо определяются достаточно сложно, например представляют собой набор записей — Recordset. Тогда можно создать все бланки программно.
Сейчас мы создадим приглашение сотрудникам фирмы "Борей" на некоторое мероприятие. Мероприятие торжественное и важное, поэтому мы хотим напечатать приглашение на красивом бланке.
Рис. 15.33. Шаблон документа для слияния с данными из Access
Шаблон документа должен быть приготовлен заранее. Рассмотрим, как это можно сделать.
- Создайте красивый бланк, пользуясь средством Microsoft Clip Gallery или любой другой библиотекой картинок, рамочек и т. д. (Можно использовать шаблон, присутствующий на компакт-диске, — файл Приглашение.dot). Это будет основной документ для слияния.
- Теперь нужно установить связь с источником данных. В программе мы будем использовать в качестве источника данных временную таблицу Access, т. е. таблицу, которая существует только при работе процедуры VBA. Однако для установления связи нужно создать такую таблицу в базе данных. Создайте новую таблицу и определите следующие поля таблицы: "Фамилия", "Имя", "Обращение", "Должность". Назовите ее "СписокПриглашенных".
- Откройте файл Приглашение-dot и выполните команду меню Сервис, Письма и рассылки, Мастер слияния (Tools, Letters and Mailing, Mail Merge Wizard). Будет запущен Мастер слияния, который в новой версии Microsoft Word реализован в виде панели задач, расположенной слева на экране (рис. 15.34)
Рис. 15.34. Панель Мастера слияния
- Далее следуйте указаниям мастера. На первом шаге выберите тип документа — Письма (Letter) и нажмите кнопку Далее (Next), чтобы перейти к следующему шагу.
- На втором шаге выберите переключатель Текущий документ (Use The current document).
- На третьем шаге нужно указать источник данных. Оставьте значение поля Выбор получателей (Select Recipient) по умолчанию — Использование списка (Use an existing List) и нажмите на ссылку Обзор (Browse). Появится стандартное диалоговое окно для выбора файла.
- Найдите в этом окне файл "Борей.MDB" и нажмите кнопку Открыть (Open). Появится диалоговое окно со списком таблиц.
- Выберите в нем таблицу "СписокПриглашенных". Появится диалоговое окно, в котором будет отображено содержимое исходной таблицы (рис. 15.35). Закройте это окно.
Рис. 15.35. Диалоговое окно с содержимым таблицы "СписокПриглашенных"
- Теперь на экране отображается панель инструментов Слияние (Mail Merge). Установите курсор в левый верхний угол документа и нажмите кнопку Добавить поля слияния (Insert Merge Fields). Появляется одноименное диалоговое окно со списком всех полей в источнике данных. Выберите в списке поле "Обращение" и нажмите кнопку Вставить (Insert). Аналогично вставьте остальные поля (см. рис. 15.34). Поля слияния являются одним из видов полей Word и выглядят в основном документе как заключенные в угловые кавычки названия соответствующих полей источника данных.
- Сохраните документ в виде шаблона (файл с расширением dot) и закройте.
Рассмотрим теперь программу, которая будет выполнять слияние документа Word с данными из таблицы Access. В этой программе мы покажем, как объект Document создается из шаблона документа. Предположим, что у нас есть форма, в которой отображаются отобранные записи о тех сотрудниках, которым мы хотим разослать приглашения. На форме есть кнопка, при нажатии на которую должны формироваться и печататься все экземпляры приглашений. Процедура обработки нажатия этой кнопки выглядит следующим образом:
Private Sub MergeDocument_Click() Dim wda As Word.Application Dim rst As Recordset, rstNew As Recordset Dim db As Database Dim tdf As TableDef Dim i As Integer Set db = CurrentDb() ' Создаем новую таблицу Set tdf = db.CreateTableDef("СписокПриглашенных") With tdf ' Создаем поля таблицы и добавляем их в семейство Fields .Fields.Append .CreateField("Фамилия", dbText) .Fields.Append . CreateFieldC'HMH", dbText) .Fields.Append .CreateField("Обращение", dbText) .FieIds.Append .CreateField("Должность", dbText) ' Добавляем таблицу в семейство TableDefs db.TableDefs.Append tdf End With ' копируем записи из формы в созданную таблицу Set rst = Me.RecordsetClone rst.MoveFirst Set rstNew = db.OpenRecordset("СписокПриглашенных") Do While Not rst.EOF rstNew.AddNew For i = 0 To rst.Fields.Count - 1 rstNew.Fields(i) = rst.Fields(i) Next i rstNew.Update rst.MoveNext Loop ' создаем объект Application Word On Error GoTo err_StartWord Set wda = GetObject(, "Word.Application") wda.Visible = True ' открываем документ на основе шаблона - он добавляется в семейство Documents wda.Documents.Add "C: \Doc\nj»iMiaEieHHe.dot" ' выполняем слияние основного документа и данных из источника With wda.ActiveDocument.MailMerge .Destination = wdSendToNewDocument .Execute End With ' печатаем приглашения wda.ActiveDocument.Printout Do While wda.BackgroundPrintingStatus <> 0 DoEvents Loop ' сохраняем получившийся документ wda.ActiveDocument.SaveAs "C:\Doc\MailMergeDoc.doc" ' закрываем окно с новым документом wda.ActiveWindow.Close False ' закрываем, не сохраняя, окно с первоначальным документом wda.Documents (1).Close False ' если нет больше открытых документов, то закрываем Word If wda.Documents.Count = 0 Then wda.Quit End If ' Удаляем временную таблицу db.TableDefs.Delete "СписокПриглашенных" db.Close Set wda = Nothing Set rst = Nothing Set rstNew = Nothing Exit Sub err_StartWord: If Err = 429 Then ' Word не запущен Set wdd = CreateObject("Word.Application") Resume Next Else MsgBox Err.Description & " " & Err.Number, vblnformation Exit Sub End If End Sub
Сначала создается таблица "СписокПриглашенных" с той же структурой, которая была создана вручную. Затем все данные, отображаемые в форме, записываются в эту таблицу. Все операции с данными выполняются с использованием объектов DАО. Объект Application Word создается с помощью функции GetObject() или CreateObject () в зависимости от того, запущен ли уже Word. Для создания нового документа на основе шаблона используется метод Add семейства Documents. При слиянии основного документа с записями в таблице создается новый документ. Для этого устанавливается значение свойства Destination объекта MailMerge равным константе wdSendToNewDocument. Этот документ уже не содержит поля слияния, а является просто текстовым документом, который можно сохранить в виде файла, задав его имя. Перед сохранением в файле документ выводится на печать. После этого нужно аккуратно закрыть сначала новый документ, потом основной документ, к которому присоединен источник данных, и потом, если нужно, сам Word.