Основы офисного программирования и документы Word

         

Реализация множественного буфера, основанная на форме


Прежде всего, я спроектировал форму с именем "BufferForm" для представления элементов, хранящихся в буфере. Эта форма, в полном соответствии с тем, что говорилось ранее, включает список, отображающий элементы буфера, и три командные кнопки. Взгляните, как выглядит эта форма в момент работы с ней:


Рис. 2.2.  Форма, отображающая элементы множественного буфера

Три командные кнопки, помещенные в форму, - "Вставить элемент", "Удалить элемент" и "Удалить все" - выполняют основные операции над элементами буфера. Отмечу одно важное свойство, установленное при проектировании формы BufferForm. Я сделал эту форму немодальной, установив булево свойство ShowModal как False. Это позволяет держать форму открытой при работе с документом и при необходимости вставлять нужные элементы из открытого списка.

Прежде, чем продолжить разговор о работе с этой формой, давайте займемся операцией добавления элементов в наш буфер. Вот как реализуется копирование выделенных объектов документа Word в наш множественный буфер. Приведу текст соответствующего макроса:

Public Sub CopyMult() 'Этот макрос копирует выделенный объект в множественный буфер MultBuffer.Add Selection.Range End Sub

Листинг 2.6.

(html, txt)

Как видите, в макросе копирования элементов в буфер для добавления элементов в коллекцию, используется метод Add, вся задача выполняется одним оператором и не требует особых пояснений. Заметьте, в коллекцию полностью добавляется выделенный объект, а не его текст или другие компоненты.

Конечно, в этот же момент можно было бы создавать и соответствующий элемент списка нашей формы. Но разумнее это делать в другом месте - в обработчике события, возникающего при активизации формы. Действительно, если представить, что форма уже открыта и расположена на экране, то программное добавление нового элемента в ее список не будет отображаться, пока форма не будет перерисована. Раз так, то целесообразнее каждый раз при активизации формы (появлении ее на экране) создавать список на основе текущего состояния множественного буфера - коллекции MultBuffer. Вот как выглядит для формы написанный мной обработчик события Activate, решающий задачу создания элементов списка формы. Естественно, что список создается на основе анализа состояния буфера:


Инструментальные кнопки класса ComboBox могут быть одного из трех типов, задавая окно редактирования, выпадающий список и список с окном редактирования. Кнопкой типа DropDown - выпадающий список можно воспользоваться для реализации множественного буфера. Вместо того, чтобы показывать список элементов буфера в отдельной форме, во многих случаях предпочтительнее иметь в меню кнопку типа DropDown, при работе с которой раскрывается список, отображающий элементы буфера.

Заметьте, этот прием может быть полезен не только в данном конкретном примере, но и во многих случаях, когда приходится предъявлять пользователю некоторый список для того, чтобы он сделал в нем свой выбор. Кнопка меню, конечно же, компактнее, чем отдельная открывающаяся форма. Именно по этой причине такой способ работы с множественным буфером может быть предпочтительнее.

Хочу обратить Ваше внимание, что стандартная реализация фактически сочетает оба эти способа. В стандартной реализации буфер обычно появляется в виде плавающей формы, но когда окно формы, являющееся стыковочным окном, "причаливает" к одному из краев экрана, то форма превращается в обычную инструментальную панель, и элементы буфера отображаются уже в списке кнопки типа Dropdown. Лично я предпочитаю при работе со стандартным буфером представлять его в виде инструментальной панели, но это, конечно, дело вкуса. Что же касается собственной реализации, то я предпочел разделить оба эти способа.

Перейдем теперь к рассмотрению деталей реализации. Замечу, что представление самого буфера в виде коллекции остается неизменным в обеих реализациях. Теперь только вместо формы появится инструментальная панель с соответствующими кнопками. Наряду с кнопкой типа DropDown, которая будет реализовывать операцию вставки элемента буфера, на инструментальной панели будут расположены и обычные командные кнопки, реализующие другие операции над буфером. Кнопку DropDown необходимо создать программно. Конечно, программно можно создать и саму панель, и все кнопки, расположенные на ней. Но я предпочел сочетать работу руками и программную работу. Вот как выглядит созданная инструментальная панель MultBufferPanel:


Рис. 2.3.  Панель MultBufferPanel с кнопкой типа DropDown

Две кнопки в первой группе RangeShape и PasteMult позволяют работать с множественным буфером, основанным на первой его реализации. Вторая группа кнопок предназначена для работы с буфером, основанным на втором способе реализации. Кнопка Copy1Mult позволяет копировать выделенный объект в документе Word в буфер, основанный на рассматриваемой нами DropDown реализации. Вторая кнопка, созданная программно, имеет тип DropDown и используется для выбора и вставки нужного элемента буфера в позицию, заданную курсором. Кнопка DelAll предназначена для чистки буфера, а кнопка InsertAll для вставки всех элементов буфера в позицию, заданную курсором. Заметьте, иногда такая операция бывает полезной. Также как и в стандартной реализации, отсутствует операция, позволяющая удалять единственный выбранный элемент буфера. Причина этого понятна, - выбор элемента в списке кнопки однозначно определяет и операцию, выполняемую над этим элементом. Такой операцией является операция вставки выбранного элемента. Для удаления элемента потребовалось бы иметь еще одну кнопку типа DropDown.

Все кнопки на панели MultBufferPanel можно создать руками, что я и делал. Единственным исключением является кнопка DropDown, которую нужно создавать программно. Рассмотрим, как это делается. Приведу сейчас тексты всех используемых мной процедур:




Прежде всего, я спроектировал форму с именем "BufferForm" для представления элементов, хранящихся в буфере. Эта форма, в полном соответствии с тем, что говорилось ранее, включает список, отображающий элементы буфера, и три командные кнопки. Взгляните, как выглядит эта форма в момент работы с ней:


Рис. 2.2.  Форма, отображающая элементы множественного буфера

Три командные кнопки, помещенные в форму, - "Вставить элемент", "Удалить элемент" и "Удалить все" - выполняют основные операции над элементами буфера. Отмечу одно важное свойство, установленное при проектировании формы BufferForm. Я сделал эту форму немодальной, установив булево свойство ShowModal как False. Это позволяет держать форму открытой при работе с документом и при необходимости вставлять нужные элементы из открытого списка.

Прежде, чем продолжить разговор о работе с этой формой, давайте займемся операцией добавления элементов в наш буфер. Вот как реализуется копирование выделенных объектов документа Word в наш множественный буфер. Приведу текст соответствующего макроса:

Public Sub CopyMult() 'Этот макрос копирует выделенный объект в множественный буфер MultBuffer.Add Selection.Range End Sub

Листинг 2.6.

Как видите, в макросе копирования элементов в буфер для добавления элементов в коллекцию, используется метод Add, вся задача выполняется одним оператором и не требует особых пояснений. Заметьте, в коллекцию полностью добавляется выделенный объект, а не его текст или другие компоненты.

Конечно, в этот же момент можно было бы создавать и соответствующий элемент списка нашей формы. Но разумнее это делать в другом месте - в обработчике события, возникающего при активизации формы. Действительно, если представить, что форма уже открыта и расположена на экране, то программное добавление нового элемента в ее список не будет отображаться, пока форма не будет перерисована. Раз так, то целесообразнее каждый раз при активизации формы (появлении ее на экране) создавать список на основе текущего состояния множественного буфера - коллекции MultBuffer. Вот как выглядит для формы написанный мной обработчик события Activate, решающий задачу создания элементов списка формы. Естественно, что список создается на основе анализа состояния буфера:




Инструментальные кнопки класса ComboBox могут быть одного из трех типов, задавая окно редактирования, выпадающий список и список с окном редактирования. Кнопкой типа DropDown - выпадающий список можно воспользоваться для реализации множественного буфера. Вместо того, чтобы показывать список элементов буфера в отдельной форме, во многих случаях предпочтительнее иметь в меню кнопку типа DropDown, при работе с которой раскрывается список, отображающий элементы буфера.

Заметьте, этот прием может быть полезен не только в данном конкретном примере, но и во многих случаях, когда приходится предъявлять пользователю некоторый список для того, чтобы он сделал в нем свой выбор. Кнопка меню, конечно же, компактнее, чем отдельная открывающаяся форма. Именно по этой причине такой способ работы с множественным буфером может быть предпочтительнее.

Хочу обратить Ваше внимание, что стандартная реализация фактически сочетает оба эти способа. В стандартной реализации буфер обычно появляется в виде плавающей формы, но когда окно формы, являющееся стыковочным окном, "причаливает" к одному из краев экрана, то форма превращается в обычную инструментальную панель, и элементы буфера отображаются уже в списке кнопки типа Dropdown. Лично я предпочитаю при работе со стандартным буфером представлять его в виде инструментальной панели, но это, конечно, дело вкуса. Что же касается собственной реализации, то я предпочел разделить оба эти способа.

Перейдем теперь к рассмотрению деталей реализации. Замечу, что представление самого буфера в виде коллекции остается неизменным в обеих реализациях. Теперь только вместо формы появится инструментальная панель с соответствующими кнопками. Наряду с кнопкой типа DropDown, которая будет реализовывать операцию вставки элемента буфера, на инструментальной панели будут расположены и обычные командные кнопки, реализующие другие операции над буфером. Кнопку DropDown необходимо создать программно. Конечно, программно можно создать и саму панель, и все кнопки, расположенные на ней. Но я предпочел сочетать работу руками и программную работу. Вот как выглядит созданная инструментальная панель MultBufferPanel:


Рис. 2.3.  Панель MultBufferPanel с кнопкой типа DropDown

Две кнопки в первой группе RangeShape и PasteMult позволяют работать с множественным буфером, основанным на первой его реализации. Вторая группа кнопок предназначена для работы с буфером, основанным на втором способе реализации. Кнопка Copy1Mult позволяет копировать выделенный объект в документе Word в буфер, основанный на рассматриваемой нами DropDown реализации. Вторая кнопка, созданная программно, имеет тип DropDown и используется для выбора и вставки нужного элемента буфера в позицию, заданную курсором. Кнопка DelAll предназначена для чистки буфера, а кнопка InsertAll для вставки всех элементов буфера в позицию, заданную курсором. Заметьте, иногда такая операция бывает полезной. Также как и в стандартной реализации, отсутствует операция, позволяющая удалять единственный выбранный элемент буфера. Причина этого понятна, - выбор элемента в списке кнопки однозначно определяет и операцию, выполняемую над этим элементом. Такой операцией является операция вставки выбранного элемента. Для удаления элемента потребовалось бы иметь еще одну кнопку типа DropDown.

Все кнопки на панели MultBufferPanel можно создать руками, что я и делал. Единственным исключением является кнопка DropDown, которую нужно создавать программно. Рассмотрим, как это делается. Приведу сейчас тексты всех используемых мной процедур:






Private Sub UserForm_Activate() Dim Txt As String NumElem = 0 For Each Elem In MultBuffer 'Анализ типа элемента буфера и создание элемента списка If Elem.Characters.Count = 1 Then 'Это объект Shape, InlineShape, 'специальный или однобуквенный символ! NumElem = NumElem + 1 Txt = "Object" & NumElem Else: Txt = Left(Elem.Text, 40) End If 'Добавление элемента в список формы ListBox1.AddItem Txt Next Elem

End Sub

Листинг 2.7.

(html, txt)

В цикле по объектам коллекции, составляющим буфер, анализируется их тип, и создаются текстовые элементы, представляющие элементы списка нашей формы. Заметьте, я достаточно просто расправляюсь с проблемой распознавания типа объекта, хранящегося в буфере. Для распознавания я использую следующий факт, - для всех рисованных объектов, объектов WordArt и подобных им объектов документа Word, свойство текст задается одним специальным символом. Поэтому я применяю следующее правило, - все объекты буфера, для которых свойство Characters возвращает коллекцию символов, содержащую ровно один символ, относятся к нетекстовым объектам или не могут, я полагаю, быть распознанными пользователем по этому символу. Поэтому такие объекты должны отображаться в списке словом "Объект" с соответствующим номером. Под это определение подпадают объекты Shape и InlineShape, специальные символы и, конечно, просто однобуквенные символы. Конечно, можно было бы предусмотреть более сложный анализ, но и принятое решение представляется вполне разумным и вполне удовлетворительно, как мне кажется, на практике. Некоторое сомнение может возникать в тех случаях, когда действительно копируются однобуквенные символы, но, заметьте, специальные символы целесообразно считать объектами, а простые символы вряд ли стоить копировать в множественный буфер. Далее я все-таки покажу, как можно было бы более детально проанализировать тип объекта, хранящегося в буфере.

Итак, задача создания буфера и списка, отражающего его элементы, решена полностью. Давайте теперь рассмотрим работу по вставке элементов из буфера и другие операции, реализованные над этими элементами. Прежде всего, замечу, что, как обычно, я спроектировал специальную инструментальную панель "MultBufferPanel" и расположил на ней две командные кнопки: "CopyMult" и "PasteMult". В ответ на нажатие первой кнопки вызывается уже приведенный одноименный макрос "CopyMult". В обработчике события нажатия второй кнопки вызывается макрос "PasteMult". Текст его очень прост:



Public Sub PasteMult() 'Показывает форму с элементами буфера BufferForm.Show End Sub

Листинг 2.8.

(html, txt)

Заметьте, что при открытии формы возникает событие Activate, а посему будет вызван обработчик этого события, что приведет к инициализации списка формы, так что в открывшейся форме будет показан список элементов, отражающих текущее состояние буфера. Ввиду немодального характера формы она будет оставаться на экране в процессе работы пользователя с документом до тех пор, пока пользователь не сочтет нужным закрыть ее. В любой момент пользователь может выполнять операции над буфером, заданные командными кнопками формы. Выбрав некоторый элемент из списка формы, и нажав кнопку "Вставить элемент", пользователь получает возможность вставить выбранный элемент в позицию, указанную курсором. Вот текст соответствующих макросов, решающих эту задачу:

Листинг 2.9.

(html, txt)

Несколько слов о том, как реализована вставка. Вначале я определяю, какой элемент списка выбран, что позволяет определить индекс элемента буфера (коллекции), который должен быть вставлен в позицию курсора. На этом этапе также приходится анализировать тип вставляемого объекта, поскольку объекты Shape не могут быть вставлены в позицию, заданную курсором. Более того, они не могут быть скопированы стандартным способом через буфер, для них приходится применять метод Duplicate, специально предназначенный для этих целей. Заметьте, в данной ситуации необходимо более корректно анализировать тип объекта, находящегося в буфере. Для распознавания того, что объект буфера принадлежит классу Shape, я вызываю метод RangeShape, возвращающий коллекцию Shapes объекта Range. Если эта коллекция не пуста, то имеем дело с объектом Shape.

Для остальных объектов, не принадлежащих классу Shape, вставка выполняется через стандартный буфер, о чем я уже говорил в предыдущем параграфе, где рассматривалась работа с одиночным буфером.

В стандартной реализации помимо вставки над буфером определены и другие операции, в частности, операция удаления элементов. Удалить можно одновременно все элементы буфера, либо удаление происходит по принципу стека. Поскольку множественный буфер имеет фиксированный размер, то при добавлении нового элемента в уже заполненный буфер, удаляется первый из его элементов, освобождая место вновь пришедшему. Наш буфер является безразмерным, поэтому нет необходимости в реализации стекового принципа удаления элементов. Но иметь возможность по своему выбору удалять уже не нужные элементы и в этом случае целесообразно. Вот макросы, решающие эту задачу:



Листинг 2.10.

(html, txt)

Заметьте, выбранный элемент удаляется как из списка, так и из буфера

Кнопка "Удалить все" позволяет полностью очистить буфер и, соответственно, список формы. По сути, макрос, решающий эту задачу, не многим отличается от макроса, удаляющего один элемент:

Private Sub CommandButton3_Click() ClearAll End Sub

Public Sub ClearAll() 'Удаляет элементы из буфера (коллекции) Dim i As Integer For i = 1 To MultBuffer.Count MultBuffer.Remove (1) Next i 'Удаляет элементы из списка For i = 1 To BufferForm.ListBox1.ListCount BufferForm.ListBox1.RemoveItem (0) Next i BufferForm.Hide End Sub

Листинг 2.11.

(html, txt)

На этом закончим рассмотрение реализации множественного буфера, использующего форму для отображения элементов буфера. Рассмотрим другой возможный вариант реализации этой задачи.

on_load_lecture()

Дальше »

  Если Вы заметили ошибку - сообщите нам.  
Страницы:

« |

1

|

2

|

3

|

4

|

5

|

6

|

7

|

вопросы | »

|

для печати и PDA

Курсы | Учебные программы | Учебники | Новости | Форум | Помощь


Телефон: +7 (495) 253-9312, 253-9313, факс: +7 (495) 253-9310, email: info@intuit.ru

© 2003-2007, INTUIT.ru::Интернет-Университет Информационных Технологий - дистанционное образование



Листинг 2.12.

(html, txt)

Основной здесь является процедура CreateComboPanel, при запуске которой будет создана панель с именем MultBufferPanel, если она не была уже создана ранее, и на эту панель будет помещена кнопка типа Dropdown. Обратите внимание, что в этой процедуре задается обработчик события, которому я дал имя DropdownReaction, вызываемый в ответ на выбор пользователем элемента списка. Этот обработчик и будет выполнять основную операцию по вставке элемента буфера в позицию заданную курсором. Текст его приведу чуть позже, а сейчас замечу, что саму работу по добавлению данной кнопки на панель выполняет функция AddCustomCombo, которая не только создает кнопку, но и присваивает ей заголовок (Caption) "DropdownItem".

Нам осталось рассмотреть процедуры, выполняющие основные операции над элементами буфера. Начну с копирования выделенного объекта в буфер. Вот текст соответствующего макроса:

Public Sub Copy1Mult() 'Этот макрос копирует выделенный объект в множественный буфер MultBuffer.Add Selection.Range 'Одновременно создается список элемента ComboBox 'на панели MultBufferPanel Dim Txt As String Dim Panel As CommandBar Dim Ctrl As CommandBarComboBox If Selection.Range.Characters.Count = 1 Then NumElem = NumElem + 1 Txt = "Object" & NumElem Else: Txt = Left(Selection.Range.Text, 40) End If Set Panel = CommandBars("MultBufferPanel") Set Ctrl = Panel.Controls("DropdownItem") 'Добавление элемента списка Ctrl.AddItem Txt End Sub

Листинг 2.13.

(html, txt)

Заметьте, в отличие от макроса RangeShape в данной реализации не только добавляется элемент в буфер, но его текстовый образ тут же динамически добавляется и в список кнопки DropdownItem.

Как я уже говорил, операция вставки элемента выполняется при выборе элемента из раскрывающегося списка кнопки DropdownItem. Имя макроса - обработчика этого события уже задано в момент создания кнопки. Так что мне остается только привести его текст:

Public Sub DropdownReaction() 'Обработчик кнопки меню - DropDown ComboBox Dim Ctrl As CommandBarComboBox Set Ctrl = CommandBars.ActionControl



Set Elem = MultBuffer(Ctrl.ListIndex) If Elem.ShapeRange.Count > 0 Then 'Это объект Shape - он не привязан ' к фиксированному положению, не может быть 'помещен в точку, заданную курсором и копируется 'специальным методом Duplicate Elem.ShapeRange(1).Duplicate Else Elem.Copy Selection.PasteSpecial End If End Sub

Листинг 2.14.

(html, txt)

Обратите внимание, я использую свойство ListIndex, чтобы понять, какой элемент был выбран пользователем из списка. Остальные детали этой процедуры подробно описаны при рассмотрении предыдущей реализации.

Макрос DelAll выполняет чистку буфера и списка:

Public Sub DelAll() 'Удаляет элементы из буфера и DropDown списка на панели Dim i As Integer Dim Panel As CommandBar Dim Ctrl As CommandBarComboBox 'Удаляет элементы из буфера (коллекции) For i = 1 To MultBuffer.Count MultBuffer.Remove (1) Next i 'Удаление из списка Set Panel = CommandBars("MultBufferPanel") Set Ctrl = Panel.Controls("DropdownItem") For i = 1 To Ctrl.ListCount Ctrl.RemoveItem (1) Next i End Sub

Листинг 2.15.

(html, txt)

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

Public Sub InsertAll() 'Вставка всех элементов из буфера в точку, 'заданную курсором. Shape-элементы вставляются, как обычно, 'не привязанные к фиксированной позиции. For Each Elem In MultBuffer If Elem.ShapeRange.Count > 0 Then 'Это объект Shape - он не привязан 'к фиксированному положению, не может быть 'помещен в точку, заданную курсором и копируется 'специальным методом Duplicate Elem.ShapeRange(1).Duplicate Else Elem.Copy Selection.PasteSpecial End If Next Elem End Sub

Листинг 2.16.

(html, txt)

На этом я завершу рассмотрение способов создания буфера.



Private Sub UserForm_Activate() Dim Txt As String NumElem = 0 For Each Elem In MultBuffer 'Анализ типа элемента буфера и создание элемента списка If Elem.Characters.Count = 1 Then 'Это объект Shape, InlineShape, 'специальный или однобуквенный символ! NumElem = NumElem + 1 Txt = "Object" & NumElem Else: Txt = Left(Elem.Text, 40) End If 'Добавление элемента в список формы ListBox1.AddItem Txt Next Elem

End Sub

Листинг 2.7.

В цикле по объектам коллекции, составляющим буфер, анализируется их тип, и создаются текстовые элементы, представляющие элементы списка нашей формы. Заметьте, я достаточно просто расправляюсь с проблемой распознавания типа объекта, хранящегося в буфере. Для распознавания я использую следующий факт, - для всех рисованных объектов, объектов WordArt и подобных им объектов документа Word, свойство текст задается одним специальным символом. Поэтому я применяю следующее правило, - все объекты буфера, для которых свойство Characters возвращает коллекцию символов, содержащую ровно один символ, относятся к нетекстовым объектам или не могут, я полагаю, быть распознанными пользователем по этому символу. Поэтому такие объекты должны отображаться в списке словом "Объект" с соответствующим номером. Под это определение подпадают объекты Shape и InlineShape, специальные символы и, конечно, просто однобуквенные символы. Конечно, можно было бы предусмотреть более сложный анализ, но и принятое решение представляется вполне разумным и вполне удовлетворительно, как мне кажется, на практике. Некоторое сомнение может возникать в тех случаях, когда действительно копируются однобуквенные символы, но, заметьте, специальные символы целесообразно считать объектами, а простые символы вряд ли стоить копировать в множественный буфер. Далее я все-таки покажу, как можно было бы более детально проанализировать тип объекта, хранящегося в буфере.

Итак, задача создания буфера и списка, отражающего его элементы, решена полностью. Давайте теперь рассмотрим работу по вставке элементов из буфера и другие операции, реализованные над этими элементами. Прежде всего, замечу, что, как обычно, я спроектировал специальную инструментальную панель "MultBufferPanel" и расположил на ней две командные кнопки: "CopyMult" и "PasteMult". В ответ на нажатие первой кнопки вызывается уже приведенный одноименный макрос "CopyMult". В обработчике события нажатия второй кнопки вызывается макрос "PasteMult". Текст его очень прост:



Public Sub PasteMult() 'Показывает форму с элементами буфера BufferForm.Show End Sub

Листинг 2.8.

Заметьте, что при открытии формы возникает событие Activate, а посему будет вызван обработчик этого события, что приведет к инициализации списка формы, так что в открывшейся форме будет показан список элементов, отражающих текущее состояние буфера. Ввиду немодального характера формы она будет оставаться на экране в процессе работы пользователя с документом до тех пор, пока пользователь не сочтет нужным закрыть ее. В любой момент пользователь может выполнять операции над буфером, заданные командными кнопками формы. Выбрав некоторый элемент из списка формы, и нажав кнопку "Вставить элемент", пользователь получает возможность вставить выбранный элемент в позицию, указанную курсором. Вот текст соответствующих макросов, решающих эту задачу:

Private Sub CommandButton1_Click() InsertElem End Sub

Public Sub InsertElem() 'Вставляет выбранный элемент буфера 'в точку, заданную курсором Dim RowIndex As Integer Dim Sel As Boolean Sel = False With BufferForm.ListBox1 For RowIndex = 0 To .ListCount - 1 If .Selected(RowIndex) Then Sel = True Set Elem = MultBuffer(RowIndex + 1) If Elem.ShapeRange.Count > 0 Then 'Это объект Shape - он не привязан 'к фиксированному положению, не может быть 'помещен в точку, заданную курсором и копируется 'специальным методом Duplicate Elem.ShapeRange(1).Duplicate Else Elem.Copy Selection.PasteSpecial End If Exit For End If Next RowIndex If Not Sel Then MsgBox ("Для вставки выберете элемент из списка!") End If End With End Sub

Листинг 2.9.

Несколько слов о том, как реализована вставка. Вначале я определяю, какой элемент списка выбран, что позволяет определить индекс элемента буфера (коллекции), который должен быть вставлен в позицию курсора. На этом этапе также приходится анализировать тип вставляемого объекта, поскольку объекты Shape не могут быть вставлены в позицию, заданную курсором. Более того, они не могут быть скопированы стандартным способом через буфер, для них приходится применять метод Duplicate, специально предназначенный для этих целей. Заметьте, в данной ситуации необходимо более корректно анализировать тип объекта, находящегося в буфере. Для распознавания того, что объект буфера принадлежит классу Shape, я вызываю метод RangeShape, возвращающий коллекцию Shapes объекта Range. Если эта коллекция не пуста, то имеем дело с объектом Shape.

Для остальных объектов, не принадлежащих классу Shape, вставка выполняется через стандартный буфер, о чем я уже говорил в предыдущем параграфе, где рассматривалась работа с одиночным буфером.

В стандартной реализации помимо вставки над буфером определены и другие операции, в частности, операция удаления элементов. Удалить можно одновременно все элементы буфера, либо удаление происходит по принципу стека. Поскольку множественный буфер имеет фиксированный размер, то при добавлении нового элемента в уже заполненный буфер, удаляется первый из его элементов, освобождая место вновь пришедшему. Наш буфер является безразмерным, поэтому нет необходимости в реализации стекового принципа удаления элементов. Но иметь возможность по своему выбору удалять уже не нужные элементы и в этом случае целесообразно. Вот макросы, решающие эту задачу:



Private Sub CommandButton2_Click() DelElem End Sub

Public Sub DelElem() 'Удаляет выбранный элемент буфера

Dim RowIndex As Integer Dim Sel As Boolean Sel = False With BufferForm.ListBox1 For RowIndex = 0 To .ListCount - 1 If .Selected(RowIndex) Then Sel = True MultBuffer.Remove (RowIndex + 1) .RemoveItem RowIndex Exit For End If RowIndex = RowIndex + 1 Next RowIndex If Not Sel Then MsgBox ("Для удаления выберете элемент из списка!") End If End With End Sub

Листинг 2.10.

Заметьте, выбранный элемент удаляется как из списка, так и из буфера

Кнопка "Удалить все" позволяет полностью очистить буфер и, соответственно, список формы. По сути, макрос, решающий эту задачу, не многим отличается от макроса, удаляющего один элемент:

Private Sub CommandButton3_Click() ClearAll End Sub

Public Sub ClearAll() 'Удаляет элементы из буфера (коллекции) Dim i As Integer For i = 1 To MultBuffer.Count MultBuffer.Remove (1) Next i 'Удаляет элементы из списка For i = 1 To BufferForm.ListBox1.ListCount BufferForm.ListBox1.RemoveItem (0) Next i BufferForm.Hide End Sub

Листинг 2.11.

На этом закончим рассмотрение реализации множественного буфера, использующего форму для отображения элементов буфера. Рассмотрим другой возможный вариант реализации этой задачи.



Public Function ExistCommandBar( PanelName As String) As Boolean 'Возвращает True, если в коллекции CommandBars 'существует панель с именем PanelName Dim bar As CommandBar, Exist As Boolean Exist = False For Each bar In CommandBars If bar.name = PanelName Or bar.NameLocal = PanelName Then Exist = True Exit For End If Next bar ExistCommandBar = Exist End Function

Public Sub AddPanel(PanelName As String) 'Добавляет и делает видимой панель с именем Panelname 'в коллекцию Commandbars 'Панель расположена вверху документа, 'не заменяет главное меню и не является временной If Not ExistCommandBar(PanelName) Then Call CommandBars.Add(name:=PanelName, Position:=msoBarTop, _ MenuBar:=False, Temporary:=False) End If CommandBars(PanelName).Enabled = True CommandBars(PanelName).Visible = True

End Sub

Public Sub CreateComboPanel() 'Создание панели с элементами класса CommandBarCombobox 'Создаем панель Dim Panel As CommandBar Dim Ctrl As CommandBarComboBox AddPanel ("MultBufferPanel") Set Panel = CommandBars("MultBufferPanel") 'Добавляем на панель Combo кнопку типа DropDown - выпадающий список Set Ctrl = AddCustomCombo(Panel, "DropdownItem", msoControlDropdown) 'Указываем обработчик события при выборе элемента списка Ctrl.OnAction = "DropdownReaction" End Sub Public Function ExistControl(Panel As CommandBar, _ Capt As String) As Boolean 'Возвращает True, если в коллекции Controls ' панели с именем Panel существует элемент с заголовком capt Dim Ctrl As CommandBarControl, Exist As Boolean Exist = False For Each Ctrl In Panel.Controls If Ctrl.Caption = Capt Then Exist = True Exit For End If Next Ctrl ExistControl = Exist End Function

Public Function AddCustomCombo(Panel As CommandBar, _ name As String, tip As Variant) As CommandBarComboBox 'Добавляет на панель элемент, тип которого задан параметром tip 'возвращая объект CommandBarComboBox в качестве результата Dim Ctrl As CommandBarComboBox If Not ExistControl(Panel, name) Then Set Ctrl = Panel.Controls.Add(Type:=tip) Ctrl.Caption = name End If Set AddCustomCombo = Panel.Controls(name) End Function



Листинг 2.12.

Основной здесь является процедура CreateComboPanel, при запуске которой будет создана панель с именем MultBufferPanel, если она не была уже создана ранее, и на эту панель будет помещена кнопка типа Dropdown. Обратите внимание, что в этой процедуре задается обработчик события, которому я дал имя DropdownReaction, вызываемый в ответ на выбор пользователем элемента списка. Этот обработчик и будет выполнять основную операцию по вставке элемента буфера в позицию заданную курсором. Текст его приведу чуть позже, а сейчас замечу, что саму работу по добавлению данной кнопки на панель выполняет функция AddCustomCombo, которая не только создает кнопку, но и присваивает ей заголовок (Caption) "DropdownItem".

Нам осталось рассмотреть процедуры, выполняющие основные операции над элементами буфера. Начну с копирования выделенного объекта в буфер. Вот текст соответствующего макроса:

Public Sub Copy1Mult() 'Этот макрос копирует выделенный объект в множественный буфер MultBuffer.Add Selection.Range 'Одновременно создается список элемента ComboBox 'на панели MultBufferPanel Dim Txt As String Dim Panel As CommandBar Dim Ctrl As CommandBarComboBox If Selection.Range.Characters.Count = 1 Then NumElem = NumElem + 1 Txt = "Object" & NumElem Else: Txt = Left(Selection.Range.Text, 40) End If Set Panel = CommandBars("MultBufferPanel") Set Ctrl = Panel.Controls("DropdownItem") 'Добавление элемента списка Ctrl.AddItem Txt End Sub

Листинг 2.13.

Заметьте, в отличие от макроса RangeShape в данной реализации не только добавляется элемент в буфер, но его текстовый образ тут же динамически добавляется и в список кнопки DropdownItem.

Как я уже говорил, операция вставки элемента выполняется при выборе элемента из раскрывающегося списка кнопки DropdownItem. Имя макроса - обработчика этого события уже задано в момент создания кнопки. Так что мне остается только привести его текст:

Public Sub DropdownReaction() 'Обработчик кнопки меню - DropDown ComboBox Dim Ctrl As CommandBarComboBox Set Ctrl = CommandBars.ActionControl



Set Elem = MultBuffer(Ctrl.ListIndex) If Elem.ShapeRange.Count > 0 Then 'Это объект Shape - он не привязан ' к фиксированному положению, не может быть 'помещен в точку, заданную курсором и копируется 'специальным методом Duplicate Elem.ShapeRange(1).Duplicate Else Elem.Copy Selection.PasteSpecial End If End Sub

Листинг 2.14.

Обратите внимание, я использую свойство ListIndex, чтобы понять, какой элемент был выбран пользователем из списка. Остальные детали этой процедуры подробно описаны при рассмотрении предыдущей реализации.

Макрос DelAll выполняет чистку буфера и списка:

Public Sub DelAll() 'Удаляет элементы из буфера и DropDown списка на панели Dim i As Integer Dim Panel As CommandBar Dim Ctrl As CommandBarComboBox 'Удаляет элементы из буфера (коллекции) For i = 1 To MultBuffer.Count MultBuffer.Remove (1) Next i 'Удаление из списка Set Panel = CommandBars("MultBufferPanel") Set Ctrl = Panel.Controls("DropdownItem") For i = 1 To Ctrl.ListCount Ctrl.RemoveItem (1) Next i End Sub

Листинг 2.15.

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

Public Sub InsertAll() 'Вставка всех элементов из буфера в точку, 'заданную курсором. Shape-элементы вставляются, как обычно, 'не привязанные к фиксированной позиции. For Each Elem In MultBuffer If Elem.ShapeRange.Count > 0 Then 'Это объект Shape - он не привязан 'к фиксированному положению, не может быть 'помещен в точку, заданную курсором и копируется 'специальным методом Duplicate Elem.ShapeRange(1).Duplicate Else Elem.Copy Selection.PasteSpecial End If Next Elem End Sub

Листинг 2.16.

На этом я завершу рассмотрение способов создания буфера.


Содержание раздела