четверг, 18 октября 2012 г.

Шаблоны в MS Office 2010.

Да..случилось страшное. Я юзаю винду. Кроме всего прочего встала такая задача.

Задача:  создать шаблон документа, создать макрос, который будет формировать печатную форму (в формате doc) из исходного, полученного из шаблона документа.

Теория: пользовалась следующими ресурсами
http://msdn.microsoft.com/ru-ru/library/ff433638.aspx#CommunityContent - об управлении контентом
http://msdn.microsoft.com/ru-ru/library/bb386290.aspx#Y2300 - создание шаблонов с помощью
элементов управления контентом
http://www.codenet.ru/progr/vbasic/bit/ - справочные статьи по VBA
http://www.firststeps.ru/vba/excel/vbaexcel1.html
Решение:

' Вызов xls-файла для заполнения элементов списка
Set exsheet = CreateObject("excel.application")
exsheet.Visible = False
exsheet.WorkBooks.Open ("D:\podrazd.xlsx")


Коллекции в VBA

Коллекции (они же семейства и множества) – это объекты, которые позволяют хранить произвольное количество элементов любого типа. Элементы в коллекции идентифицируются уникальным ключом, которым может быть не только номер элемента в коллекции, но и значение строкового или другого типа. При программировании на VBA различные коллекции используются очень часто. Например, к коллекции Workbooks нужно обращаться для получения ссылки на объект Workbook нужной рабочей книги, к коллекции Worksheets – для получения ссылки на объект Worksheet нужного рабочего листа и т. д.
В VBA коллекции реализованы во встроенном классе Collection. Создание объекта Collection ничем не отличается от создания объекта другого типа:
Dim col As New Collection
или
Dim col As Collection
Set col = New Collection

Добавление элементов

Для добавления элементов в коллекции реализован метод Add, имеющий следующий формат:
Ссылка. Add Элемент [, Ключ][, Добавить_перед][, Добавить_после]
Единственным обязательным параметром метода Add является значение добавляемого элемента. Элемент может быть константой или переменной любого типа, кроме типа, определенного пользователем. При добавлении элемента можно указать ключ, который будет однозначно идентифицировать элемент в коллекции. Ключ – это любое значение типа Variant.
По умолчанию новые элементы добавляются в конец коллекции. Для изменения порядка добавления элементов используются параметры Добавить_перед и Добавить_после, с помощью которых указывается номер или ключ того элемента, перед которым или после которого нужно вставить новый элемент. Нумерация элементов в коллекции начинается с единицы.
Ниже приведены примеры инструкций, добавляющих новые элементы в коллекцию:
col.Add «Value1», «Key1»
col.Add «Value2», «Key2»
col.Add «Value0»,"Key1"

Количество элементов в коллекции

Для определения количества элементов в коллекции используется свойство только для чтения Count. При его получении возвращается значение типа Long. Пример получения количества элементов коллекции приведен ниже:
lngCount = col.Count

Удаление элементов из коллекции

Для удаления элементов из коллекции используется метод Remove:
Ссылка. Remove Номер
Единственным параметром метода Remove является номер элемента в коллекции или его ключ. Например, для удаления значения «Value2», добавленного в коллекцию при рассмотрении метода Add, можно использовать инструкцию
col.Remove 3
или
col.Remove «Кеу2»

Доступ к элементам коллекций

Для получения значений элементов коллекции используется метод Item, который возвращает значение соответствующего элементу типа:
Ссылка. Item (Номер)
Единственным параметром метода I tern является Номер – это ключ элемента или его порядковый номер в коллекции. Например, для получения значения элемента с ключом «Keyl» (или номером 2) можно использовать следующие инструкции:
val = col.Item(«Key1»)
val = col.Item(2)
Следует отметить, что Item является для объекта Collection методом по умолчанию, поэтому значения элемента с ключом «Key 1» можно получать и таким образом:
val = col(«Key1»)
val = col(2)
взято тут

InlineShape

Перебор графических объектов в Microsoft Word средствами VBA

Графические объекты представляются в VBA с помощью двух классов: Shape и InlineShape.
Примечание. Есть еще класс объектов Frame, представляющих рамки. Рамки широко использовались в версиях, предшествовавших Microsoft Word 97, где еще не было надписей, а в последующих версиях их рекомендуется использовать вместо надписей для текста и объектов InlineShape, содержащих примечания, сноски или некоторые поля. Рамка выглядят почти также, как надпись, и выполняет похожие функции, но является элементом стилевого форматирования, а не графическим объектом. Текст рамки содержится в начале абзаца, к которому относится надпись. Создать рамку в современных версиях Microsoft Word можно только преобразованием из надписи. После этого ее можно скопировать в любое место документа, которое может быть оформлено стилем.
Для перебора объектов Shape и InlineShape можно использовать следующие содержащие их коллекции:


Объект
Коллекция
Shape
Shapes
ShapeRange
InlineShape
InlineShapes


Доступ к этим коллекциям можно получить с помощью свойств других объектов-контейнеров:


Объект
Коллекция
Объект-контейнер
Свойство объекта-контейнера
Shape
Shapes
Document
Shapes

HeaderFooter
ShapeRange
Range
ShapeRange

Selection
InlineShape
InlineShapes
Document
InlineShapes

Range
Selection


Применение свойства Shapes

Объекты Shape могут находиться в основном тексте и в колонтитулах документа.
Когда свойство Shapes применяется к объекту Document, оно возвращает все объекты Shapes, расположенные  в основном тексте документа. Объекты Shapes, содержащиеся в колонтитулах, пропускаются.
Когда свойство Shapes применяется к любому из объектов HeaderFooter, оно возвращает все объекты, находящиеся во всех колонтитулах документа. Описание для примера, приведенного в справке VBA, ошибочно.

The Shapes property, when applied to a document, returns all the Shapes objects in the main story of the document, excluding the headers and footers. When applied to a HeaderFooter object, the Shapes property returns all the Shapes objects found in all the headers and footers in the document
Example
This example displays a count of all the shapes in the primary all header and footer of the first section of the active document.
Visual Basic for Applications
MsgBox ActiveDocument.Sections(1). _
    Headers(wdHeaderFooterPrimary).Shapes.Count
В приведенном примере выводится количество объектов Shape, содержащихся во всех колонтитулах активного документа, а не только в основных колонтитулах первого раздела.
К моему удивлению, обнаружилось (в Microsoft Word 2003, в 2007 не проверял), что после обращения к свойству Shapes свойство Saved соответствующего документа принимает значение False. Это означает, что при закрытии документа последует запрос о его сохранении.

Применение свойства ShapeRange

к объекту Range

Returns a ShapeRange collection that represents all the Shape objects in the specified range
Когда свойство ShapeRange применяется к объекту Range, оно возвращает все объекты Shape, относящиеся к диапазону, представленному этим объектом Range.
К сожалению, в версии Microsoft Word 2003 при обращении к свойству ShapeRange, когда в диапазоне <range evaluation> объектов Shape нет, может появиться сообщение об ошибке "Requested object is not available".
Из-за этого использовать свойство ShapeRange в версии Microsoft Word 2003 не получается.

к объекту Selection

Returns a ShapeRange collection that represents all the Shape objects in the selection
Когда свойство ShapeRange применяется к объекту Selection, оно возвращает все выделенные объекты Shape, а не те объекты, которые относятся к выделенному диапазону, как можно было предположить по аналогии с применением этого свойства к объекту Range. Догадаться об этом из справки VBA невозможно.
К сожалению, в версии Microsoft Word 2003 цикл For Each по коллекции Selection.ShapeRange, когда нет выделенных объектов, приводит к ошибке "Out of memory". Прежде чем его применять, проверьте значение Selection.ShapeRange.Count.

Применение свойства InlineShapes

к объекту Selection

Returns an InlineShapes collection that represents all the InlineShape objects in a selection
Когда свойство InlineShapes применяется к объекту Selection, оно возвращает коллекцию InlineShapes, представляющую все объекты InlineShape, относящиеся к выделенному диапазону, представленному этим объектом Selection.

к объекту Range

Returns an InlineShapes collection that represents all the InlineShape objects in a range.
Когда свойство InlineShapes применяется к объекту Range, оно возвращает коллекцию InlineShapes, представляющую все объекты InlineShape, относящиеся к диапазону, представленному этим объектом Range.

к объекту Document

Returns an InlineShapes collection that represents all the InlineShape objects in a document.
Когда свойство InlineShapes применяется к объекту Document, оно возвращает коллекцию InlineShapes, представляющую все объекты InlineShape, находящиеся в основном тексте документа, представленного этим объектом Document.

Перебор объектов InlineShapes

Для перебора всех объектов InlineShapes удобнее всего пользоваться свойством InlineShapes объекта Range. Это обеспечивает доступ ко всем частям документа, где могут находиться объекты InlineShapes, и при этом на экране не происходит никаких нежелательных изменений.
Объекты InlineShapes могут находиться в любой цепочке (story) документа (в основном тексте, надписях, колонтитулах, примечаниях и сносках), а также в надписях, содержащихся в объектах Shapes, расположенных в колонтитулах.
Для перебора цепочек удобнее всего использовать двойной цикл, который я впервые увидел в программе Replace text on a batch of files на странице http://www.gmayor.com/batch_replace.htm сайта Graham Mayor.
Чтобы продемонстрировать, как работает этот двойной цикл, приведем пример макроса, вычисляющего количество цепочек в документе.

Sub Example1()
'Пример: перебор цепочек в документе
'Вычисление количества цепочек

  Dim intStoryCount 'Счетчик цепочек
  Dim rngStory As Range 'range для цепочки в цикле
 
  intStoryCount = 0
   
  'Цикл по каждому типу цепочек активного документа
  For Each rngStory In ActiveDocument.StoryRanges
    'цикл по всем цепочкам одинакового типа
    Do 'в диапазоне цепочки rngStory на каждой итерации
       
      intStoryCount = intStoryCount + 1
     
      'переход к следующей цепочке rngStory того же типа
      Set rngStory = rngStory.NextStoryRange
    Loop Until rngStory Is Nothing
  Next rngStory
  MsgBox "Всего цепочек: " & intStoryCount, vbInformation _
          , "Перебор всех цепочек"
End Sub

Чтобы пересчитать все объекты InlineSpape в каждой цепочке, т. е. в диапазоне, представленном переменной rngStory, можно выполнить перебор по всем элементам коллекции rngStory.InlineSpapes:
Для этого в теле цикла заменим инструкцию счета цепочек циклом по коллекции InlineSpapes, в котором считается количество объектов InlineSpape:

Sub Example2()
'Пример: перебор объектов InlineShape в цепочках документа
'Вычисляется число объектов InlineShape в цепочках документа
'Объекты InlineShape в надписях, расположенных в колонтитулах,
'не учитываются, поскольку не содержатся в цепочках

  Dim intInlShpCount As Integer 'Счетчик InlineStory
  Dim rngStory As Range 'range для текущей цепочки в цикле
  Dim inlShape As InlineShape 'текущий объект InlineShape в цикле

  intInlShpCount = 0
   
  'Цикл по каждому типу цепочек активного документа
  For Each rngStory In ActiveDocument.StoryRanges
    'цикл по всем цепочкам одинакового типа
    Do
      'в диапазоне цепочки rngStory на каждой итерации
        For Each inlShape In rngStory.InlineShapes
          intInlShpCount = intInlShpCount + 1
        Next inlShape
     
      'переход к следующей цепочке rngStory того же типа
      Set rngStory = rngStory.NextStoryRange
    Loop Until rngStory Is Nothing
  Next rngStory
  MsgBox "Всего в цепочках объектов InlineShape: " & intInlShpCount, vbInformation _
          , "Перебор объектов InlineShape во всех цепочках"
End Sub

Обратите внимание, что объекты InlineShape, расположенные в тексте, находящемся в объектах Shape (в надписях и в автофигурах, к которым добавлены надписи), учитываются только в основном тексте документа. В колонтитулах объекты InlineShape внутри надписей не учитываются, поскольку надписи в колонтитулах не входят в число цепочек (в отличие от надписей, расположенных в основном тексте документа).
Это упущение мы ликвидируем  при обработке объектов Shape.

Перебор объектов Shapes

Объекты Shape могут находиться только в основном тексте документа и в колонтитулах. Поэтому можно обойтись без применения свойства ShapeRange, которое некорректно работает в версии Word 2003.
Начнем с макроса, в котором перебираются невложенные объекты Shape, т. е. объекты, не лежащие на полотне и не входящие в состав группы.
Сначала осуществляется перебор по объектам Shape, находящимся в основном тексте документа, а затем по всем колонтитулам. Как уже упоминалось, чтобы получить коллекцию Shapes, содержащую объекты Shape во всех колонтитулах, достаточно применить свойство Shapes к любому из объектов HeaderFooter. Здесь использован объект, представляющий основной верхний колонтитул первого раздела, существующий в любом документе.
Если не требуется выделять объекты в колонтитулах, то переносить курсор в колонтитул не обязательно.

Sub Example3()
'Пример: перебор по невложенным объектам Shapes в
'основном тексте и колонтитулах (не находящихся на канвах и в группах)
'Вычисляется число невложенных объектов Shapes

  Dim intShapeCount As Integer 'счетчик объектов Shape
  Dim shp As Shape 'shape для текущей цепочки в  rngStory
 
  intShapeCount = 0

  'Цикл по Shapes в Main Text
  For Each shp In ActiveDocument.Shapes
    intShapeCount = intShapeCount + 1
  Next shp
 
  'Цикл по всем Shapes во всех колонтитулах
  '(в первом разделе документа всегда существует основной верхний колонтитул)
  For Each shp In ActiveDocument.Sections(1).Headers(wdHeaderFooterPrimary).Shapes
    intShapeCount = intShapeCount + 1
  Next shp
  MsgBox "Невложенных объектов Shape: " & intShapeCount, vbInformation _
          , "Перебор по невложенным объектам shape"
End Sub

Перебор вложенных объектов Shapes и InlineShape

Для перебора объектов Shape и InlineShape, содержащихся в других объектах Shape, напишем отдельную подпрограмму:
Private Sub CountInShps(shp As Shape, intShpCount As Integer)
'Добавить в intShpCount число объектов Shape и InlineShapes, вложенных в shp
 
  Dim shpInShape As Shape 'переменная для цикла по CanvasItems или GroupItems
  Dim ils As InlineShape  'переменная для цикла по InlineShapes
 
  intShpCount = intShpCount + 1
 
  Select Case shp.Type
    Case 20 'msoCanvas
    'msoCanvas = 20 'не определено в Office pre-2000, поэтому используется число 20
      'Переход к элементам в канве
      If shp.CanvasItems.Count > 0 Then ' Для предотвращения ошибки Automatization Error
                                        ' в Word 2003
        For Each shpInShape In shp.CanvasItems
          'Рекурсия
          Call CountInShps(shpInShape, intShpCount)
        Next shpInShape
      End If
     
    Case 6 'msoGroup
      'Переход к элементам в группе
      For Each shpInShape In shp.GroupItems
        'Рекурсия
        Call CountInShps(shpInShape, intShpCount)
      Next shpInShape
     
    Case Else
      'Цикл по объектам InlineShapes в тексте, расположенном в Shape
      If shp.TextFrame.HasText Then
          For Each ils In shp.TextFrame.TextRange.InlineShapes
            intShpCount = intShpCount + 1
          Next ils
      End If
  End Select
End Sub
Если объект shp представляет канву или группу, то происходит перебор по всем объектам Shape, содержащимся в shp, и для каждого такого элемента выполняется рекурсивное обращение к подпрограмме CountInShps для дальнейшей обработки вложенных элементов. В противном случае, если объект shp содержит текст, вычисляется количество объектов InlineShape в этом тексте.

Подпрограмма CountInShps позволяет усовершенствовать подпрограмму Example3 и подсчитать общее число объектов Shapes и вложенных объектов InlineShapes в основном тексте документа и в колонтитулах.

Sub Example4()
'Пример: перебор по объектам Shapes и вложенным в надписи
'объектам InlineShapes в основном тексте и колонтитулах
'Вычисляется число объектов Shapes и вложенных объектов InlineShapes

  Dim intShpCount As Integer 'счетчик объектов Shape
  Dim shp As Shape 'shape для текущей цепочки в rngStory
 
  intShpCount = 0

  'Цикл по Shapes в Main Text
  For Each shp In ActiveDocument.Shapes
    Call CountInShps(shp, intShpCount)
  Next shp
 
  'Цикл по всем Shapes во всех колонтитулах
  '(в первом разделе документа всегда существует основной верхний колонтитул)
  For Each shp In ActiveDocument.Sections(1).Headers(wdHeaderFooterPrimary).Shapes
    Call CountInShps(shp, intShpCount)
  Next shp
 
  MsgBox "Объектов Shape и вложенных InlineShape: " & intShpCount, vbInformation _
          , "Перебор по объектам Shape по вложенным объектам InlineShape"
End Sub

Теперь можно объединить подпрограммы Example2 и Example4, чтобы посчитать общее число графических объектов в документе. Однако следует отметить, что объекты InlineShape в надписях, расположенных в основном тексте документа, учитываются в каждой из этих подпрограмм. Поэтому исключим их из обработки, выполняемой в программе Example2
Sub Example5()
'Пример: перебор по объектам Shapes и InlineShapes в активном документе
'Вычисляется число объектов Shapes и InlineShapes

  Dim intShpCount As Integer 'счетчик объектов Shape
  Dim shp As Shape 'shape для текущей цепочки в  rngStory
  Dim intInlShpCount As Integer 'счетчик InlineStory
  Dim rngStory As Range 'range для текущего объекта story в цикле
  Dim inlShape As InlineShape 'текущей объект InlineShape в цикле
 
  intShpCount = 0

  'Цикл по Shapes в основном тексте (Main Text)
  For Each shp In ActiveDocument.Shapes
    Call CountInShps(shp, intShpCount)
  Next shp
 
  'Цикл по всем Shapes во всех колонтитулах
  '(в первом разделе документа всегда существует основной верхний колонтитул)
  For Each shp In ActiveDocument.Sections(1).Headers(wdHeaderFooterPrimary).Shapes
    Call CountInShps(shp, intShpCount)
  Next shp
 
  'Цикл по каждому типу цепочек активного документа
  For Each rngStory In ActiveDocument.StoryRanges
    'Надписи (TextFrame) уже обработаны
    If rngStory.StoryType <> wdTextFrameStory Then
      'iterate thru each story the same type
      Do
        'в диапазоне цепочки rngStory на каждой итерации
          For Each inlShape In rngStory.InlineShapes
            intShpCount = intShpCount + 1
          Next inlShape
       
        'переход к следующей цепочке rngStory того же типа
        Set rngStory = rngStory.NextStoryRange
      Loop Until rngStory Is Nothing
    End If
  Next rngStory
 
  MsgBox "Объектов Shape и InlineShape: " & intShpCount, vbInformation _
          , "Перебор объектов Shape и InlineShape"
End Sub

Следует упомянуть, что в этой подпрограмме не учитываются рамки (Frames), о которых говорится в примечании 1.
Кроме того, здесь не учитываются встроенные фигуры, которые могут быть вставлены в узлы диаграмм в Microsoft Word 2003. Это можно было бы сделать, но эти диаграммы исключены из Microsoft Word 2007, поэтому я счел эту работу бесперспективной и не стал усложнять программу. Наконец, в Microsoft Word 2007 объекты InlineShape могут содержаться в объектах SmartArt (например, в качестве фона элемента), но в VBA я не смог найти средств доступа к компонентам объектов SmartArt.

читаем оригинал тут

Комментариев нет:

Отправить комментарий