Использование COM-объекта Word.Application для программной отрисовки таблиц и сборки документа

11 1

История вопроса

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

Часть I. Индекс.

Был выбран путь формирование отчета из макета. Все текстовые поля замечательно проставляются с помощью макропеременных, но появляется загвоздка в формировании индекса. В RTF-отчете он формировался с помощью таблицы. Выбирая разные стили границ, мы можем рисовать цифры. Можно было бы найти какой-нибудь подходящий шрифт, но его надо было бы устанавливать на все компьютеры, с которых возможна печать конвертов.

Посмотрели на готовый результат RTF-отчета с пустым индексом, сохранили его как docx, занесли в систему и обозвали макетом. Лишнее убрали, нужное добавили и сделали генерацию документа. И вот отчет уже почти готов.

Осталось нарисовать такие цифры:

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

  // Верхняя часть цифры
  UpperPartOfNumber = CreateList()
  UpperPartOfNumber.Add(0; ArrayOf(-1; -2; -4))
  UpperPartOfNumber.Add(1; ArrayOf(-4; -8))
  UpperPartOfNumber.Add(2; ArrayOf(-1; -4))
  UpperPartOfNumber.Add(3; ArrayOf(-1; -8))
  UpperPartOfNumber.Add(4; ArrayOf(-2; -4))
  UpperPartOfNumber.Add(5; ArrayOf(-1; -2))
  UpperPartOfNumber.Add(6; ArrayOf(-8))
  UpperPartOfNumber.Add(7; ArrayOf(-1; -8))
  UpperPartOfNumber.Add(8; ArrayOf(-1; -2; -4))
  UpperPartOfNumber.Add(9; ArrayOf(-1; -2; -4))
  
  // Нижняя часть цифры
  LowerPartOfNumber = CreateList()
  LowerPartOfNumber.Add(0; ArrayOf(-2; -3; -4))
  LowerPartOfNumber.Add(1; ArrayOf(-4))
  LowerPartOfNumber.Add(2; ArrayOf(-3; -8))
  LowerPartOfNumber.Add(3; ArrayOf(-1; -8))
  LowerPartOfNumber.Add(4; ArrayOf(-1; -4))
  LowerPartOfNumber.Add(5; ArrayOf(-1; -3; -4))
  LowerPartOfNumber.Add(6; ArrayOf(-1; -2; -3; -4))
  LowerPartOfNumber.Add(7; ArrayOf(-2))
  LowerPartOfNumber.Add(8; ArrayOf(-1; -2; -3; -4))
  LowerPartOfNumber.Add(9; ArrayOf(-1; -8))

Приступаем к заполнению.

VBDocApp = CreateObject('Word.Application')
VBDoc = VBDocApp.Documents.Open(FileName)
PositionOfIndexNumber = 1
while PositionOfIndexNumber <= Length(OrgIndex)
  // Получаем цифру индекса
  IndexNumber = Copy(OrgIndex; PositionOfIndexNumber; 1)
  // Заполняем вернюю часть цифры
  UpperPart = UpperPartOfNumber.FindItem(IndexNumber)
  UpperPartTable = VBDoc.Tables(INDEX_TABLE_NUMBER).Rows(UPPER_PART_POINTER).Cells((PositionOfIndexNumber*2)-1) 
  // x*2-1 нужно, потому что между цифрами так же есть столбцы без отображаемых границ
  CyclePointer = 0    
  CycleCount = ArrayHighBound(UpperPart)
  // Отрисовка верхней части цифры
  while CyclePointer <= CycleCount
   UpperPartTable.Borders.Item(UpperPart[CyclePointer]).LineStyle = INDEX_LINE_STYLE
   UpperPartTable.Borders.Item(UpperPart[CyclePointer]).LineWidth = INDEX_LINE_WIDTH
   CyclePointer = CyclePointer + 1
  endwhile
  // Заполняем нижнюю часть цифры
  LowerPart = LowerPartOfNumber.FindItem(IndexNumber)
  LowerPartTable = VBDoc.Tables(INDEX_TABLE_NUMBER).Rows(LOWER_PART_POINTER).Cells((PositionOfIndexNumber*2)-1)
  CyclePointer = 0    
  CycleCount = ArrayHighBound(LowerPart)
  // Отрисовка нижней части цифры
  while CyclePointer <= CycleCount
    LowerPartTable.Borders.Item(LowerPart[CyclePointer]).LineStyle = INDEX_LINE_STYLE
    LowerPartTable.Borders.Item(LowerPart[CyclePointer]).LineWidth = INDEX_LINE_WIDTH
    CyclePointer = CyclePointer + 1
  endwhile
  PositionOfIndexNumber = PositionOfIndexNumber + 1
endwhile

Часть II. Сборка единого документа.

Пожалуй, более полезная и распространенная, при этом, значительно более короткая часть изысканий в объектной модели Word.Application.

Рисование в таблице, как оказалось, не единственное действие, для которого нам понадобился данный COM-объект. В RTF-отчете, с помощью тегов, можно разбивать документ на страницы. При генерации документов из макета, их придется склеивать средствами, предоставляемыми COM.

  // Берем текущее содержимое документа
  Content = MainDoc.Content
  Content.Collapse(END_COLLAPSE_DIRECTION)
  // Вставляем разделитель страницы
  Content.InsertBreak(PAGE_BREAKE)
  // Переходим на вновь получившуюся страницу
  NewPageContent = Report.GoTo(GOTO_PAGE_ITEM; GOTO_LAST_PAGE_DIRECTION)
  // Вставляем содержимое другого документа в главный
  // DocPath – путь до документа в файловой системе
  NewPageContent.InsertFile(DocPath) 

GOTO_PAGE_ITEM – перечисление wdGoToItem. Определяет тип элемента для перехода. В нашем случае указываем, что перемещаемся по страницам.

GOTO_LAST_PAGE_DIRECTION – перечисление wdGoToDirection. Указывает направление перемещения. Для нас это последний элемент.

Эти перечисления указывают, что надо взять содержимое, находящееся на последней странице. Туда мы и вставляем новую информацию. Если бы эта страница имела бы какой-нибудь контент, он был бы заменен новой информацией. Если бы надо было добавить только подготовленную текстовую информацию, то можно было бы использовать метод InsertAfter для всего содержимого документа, но у нас во втором документе находится несколько более комплексная информация.

Для справки.

Более подробную информацию по данному объекту можно найти в MSDN и справке по VBA.

11
Авторизуйтесь, чтобы оценить материал.
Николай Перфильев

Супер! Уже применил спасибо ) Работает отлично!

Авторизуйтесь, чтобы написать комментарий