Домашняя страница > Обработка графики в VBA
Обработка графики в Microsoft Word средствами VBA
|
Предварительные сведения об объектах Shape и InlineShape Преобразование InlineShape — Shape Встроенные и перемещаемые объекты Преобразование встроенный — перемещаемый Ограничения для средств пользовательского интерфейса Перебор графических объектов в Microsoft Word средствами VBA Применение свойства ShapeRange Применение свойства InlineShapes Перебор вложенных объектов Shapes и InlineShape Обработка графики в программе EachShape |
|
В загружаемом документе GraphProc.rar помимо текста данной страницы содержатся макросы. Макросы к разделу Перебор графических объектов в Microsoft Word средствами VBA находятся в модуле Example, а к разделу Обработка графики в программе EachShape — в модуле Each_shape и в форме frmEachShape.
Графические объекты, используемые в документах Microsoft Word, в объектных библиотеках представлены классами Shape и InlineShape. Способ обработки графических объектов средствами VBA существенно зависит от того, к какому классу принадлежит объект. В этом разделе приведены основные особенности объектов, относящихся к каждому из этих классов.
Объекты Shape могут находиться только в основном тексте документа и в колонтитулах, а объекты InlineShape можно разместить также в сносках (включая продолжения сносок и уведомления о продолжении сносок), примечаниях и почти всегда в тексте, содержащемся в объектах Shape.
Любой объект Shape, кроме канвы (объекта типа msoCanvas), можно разместить также на канве, а любые объекты, кроме канвы и группы (объекта типа msoGroup), могут входить в состав группы.
Если объект InlineShape находится в таком месте, где могут находиться объекты Shapе, его можно обратимо преобразовать в соответствующий объект Shape. К объектам InlineShape относятся OLE-объекты (объекты, вставленные из других приложений), рисунки, горизонтальные линии, рисованные маркеры для маркированных списков, объекты WordArt и SmartArt. В то же время такие объекты Shape, как канва, группа, надпись и автофигура, преобразовать в объект InlineShape нельзя.
Все объекты InlineShape являются встроенными (in line), то есть расположенными в тексте аналогично символам и перемещаемыми вместе с текстом.
Объекты Shape могут быть как встроенными, так и перемещаемыми (float). Перемещаемый объект можно точно расположить на странице (и даже вне ее) с размещением текста вокруг этого объекта, поверх него или под ним.
Если перемещаемый объект Shape не находится на канве и не входит в группу, его можно преобразовать во встроенный объект. Если же он относится к тому типу объектов, которые могут быть преобразованы в объект InlineShape, то в ряде случаев при преобразовании перемещаемого объекта Shape во встроенный объект незаметно для пользователя автоматически происходит его преобразование в объект InlineShape (это зависит не только от типа объекта и его состояния, но и от версии Microsoft Word).
При работе с графическими объектами средствами пользовательского интерфейса Microsoft Word нет никакой разницы между встроенным объектом Shape и полученным из него объектом InlineShape. Наверное, поэтому ни в пользовательском интерфейсе Microsoft Word, ни в справочной документации ничего не говорится о разделении на объекты Shape и InlineShape. Однако и тем пользователям, которые не прибегают к программированию, не помешало бы знать, что такой объект, как канва, группа, надпись или автофигура, можно разместить только в основном тексте документа и в колонтитулах, а в остальных частях документа можно размещать только встроенные объекты. Эти два условия ограничивают возможности преобразования встроенных объектов в перемещаемые и копирования перемещаемых объектов в другие части документа.
Графические объекты представляются в 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 |
Объекты 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. Это означает, что при закрытии документа последует запрос о его сохранении.
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 не получается.
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.
Returns an InlineShapes collection that represents all the InlineShape objects in a selection
Когда свойство InlineShapes применяется к объекту Selection, оно возвращает коллекцию InlineShapes, представляющую все объекты InlineShape, относящиеся к выделенному диапазону, представленному этим объектом Selection.
Returns an InlineShapes collection that represents all the InlineShape objects in a range.
Когда свойство InlineShapes применяется к объекту Range, оно возвращает коллекцию InlineShapes, представляющую все объекты InlineShape, относящиеся к диапазону, представленному этим объектом Range.
Returns an InlineShapes collection that represents all the InlineShape objects in a document.
Когда свойство InlineShapes применяется к объекту Document, оно возвращает коллекцию InlineShapes, представляющую все объекты InlineShape, находящиеся в основном тексте документа, представленного этим объектом Document.
Для перебора всех объектов 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.
Объекты 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
Для перебора объектов 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.
Теперь, когда мы научились перебирать графические объекты, можно сделать что-нибудь более интересное, чем просто посчитать их количество. Для этого следует написать подпрограмму обработки одного графического объекта и вставить ее вместо оператора приращения счетчика в подпрограммы Example5 и CountInShps. Точнее, надо написать, как минимум, две подпрограммы: одну для обработки объектов Shape, а другую для объектов InlineShape (эти объекты обрабатываются по-разному). Кроме того, необходима программа для подготовки к перебору объектов (вместо обнуления счетчика) и программа вывода результатов.
В качестве примера рассмотрим программу Each Shape, в которой перебираются все графические объекты в активном документе и каждый из них по очереди выделяется. О каждом выделенном объекте сообщаются основные данные, а в конце выводится журнал — документ, в который копируются все графические объекты вместе с информацией о них, а также текст из надписей, содержащихся в этих объектах. Эта программа содержится в модуле Each_shape (она также оформлена в виде шаблона, который можно загрузить на странице http://markros.ru/eachshape).
Прошу прощения за англоязычный интерфейс пользователя. Я счел нецелесообразным по своему разумению переводить на русский язык многочисленные названия типов графических объектов. Это только запутало бы читателя. А делать смесь "французского с нижегородским" мне не хотелось.
Программа выполняется в несколько этапов:
Собирается статистика по всем графическим объектам активного документа, и полученные результаты отображаются для пользователя на форме frmEachShape.
С помощью формы frmEachShape пользователь отбирает объекты для просмотра и способ их обработки и запускает обработку.
В соответствии с выбором пользователя выполняется последовательное выделение всех графических объектов с отображением основных сведений о каждом из них.
После просмотра графических объектов выводится файл с копией всех графических объектов, краткой информацией об этих объектах и текстом из надписей, содержащихся в объектах.
Таким образом, выполняется два шага перебора графических объектов: сбор статистики и собственно обработка объектов.
Глобальная переменная intProcessStepPbl— номер шага.
Для запуска программы используется кнопка Each Shape, расположенная на панели инструментов EachShape и вызывающая макрос EachShape:
Sub EachShape()
'process step number
'номер шага обработки
intProcessStepPbl = 1
Set docActivePbl = ActiveDocument
'seroing statistic
'обнуление статистических характеристик
Call PblZeroing
'save <saved> property to restore it (if it need)
'запомнить свойство <saved>, чтобы при необходимости восстановить его
boolDocSavedPbl = docActivePbl.Saved
'first graphics iteration
'первый перебор графики
Call IterateGrapics
'Fill And Show Form
'Заполнение и отображение формы
Call FillAndShowForm
End Sub
После завершения работы макроса EachShape отображается форма frmEachShape с собранной статистикой, флажками для выбора способа обработки, флажками для отбора объектов для просмотра и кнопками запуска и отмены обработки:
После выбора параметров обработки пользователь запускает второй шаг перебора графики. Это демонстрирует следующий фрагмент макроса, обрабатывающего событие нажатия кнопки Start:
Private Sub btnStart_Click()
............
'process step number
'номер шага обработки
intProcessStepPbl = 2
'fill reference tables
'заполнение справочных таблиц
Call Init
'Create log document and add statistics to it
'создание журнала обрабоки и занесение в него статистики
Call AddLogDoc
'zeroing graphics counter
'обнуление счетчика графики
intGraphicsPbl = 0
'second process step
'второй шаг обработки
Call IterateGrapics
'finishing
'завершение работы
Call allDone
End Sub
На каждом шаге перебор графических объектов осуществляется подпрограммой IterateGrapics, содержащей обращение к подпрограмме NestShp. Эти две подпрограммы действуют аналогично описанным выше подпрограммам Example5 и CountInShps.
В подпрограммах IterateGrapics и NestShp в том месте, где в программах Example5 и CountInShps были инструкции приращения счетчика объектов, происходит вызов программ обработки графических объектов: подпрограммы ProcessShp для обработки объектов Shape и подпрограммы ProcessIls для обработки объектов InlineShape.
Дополнительно в подпрограммах IterateGrapics и NestShp предусмотрен учет расположения и вложенности графических объектов. С этой целью в них вычисляются и передаются в подпрограммы обработки графических объектов следующие параметры:
intNestLevel — уровень вложенности
strNesting — массив имен объектов, в которых находится текущий объект
lctn — признак местоположения (основной текст, колонтитулы, комментарии, сноски, концевые сноски)
В подпрограммах ProcessShp и ProcessIls в зависимости от выполняемого шага (сбор статистики или обработка объектов) вызываются различные подпрограммы обработки.
Подробности алгоритма можно посмотреть в коде подпрограмм, поэтому я решил их не описывать, а обратить ваше внимание на наиболее интересные моменты обработки графики:
Восстанавливается свойство Saved
Как я уже упоминал, после обращения к свойству Shapes свойство Saved активного документа принимает значение False. Это означает, что при закрытии документа последует ненужный запрос о его сохранении.
Поэтому в макросе EachShape запоминается начальное значение этого свойства, а на выходе из программы в макросах AllDone свойство Saved активного документа восстанавливается.
В макросе boolCheckInPage учитывается, что в случае переноса на страницу объектов, лежащих вне ее, значением этого свойства должно быть False.
Проверяется, является ли объект InlineShape объектом WordArt
Для этой цели применяется макрос strInlineWordArtText.
Составлены громоздкие таблицы для текстового описания типов графических объектов
В макросе Init заполняются таблицы, по которым можно находить названия типов объектов Shape, InlineShape и AutoShape по числовым значениям встроенных констант (в справке Microsoft Word русские названия для них не упоминаются, и официального перевода для них нет).
Графические объекты, находящиеся вне страниц, по желанию пользователя могут возвращаться на страницу
Макрос boolCheckInPage проверяет, находится ли объект хотя бы частично в пределах страницы, и при необходимости может перенести его на страницу. Без средств VBA такую операцию выполнить сложно.
Определяются различные свойства и параметры графических объектов
Макросы strShpProperty и strIlsProperty и используемые в них подпрограммы помимо типа объекта определяют, является ли объект перемещаемым, выявляют наличие в объекте текста, выясняют, связаны ли надписи (перетекает ли текст), проверяют, является ли объект рисунком, определяют приложение — источник объекта, вычисляют размеры объекта и т. д.
Выводится сообщение о выделенном в колонтитуле объекте с отображением выделения
Макросы SelectShp и SelectIls позволяют вывести сообщение о выделенном объекте, находящемся в колонтитуле. Если не прибегать к искусственным приемам, то при выводе сообщения выделение таких объектов не отображается.
Копируется в другой документ текущий объект Shape без его выделения
Чтобы скопировать в другой документ текущий объект Shape, не выделяя его, в макросе LogShp копируется с форматированием соответствующий объект Anchor.
© Розенберг М. М., 2010
Последнее обновление страницы: 01.04.2010