Свойства largechange и smallchange определяют, на сколько изменится значение value при одном щелчке поверхности полосы между кнопкой прокрутки и бегунком в первом случае и при щелчке кнопки прокрутки – во втором. Эти же свойства указывают, на сколько при этом смещается бегунок. По умолчанию оба свойства равны 1. Рекомендуемая область значений обоих свойств – от –32,767 до 32,767.
    Свойство delay (задержка) определяет в миллисекундах время, через которое последовательно возникают события change, если пользователь непрерывно щелкает кнопку прокрутки или левую кнопку мыши, указывающей на полосу прокрутки. По умолчанию устанавливается значение в 50 миллисекунд.
    Свойство proportionalthumb определяет размер бегунка: true – размер бегунка пропорционален размеру области прокрутки (это значение по умолчанию); false – система определяет фиксированный размер бегунка.
    Пример 26. Создать форму, содержащую два элемента scrollbar, два текстовых поля и кнопку, выводящую результат вычисления в метку на форме. Программно отражать значения в текстовых полях формы при движении бегунка. После нажатия на кнопке «Вычислить» программа считывает значения с текстовых полей, переводит эти значения в числовые и суммирует. Результат отражается в соответствующей метке на форме.
    Технология выполнения
   1. Активизируйте приложение Word и сохраните документ.
   2. Перейдите в редактор VBA и создайте форму (рис. 56).
 
    Рис. 56.Форма примера 26 в режиме конструктора и рабочем режиме
 
   3. Обработайте элементы ScrollBar и кнопку «Вычислить».
   Dim a, b, c As Integer
   Private Sub CommandButton1_Click()
   c = a + b
   Label4.Caption = «Сумма с=» & c
   End Sub
   Private Sub ScrollBar1_Change()
   TextBox1.Text = ScrollBar1.Value
   a = Val(TextBox1.Text)
   End Sub
   Private Sub ScrollBar2_Change()
   TextBox2.Text = ScrollBar2.Value
   b = Val(TextBox2.Text)
   End Sub
   4. Откомпилируйте программу и запустите форму на выполнение.
Счетчик SpinButton
   SpinButton (счетчик, ворот) позволяет пользователю увеличивать и уменьшать числовой параметр до получения требуемого значения. Один щелчок кнопки прокрутки увеличивает или уменьшает значение свойства Value на величину, заданную свойством SmallChange. Как и для ScrollBar, интервал изменения числовой характеристики определяется значениями свойств Min и Мах, вертикальная или горизонтальная ориентация счетчика – свойством Orientation, а задержка между повторными событиями Change – свойством Delay.
   Чтобы изменения Value были видны пользователю, счетчик надо связать с полем ввода или с меткой в процедуре обработки события Change, так же как для полосы прокрутки.
    Пример 27. Создать форму, содержащую два элемента spinbutton, два текстовых поля и кнопку, выводящую результат вычисления в метку на форме. Программно отражать значения в текстовых полях формы при движении бегунка. После нажатия на кнопке «Вычислить» программа считывает значения с текстовых полей, переводит эти значения в числовые и перемножает. Результат вычисления отражается в соответствующей метке на форме.
    Технология выполнения
   1. Активизируйте приложение Word и сохраните документ.
   2. Перейдите в редактор VBA и создайте форму (рис. 57).
 
    Рис. 57.Форма примера 27 в режиме конструктора и в рабочем режиме
 
   3. Обработайте элементы SpinButton и кнопку «Вычислить».
   Dim a, b, c As Integer
   Private Sub CommandButton1_Click()
   c = a * b
   Label4.Caption = «Произведение с =» & c
   End Sub
   Private Sub SpinButton1_Change()
   TextBox1.Text = SpinButton1.Value
   a = Val(TextBox1.Text)
   End Sub
   Private Sub SpinButton2_Change()
   TextBox2.Text = SpinButton2.Value
   b = Val(TextBox2.Text)
   End Sub
   4. Откомпилируйте программу и запустите форму на выполнение.

4.4. Объект DataObject [3]

Описание объекта DataObject
   Этот объект не является элементом управления, но участвует в операциях перетаскивания выделенных текстов из одного элемента управления в другой. В нем одновременно могут храниться несколько текстовых данных в разных форматах. Когда в DataObject помещается новый текст с имеющимся в нем форматом, то прежний текст с этим форматом заменяется на новый.
   Поведение DataObject похоже на поведение буфера обмена. Однако DataObject существует только в момент работы приложения и исчезает после ее завершения, а данные в буфере обмена при этом не теряются, DataObject может хранить только текстовые данные, а буфер обмена – и графические. С другой стороны, DataObject – настоящий OLE-объект и поддерживает, в отличие от буфера обмена, операции перетаскивания текста.
   Текст заносится в DataObject методом SetText, а извлекается оттуда методом GetText:
   объект. SetText(StoreData [, format])
   и
   Строка = объект. GetText([format]),
   где объект – объект – владелец метода;
   StoreData – текст, который надо запомнить в объекте;
   format – это необязательный параметр, задающий «формат» данных (1 соответствует стандартному текстовому формату, а другие числа и строки соответствуют пользовательским форматам).
 
   Если параметр format в вызове SetText явно не указан, то запоминаемому тексту присваивается формат стандартного текста 1. Так как для каждого формата DataObject содержит лишь один текст с этим форматом, то фактически формат играет роль ключа, с помощью которого текст заносится и извлекается из DataObject. Метод GetFormat позволяет узнать, имеется ли в объекте DataObject текст определенного формата:
   BooleanVar = объект. GetFormat(format)
   Переменная BooleanVar получит значение True, если данные с указанным форматом входят в объект. Объект DataObject может обмениваться данными с буфером обмена посредством методов GetFromClipboard и PutInClipboard. Оператор
   String = объект. GetFromClipboard()
   помещает содержимое буфера обмена в DataObject, а вызов
   объект. PutInClipboard
   переносит данные из DataObject, имеющие текстовый формат 1, в буфер обмена.
    Пример 28. Форма содержит два текстовых поля, в одном из них программно отображается текст, который при помощи методов объекта dataobject необходимо перенести (перекопировать) во второе текстовое поле. Данное действие происходит после нажатия на кнопку «Копировать», причем все производимые действия программы отображаются в соответствующей метке на форме (рис. 58).
 
    Рис. 58.Форма примера 28 в режиме конструктора и в рабочем режиме
 
    Технология выполнения
   1. Активизируйте приложение Word и сохраните документ.
   2. Перейдите в редактор VBA и создайте форму (рис. 58).
   3. Пропишите при инициализации окна в поле TextBox1 текстовую информацию и проинициализируйте глобальные переменные:
   Public NewData As DataObject
   Public NumClick As Integer
   Private Sub UserForm_Initialize()
   Set NewData = New DataObject 'инициализация объекта
   NumClick = 0
   'число щелчков
   TextBox1.Text = "Пример переноса данных с помощью
   DataObject»
   End Sub
   4. При последовательных щелчках по командной кнопке будут происходить последовательно действия, описанные в программе:
   Private Sub CommandButton1_Click()
   Select Case NumClick
   Case 0
   NewData.SetText TextBox1.Text
   Label1.Caption = «Из первого поля в DataObject»
   Case 1
   NewData.PutInClipboard
   Label1.Caption = «Из DataObject в буфер обмена»
   Case 2
   TextBox2.Paste
   Label1.Caption = «Из буфера обмена во второе поле»
   End Select
   NumClick = NumClick + 1
   If NumClick = 3 Then NumClick = 0
   End Sub
   5. Откомпилируйте программу и запустите форму на выполнение.
    Примечание.Перенос информации из одного поля в другое можно осуществить и через буфер обмена, минуя DataObject. Для копирования данных из поля ввода в буфер обмена можно использовать метод Сору.
Перемещение объектов. Реализация технологии DragAndDrop
   Для копирования данных из поля ввода в буфер обмена обычно вызывают метод Сору. Однако при организации интерфейса в диалоговых формах полезно предоставить пользователю возможность работы с техникой DragAndDrop (Переместить и Опустить). Некоторый объект захватывается мышью, перетаскивается к другому целевому объекту и отпускается, изменяя при этом свойства целевого объекта. Типичным примером является возможность перетаскивать элемент из одного списка в другой. Другой пример – перетаскивание писем и опускание их в почтовый ящик. Важным элементом этой техники является изменение внешнего вида курсора. Захват объекта происходит при подведении курсора к объекту и нажатии левой кнопки мыши. В этот момент курсор меняет внешнюю форму. Когда происходит перемещение мыши, то в тех областях, где расположен целевой объект, курсор снова меняет форму, показывая, что цель достигнута. Если в этот момент отпустить левую кнопку мыши, то операция перемещения заканчивается успешно. Если отпустить кнопку мыши в других областях, то это приведет к неудаче. Объект DataObject и его метод StartDrag являются частью этой технологии.
    Пример 29. Создать форму, имеющую два элемента управления: список и текстовое поле. При помощи мыши из списка перетаскивают в текстовое поле необходимый элемент, выделенный в списке (рис. 59, 60, 61).
   Программно заполняются элементы списка, который содержит наименования месяцев года. Программа, используя технологию DragAndDrop объекта DataObject, позволяет перетащить выбранный элемент из списка в текстовое поле выбора (рис. 60). При неправильном действии, т. е. перетаскивании не в текстовое поле, происходит вызов предупреждающего сообщения (рис. 61).
 
    Рис. 59.Форма примера 29 в режиме конструктора
 
    Рис. 60.Форма примера 29 в рабочем режиме
 
    Рис. 61.Окно предупреждения о неправильно выполненной операции
 
   Когда пользователь захватывает выбранный им элемент списка, то возникает некоторое событие. В нашем примере это событие MouseMove, обработчик которого и будет вызывать метод StartDrag объекта DataObject, который хранит значение перетаскиваемого элемента. Синтаксис метода:
   Function StartDrag([Effect As fmDropEffect]) As
   fmDropEffect
   Эта функция обычно вызывается в операторе присваивания вида:
   ResultEffect=объект. StartDrag([effect as fmDropEffect])
   Необязательный параметр Effect и результат выполнения функции принадлежат перечислению fmDropEffect. Константы, входящие в это перечисление, имеют следующие значения:
    fmDropEffectNone = 0 – не копировать и не передвигать опущенный исходный элемент на место назначения;
    fmDropEffectCopy =1 – копировать опущенный исходный элемент на место назначения;
    fmDropEffectMove = 2 – передвинуть опущенный исходный элемент на место назначения;
    fmDropEffectCopyOrMove = 3 – скопировать или передвинуть опущенный исходный элемент на место назначения.
   Параметр Effect задает цель операции и имеет по умолчанию значение 1 (fmDropEffectCopy). Обычно он опускается, поскольку значение по умолчанию задает наиболее вероятную цель операции. Значение, возвращаемое методом StartDrag, определяет результат выполнения операции. Его можно использовать для анализа того, что же произошло в результате перетаскивания на самом деле. Между запуском метода StartDrag в правой части оператора присваивания и присваиванием результата левой части переменной ResultEffect в процессе перемещения объекта происходит много событий. Работают обработчики этих событий, и результат говорит о том, как закончился этот процесс.
    Технология выполнения
   1. Активизируйте приложение Word и сохраните документ.
   2. Перейдите в редактор VBA и создайте форму (рис. 59).
   3. Создайте обработчик события Initialize для диалогового окна, обеспечивающего инициализацию начального состояния:
   Private Sub UserForm_Initialize()
   With Me.ListBox1
   AddItem «январь»
   AddItem «февраль»
   AddItem «март»
   AddItem «апрель»
   AddItem «май»
   AddItem «июнь»
   AddItem «июль»
   AddItem «август»
   AddItem «сентябрь»
   AddItem «октябрь»
   AddItem «ноябрь»
   AddItem «декабрь»
   End With
   End Sub
   4. В результате инициализируется список «Месяц года», имеющий имя ListBox1. Готовясь перетащить этот элемент в другое место, пользователь выбирает элемент этого списка. Затем он нажимает левую клавишу мыши, и у списка возникает событие MouseMove, обработчик которого имеет много параметров. Приведем текст этого обработчика:
   Private Sub ListBox1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
   Dim MyDataObject As DataObject
   Dim Msg As String
   Msg = «Видимо, Вы уронили месяц при перетаскивании. Повторите операцию!»
   If Button = 1 Then
   Debug.Print «MouseMove»
   Set MyDataObject = New DataObject
   Dim Effect As Integer
   MyDataObject.SetText ListBox1.Value
   Effect = MyDataObject.StartDrag(fmDropEffectCopy)
   If Effect = 0 Then MsgBox (Msg)
   Debug.Print "Effect = ", Effect
   End If
   End Sub
   5. Откомпилируйте программу и запустите форму на выполнение.
    Дополнительные элементы управления
   В VBA, кроме перечисленных стандартных элементов управления, имеется ряд дополнительных. Дополнительные элементы управления являются самостоятельными объектами, обладающими как общими для всех элементов управления свойствами и методами, так и присущими только им свойствами и методами. Для добавления дополнительных элементов управления на панель элементов необходимо:
   1) выбрать команду Сервис + Дополнительные элементы(Tools + Additional Controls);
   2) в появившемся на экране окне Дополнительные элементы(Additional Controls) (рис. 62) в списке Доступные элементы(Available Controls) установить флажок напротив добавляемого элемента;
   3) нажать кнопку ОК.
   Удаление ненужного элемента управления из панели элементов происходит аналогично добавлению, только флажок снимают.
 
 
    Рис. 62.Окно добавления дополнительных элементов
 
   Среди дополнительных элементов управления очень полезным является элемент управления Calendar (календарь) (рис. 63). Этот объект представляет средство для организации удобного интерфейса по вводу дат. Элемент управления конструируется в форме с помощью кнопки Календарь(Calendar).
 
 
    Рис. 63.Элемент управления calendar, расположенный на форме
 
   Перечислим основные свойства элемента управления Calendar (табл. 14).
 
    Таблица 14
Свойства Calendar
 
   Перечислим основные методы элемента управления Calendar (табл. 15).
 
    Таблица 15
Методы Calendar
 
   В качестве примера использования календаря приведем следующую процедуру, которая считывает из календаря выбранную дату и вводит ее в ячейку рабочего листа:
   Private Sub Calendar1_Click()
   Cells(1, 1).Value = Calendar1.Value
   End Sub

Часть II
Программирование на VBA в Word

Глава 5
Вывод текста в документ Word

5.1. Основные объекты Word

Объект Word.Application
   Дополнительно ко всем возможностям программирования на VBA, рассмотренным в части I, можно добавить возможности вывода всех результатов вычислений, преобразований, сообщений в документ Word, с возможностью дальнейшего отправления на печать. Для этого необходимо рассмотреть основные объекты приложения Word.
   Ключевым в объектной модели Word является объект Application, так как он содержит все остальные объекты Word. Его элементами на разных уровнях иерархии являются около 180 объектов. Сам корневой объект Application имеет более сотни элементов: свойств, методов и событий.
Свойства объекта Word.Application
   Свойства любого объекта делятся на две группы: свойства-участники (объекты) и терминальные свойства (обычные переменные VBA).
   Единую систему организации панелей меню и инструментальных кнопок обеспечивает объект CommandBars, справок – Assistant, поиска – FileSearch.
   Центральными объектами Word являются коллекции Documents и Templates, точнее составляющие их элементы, сам документ и шаблоны.
   Рассмотрим объекты второго плана.
   Объект AutoCorrectподдерживает работу по автоматической коррекции набираемых текстов. Его возможности эквивалентны команде Автозаменаменю Сервис.
   Объект Browserпозволяет перемещать точку вставки, указывающую на объекты в документе.
   Коллекция объектов Dialogsпредставляет совокупность диалоговых окон, встроенных в Word. Добавлять новые или удалять элементы этой коллекции программным путем нельзя. Но соответствующие окна можно открыть и показать на экране дисплея и тем самым организовать диалог пользователем по теме, заданной соответствующим окном.
   Три объекта, связанные с проверкой грамматики и орфографии: Languages, Dictionaries, SpellingSuggestions, – позволяют установить нужный язык, выбрать словарь, в том числе пользовательские словари, а также работать со списком слов, предлагаемых для исправления при обнаружении ошибки правописания. Команды Правописание и Язык меню Сервис предоставляют аналогичные, функциональные возможности при работе с документом вручную.
   С помощью объекта Options можно программным путем установить различные опции приложения и документа аналогично тому, как если бы вы выбрали команду Параметры в меню Сервис.
Работа с документами и класс Document
   Когда открывается приложение, создается коллекция документов Documents, содержащая все открытые документы. В начальный момент коллекция содержит минимум один новый или ранее существовавший документ. Новый документ добавляется методом Add, а уже существующий – методом Open объекта Documents. Чтобы добраться до нужного документа, достаточно указать его индекс – имя файла, хранящего документ, или его порядковый номер в коллекции. Для той же цели можно использовать и метод Item, но обычно он опускается. Метод Save позволяет сохранить документ, а метод Close, сохраняя документ в файле, закрывает его и удаляет из коллекции.
   Глобальное свойство Dialogs возвращает коллекцию диалоговых окон. Константа wdDialogFileOpen задает конкретное диалоговое окно – объект класса Dialog.
 
    Классы, задающие структуризацию текста документа
   Текст – это основа большинства документов. Его можно структурировать, оперируя различными единицами при решении тех или иных задач преобразования. Минимальной единицей текста обычно является символ. Кроме этого, существуют следующие единицы: слова, предложения, абзацы, а также более крупные образования: страницы, параграфы, главы.
   Классы Characters, Words, Statements, Paragraphs, Sections позволяют работать с последовательностями (коллекциями) символов, слов, предложений, абзацев и разделов. Самой крупной единицей после абзаца выступает раздел. Элементом коллекций Characters, Words и Statements является объект класса Range. Объект Range позволяет работать как с одним элементом, так и с произвольной последовательностью элементов. Документы, поддокументы, абзацы, разделы – все они имеют метод или свойство Range, возвращающее интервал, связанный с объектом. Поэтому работа с текстом так или иначе ведется через методы и свойства объекта Range.
 
    События объекта Document
   Объект Document может реагировать на три события, возникающие в результате действий пользователя.
 
    Таблица 16
События объекта Document
Документ и его части
   Рассмотрим основные классы, определяющие структуру документа.
   1.  Subdocuments (Subdocument)– коллекция и сам поддокумент. Есть некоторый разумный предел размера одного документа. Если в документе больше 10–20 страниц, работать с ним становится неудобно. В этом случае в нем выделяют главный документ и поддокументы. Главный документ в этом случае имеет коллекцию поддокументов, каждый из них является, по сути, документом, с которым можно работать независимо.
   Метод AddFromRange класса SubDocuments создает поддокумент, выделяя из главного документа область, заданную параметром Range.
   2. Tables (Table), TablesOfAuthoritiesCategories (T.O.A.C), TablesOfAuthorities (TableOfAuthorities), TablesOfContents (TablesOfContent), TablesOfFigures (TablesOfFigure). Класс Table определяет «обычные» таблицы с произвольным количеством строк и столбцов и произвольным заполнением полей. Остальные классы задают таблицы специального вида.
   3.  Shapes(Shape), InlineShapes(InlineShape)– эти две коллекции с их элементами позволяют добавлять в документ рисунки, но не только их. ActiveX– и OLE-объекты также являются элементами этих коллекций. Элементы этих двух коллекций отличаются тем, как они привязаны к документу: первые могут свободно перемещаться, вторые жестко привязаны к заданной области документа.
   4.  Lists(List), ListParagraphs(ListParagraph), listTemplates (ListTemplate)– списки удобно вводить в документ, когда имеешь дело с перечислением. Списки можно оформлять в соответствии с шаблоном. Существуют две группы шаблонов: нумерованные списки и списки-бюллетени. Коллекция ListTemplates содержит шаблоны оформления списков, а класс ListTemplate описывает конкретный шаблон. Шаблон применяется к списку абзацев и придает ему структуру, заданную шаблоном. Коллекция Lists содержит те списки документа (списки абзацев), что оформлены как нумерованные списки или списки-бюллетени. Коллекция ListParagraphs представляет список абзацев всех списков документа. Свойством ListParagraphs, которое возвращает объект соответствующего класса, обладает не только документ, но и объекты List и Range. Так что при наличии списка – объекта List можно выделить список абзацев. Чаще приходится выполнять обратную операцию – применять к списку абзацев один из возможных шаблонов, придав ему «настоящую» структуру списка. Тогда используют объект ListFormat.
   5.  Comments(Comment), Bookmarks(Bookmark), FootNotes (FootNote), EndNotes(EndNote), Fields(Field)– эти коллекции и их элементы отражают независимые, но близкие по духу понятия. Это части документа, косвенно связанные с ним. При нормальном просмотре документа они могут быть и не видны.
    Коллекция comments и класс comment задают комментарии. Комментарии, как известно, вводятся для пояснения тех или иных терминов или понятий документа. Формально они приписываются некоторой области – объекту range.
    Большой документ, к отдельным частям которого приходится часто обращаться, стоит снабдить закладками. Коллекция bookmarks задает все закладки данного документа.
    Еще один способ комментирования – сноски. Они могут быть двух видов: подстраничные (внизу страницы) и концевые (в конце документа). Первые собраны в коллекцию footnotes, вторые – endnotes.
   6.  Fields(Field) – эта коллекция позволяет работать с полями документа. Одна из особенностей полей состоит в том, что их значения обновляются автоматически в зависимости от изменившихся внешних условий или контекста.
   7.  Story Ranges(Range) – эта коллекция представляет совокупность частей документа, называемых фрагментами (Story). Количество различных фрагментов документа фиксировано. Нельзя добавлять элементы в эту коллекцию обычным способом, используя метод Add. Фрагменты появляются в коллекции, когда создается соответствующая часть документа.
   Фрагменты имеют тип, задаваемый константами из перечисления wdStoryType. Главный фрагмент – текст документа, тип которого задается константой wdMainTextStory. Комментарии, ссылки, колонтитулы составляют фрагменты других типов, т. е. сам фрагмент является объектом Range. Так что благодаря фрагментам можно, например, работать с коллекцией комментариев как с единой областью.
   8.  Variables(Variable) – с документом можно связать коллекцию переменных типа Variant. Это важная для программистов коллекция, так как время жизни переменных, в нее входящих, совпадает со временем жизни документа. Тем самым появляется возможность сохранять информацию о работе той или иной процедуры между сеансами. Например, можно иметь счетчики, подсчитывающие число вызовов макроса, и в зависимости от этого по-разному определять его дальнейшую работу.
Объекты Range и Selection
   Объект Document имеет метод Range, возвращающий объект Range, и метод Select, создающий объект Selection. Метод Range – это функция, возвращающая как результат объект Range; метод Select – это процедура без параметров, которая создает объект Selection в качестве побочного эффекта. Объект Range имеет метод Select, превращающий область объекта Range в выделенную. Тем самым метод Select определяет новый объект Selection. Симметрично, объект Selection имеет свойство Range, возвращающее объект Range, соответствующий выделенной области.
   Большинство ранее описанных частей документа являются и частями (свойствами) объектов Range и Selection.
   Объект Range напоминает матрешку: в каждую область вложена область поменьше. Вот пример корректного (хоть и не самого эффективного) задания объекта Range:
   ActiveDocument.Range.Sections(1).Range.Paragraphs(l).Range.Sentences(1). Words(1).Characters(1)
Работа с текстом
   Объекты Range и Selection позволяют выполнять основные операции над текстом: «выделить», «добавить», «заменить», «удалить». У наших объектов большой набор методов, позволяющих реализовать эти операции. Все рассматриваемые здесь методы принадлежат обоим объектам, если не сделана специальная оговорка.
    Выделение
   Выделить некоторую часть текста по существу означает определить объект Range или Selection. Объекты задают некоторую область в тексте документа, а их свойства Start и End позволяют установить начало и конец этой области. Меняя значения свойства, можно задать нужную область выделения.
   Move является основным методом перемещения точки вставки. Остальные методы этой группы – в той или иной степени его модификации. Метод Move(Unit, Count) сжимает область в точку, стягивая ее в начало или конец, а затем перемещает точку вставки. Параметр Unit определяет единицы перемещения, a Count – количество этих единиц (по умолчанию 1). Знак переменной Count задает направление стягивания и перемещения. Положительные значения этого параметра задают стягивание к концу и перемещение вперед, отрицательные – стягивание в начало и перемещение назад. Чистое стягивание без перемещения точки вставки задается как перемещение на одну единицу. Метод возвращает количество единиц, на которое фактически произошло перемещение, или 0, если оно не осуществлено. Параметр Unit принимает значения wdCharacter (по умолчанию), wdWord, wdSentence, wdParagraph, wdSection, wdStory, wdCell, wdColumn, wdRow и wdTable.