Как выстраивать стандартные элементы управления на ленте в желаемом порядке я уже рассказывал.
Как добавить на ленту собственные элементы управления и научить их откликаться на действия пользователя я буду рассказывать в серии заметок так, чтобы это не вызывало трудностей у новичков.
Чтобы пользовательскую ленту научить откликаться на действия пользователя, мало просто задать расположение элементов управления. Необходимо, используя язык VBA, прописать действия, выполняемые тем или иным элементом управления, а также внутри XML-кода указать, что работа того или иного элемента управления контролируется извне.
Начнём с двух, на мой взгляд самых простых элементов управления: кнопки (Button) и флажка(CheckBox).
Разберём простенький пример. Поместим на ленту новую вкладку с именем «Тест», в ней создадим группу с тем же именем. В группе разместим флажок (checkbox) и кнопку. При изменении состояния флажка будет изменяться активность кнопки, а также текст флажка, отображающий количество нажатий на нём и его состояние. Кнопкой просто будем устанавливать или снимать флажок.
XML-схема пользовательского интерфейса будет такой:
Процесс создания XML-кода с помощью RXE уже объяснялся, поэтому остановлюсь только на отличиях. XML-строки, соответствующие кнопке и флажку, добавляются кнопками
и
. Атрибуты можно писать вручную, а можно, и даже нужно, вводить, используя возможности RXE. В последней на сегодняшний день версии за ввод разнообразных атрибутов отвечают три выпадающих списка, расположенных над основным полем редактирования.
Код отличается от приведённых раньше прежде всего тем, что в нём я не задаю явно текст, отображаемый на элементе управления. Вместо этого прописан набор атрибутов, начинающихся со слова get. По порядку, что они означают:
Кроме этих атрибутов, имеется ещё один — onAction, который определяет имя процедуры, выполняющейся при клике мышью на элементе управления. Также у элемента пользовательского интерфейса, определяемого тегом customUI, я задал атрибут onLoad, который, как наверное уже понятно, определяет процедуру, выполняющуюся при загрузке пользовательского интерфейса.
Имена процедур, задаваемые атрибутам, могут быть совершенно произвольными, но, желательно, понятными разработчику :)
Схему создали. Сохраняем документ и открываем в Word. При этом получим сообщение:

Оно вызвано тем, что в XML-схеме задано значение атрибута щnLoad, а процедуры с соответствующим именем ещё нет. Поэтому следует прописать эту, а также остальные процедуры, указанные в XML-схеме.
Открываем редактор VBA и вставляем в него такой код:
Пугаться не нужно, разберём всё по кирпичикам.
После введения кода. Документ нужно сохранить и повторно открыть. Если всё было сделано правильно, то выглядеть это будет так:
Сразу после открытия

Первый клик по флажку, чтобы активировать кнопку.

Нажатие на кнопку, чтобы изменить состояние флажка. Событие onAction для флажка в этом случае не вызывается! Поэтому кнопка остаётся активной.

Готовый пример файла
Как добавить на ленту собственные элементы управления и научить их откликаться на действия пользователя я буду рассказывать в серии заметок так, чтобы это не вызывало трудностей у новичков.
Чтобы пользовательскую ленту научить откликаться на действия пользователя, мало просто задать расположение элементов управления. Необходимо, используя язык VBA, прописать действия, выполняемые тем или иным элементом управления, а также внутри XML-кода указать, что работа того или иного элемента управления контролируется извне.
Начнём с двух, на мой взгляд самых простых элементов управления: кнопки (Button) и флажка(CheckBox).
Разберём простенький пример. Поместим на ленту новую вкладку с именем «Тест», в ней создадим группу с тем же именем. В группе разместим флажок (checkbox) и кнопку. При изменении состояния флажка будет изменяться активность кнопки, а также текст флажка, отображающий количество нажатий на нём и его состояние. Кнопкой просто будем устанавливать или снимать флажок.
XML-схема пользовательского интерфейса будет такой:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="RibbonLoading"> <ribbon startFromScratch="false"> <tabs> <tab id="Tab1" label="Тест"> <group id="Tab1_gr1" label="Тест"> <checkBox id="chb1" getLabel="getLabel" getEnabled="getEnabled" getPressed="getPressed" onAction="onAction" /> <button id="btn1" getLabel="getLabel" getEnabled="getEnabled" onAction="btnOnAction" /> </group> </tab> </tabs> </ribbon> </customUI>
Процесс создания XML-кода с помощью RXE уже объяснялся, поэтому остановлюсь только на отличиях. XML-строки, соответствующие кнопке и флажку, добавляются кнопками
Код отличается от приведённых раньше прежде всего тем, что в нём я не задаю явно текст, отображаемый на элементе управления. Вместо этого прописан набор атрибутов, начинающихся со слова get. По порядку, что они означают:
- getLabel — атрибут, определяющий имя процедуры, которая задаёт текст элемента управления;
- getEnabled — атрибут, определяющий имя процедуры, устанавливающей активность элемента управления;
- getPressed — атрибут, определяющий имя процедуры, устанавливающей состояние элемента управления. Этот атрибут определён только для элементов управления, имеющих фиксированные состояния: checkbox и togglebutton.
Кроме этих атрибутов, имеется ещё один — onAction, который определяет имя процедуры, выполняющейся при клике мышью на элементе управления. Также у элемента пользовательского интерфейса, определяемого тегом customUI, я задал атрибут onLoad, который, как наверное уже понятно, определяет процедуру, выполняющуюся при загрузке пользовательского интерфейса.
Имена процедур, задаваемые атрибутам, могут быть совершенно произвольными, но, желательно, понятными разработчику :)
Схему создали. Сохраняем документ и открываем в Word. При этом получим сообщение:

Оно вызвано тем, что в XML-схеме задано значение атрибута щnLoad, а процедуры с соответствующим именем ещё нет. Поэтому следует прописать эту, а также остальные процедуры, указанные в XML-схеме.
Открываем редактор VBA и вставляем в него такой код:
Option Explicit Sub RibbonLoading(ribbon As IRibbonUI) End Sub Sub getLabel(control As IRibbonControl, ByRef label) End Sub Sub getEnabled(control As IRibbonControl, ByRef enabled) End Sub Sub getPressed(control As IRibbonControl, ByRef pressed) End Sub Sub onAction(control As IRibbonControl, pressed As Boolean) End Sub Sub btnOnAction(control As IRibbonControl) End SubЭто "тела" процедур, имена которых были определены в XML-схеме. Наполним эти процедуры содержимым:
Option Explicit 'Глобальные переменые, необходимые для передачи состояния элементов управления _ между процедурами Dim chb1_pressed As Boolean 'Состояние флажка Dim chb1_enabled As Boolean 'Активность флажка Dim btn1_enabled As Boolean 'Активность кнопки Dim myRibbon As IRibbonUI 'Пользовательский интерфейс Dim PressCounter As Integer 'Счётчик нажатий Sub RibbonLoading(ribbon As IRibbonUI) ' 'Загрузка ленты ' 'Задаём состояние флажка и кнопки chb1_enabled = True btn1_enabled = chb1_pressed 'Запоминаем наш интерфейс в переменную Set myRibbon = ribbon End Sub Sub getEnabled(control As IRibbonControl, ByRef returnedVal) ' 'Задаём активность элемента управления ' 'Определяем элемент управления, вызвавший процедуру Select Case control.ID Case "chb1" 'Устанавливаем активность флажка returnedVal = chb1_enabled Case "btn1" 'Устанавливаем активность кнопки returnedVal = btn1_enabled End Select End Sub Sub getPressed(control As IRibbonControl, ByRef returnedVal) ' 'Задаём состояние элемента управления ' returnedVal = chb1_pressed End Sub Sub getLabel(control As IRibbonControl, ByRef returnedVal) ' 'Задаём текст элемента управления ' 'Определяем какой элемент управления вызвал эту процедуру Select Case control.ID Case "chb1" 'Задаём текст флажка returnedVal = "Нажат " & PressCounter & " раз. Текущее состояние: " & IIf(chb1_pressed, "установлен", "снят") Case "btn1" 'Задаём текст кнопки returnedVal = "Кнопка изменения состояния флажка" End Select End Sub Sub onAction(control As IRibbonControl, pressed As Boolean) ' 'Клик по флажку ' 'Запоминаем состояние флажка в глобальные переменные chb1_pressed = pressed btn1_enabled = pressed PressCounter = PressCounter + 1 'Инкремент счётчика 'Обновляем элементы управления myRibbon.InvalidateControl control.ID 'флажок, вызвавший процедуру myRibbon.InvalidateControl "btn1" 'кнопка End Sub Sub btnOnAction(control As IRibbonControl) ' 'Нажатие на кнопку ' chb1_pressed = Not chb1_pressed 'Изменяем значение переменной состояния флажка на противоположное PressCounter = PressCounter + 1 'Инкремент счётчика myRibbon.InvalidateControl "chb1" 'Обновляем флажок End Sub
Пугаться не нужно, разберём всё по кирпичикам.
- Кирпичик №1. Объявление глобальных переменных
'Глобальные переменые, необходимые для передачи состояния элементов управления _
В самом начале кода объявляем глобальные переменные, используемые для взаимодействия с элементами управления на ленте и с самой лентой. С помощью этих переменных мы сможем объяснить флажку, какой текст ему нужно иметь, в какое состояние его поставил кнопка и т.д.
между процедурами
Dim chb1_pressed As Boolean 'Состояние флажка Dim chb1_enabled As Boolean 'Активность флажка Dim btn1_enabled As Boolean 'Активность кнопки Dim myRibbon As IRibbonUI 'Пользовательский интерфейс Dim PressCounter As Integer 'Счётчик нажатий - Кирпичик №2. Загрузка пользовательского интерфейса. RibbonLoading
Sub RibbonLoading(ribbon As IRibbonUI) ' 'Загрузка ленты ' 'Задаём состояние флажка и кнопки chb1_enabled = True btn1_enabled = chb1_pressed 'Запоминаем наш интерфейс в переменную Set myRibbon = ribbon End Sub
Эта процедура выполняется самой первой при загрузке пользовательского интерфейса. Как видно, она вызывается не пустой, а с параметром ribbon, содержащим ссылку на загружаемый интерфейс. В этой процедуре я устанавливаю значение переменных, определяющих активность кнопки и флажка, и запоминаю в свою переменную myRibbon ссылку на пользовательский интерфейс, чтобы обращаться к нему из других процедур. - Кирпичик №3. Определение активности элемента управления. getEnabled
Sub getEnabled(control As IRibbonControl, ByRef returnedVal) ' 'Задаём активность элемента управления ' 'Определяем элемент управления, вызвавший процедуру Select Case control.ID Case "chb1" 'Устанавливаем активность флажка returnedVal = chb1_enabled Case "btn1" 'Устанавливаем активность кнопки returnedVal = btn1_enabled End Select End Sub
После того, как лента загружена, начинается прорисовка элементов управления. Насколько я заметил, элементы управления прорисовываются сверху вниз и справа налево. При этом вызываются процедуры, заданные в атрибутах, начинающихся с get.
Эта процедура вызывается для каждого элемента управления, чтобы определить его активность. В качестве параметров процедуры передаётся сам элемент управления (control) и ссылка на свойство, которое у этого элемента нужно изменить. В данное процедуре таким свойством является Enabled, ссылка на которое передана в переменной returnedVal.
В данном случае внутри процедуры оператором Select…Case определяется какой элемент управления её вызвал и в переменную, содержащую ссылку на свойство, записывается значение глобальной переменной, определённой выше. Поскольку в процедуре RibbonLoading я уже задал значения переменным chb1_enabled и btn1_enabled (true и false соответственно), то флажок будет отображаться активным, а кнопка — неактивной. - Кирпичик №4. Установка состояния флажка. getPressed"
Sub getPressed(control As IRibbonControl, ByRef returnedVal) ' 'Задаём состояние элемента управления ' returnedVal = chb1_pressed End Sub
Это совсем просто, если вы «раскусили» предыдущий кирпичик. Состояние флажка определяется значением глобальной переменной chb1_pressed. Задать значение этой переменной можно где угодно. Поскольку до этого мы его ещё нигде не задавали, то оно равно false и, соответственно, флажок будет снят. В эту процедуру передаются те же параметры, что и в предыдущую, только под returnedVal уже подразумевается свойство Checked. Эта процедура будет вызываться только для флажка. - Кирпичик №5. Установка текста элемента управления. getLabel
Sub getLabel(control As IRibbonControl, ByRef returnedVal) ' 'Задаём текст элемента управления ' 'Определяем какой элемент управления вызвал эту процедуру Select Case control.ID Case "chb1" 'Задаём текст флажка returnedVal = "Нажат " & PressCounter & " раз. Текущее состояние: " & IIf(chb1_pressed, "установлен", "снят") Case "btn1" 'Задаём текст кнопки returnedVal = "Кнопка изменения состояния флажка" End Select End Sub
Процедура, аналогичная getEnabled, только returnedVal определяет текст, отображаемый на элементе управления. В этой процедуре также используется глобальная переменная chb1_pressed, чтобы правильно отображать информацию о состоянии флажка. - Кирпичик №6. Клик на флажке. onAction
Sub onAction(control As IRibbonControl, pressed As Boolean) ' 'Клик по флажку ' 'Запоминаем состояние флажка в глобальные переменные chb1_pressed = pressed btn1_enabled = pressed PressCounter = PressCounter + 1 'Инкремент счётчика 'Обновляем элементы управления myRibbon.InvalidateControl control.ID 'флажок, вызвавший процедуру myRibbon.InvalidateControl "btn1" 'кнопка End Sub
Эта процедура, вызывается, когда пользователь кликает по флажку. Первый параметр, который передаётся в этой процедуре, это всё тот же элемент управления, вызвавший её. Вторым параметром идёт состояние элемента управления после клика на нём. Именно с помощью этого второго параметра мы передаём в глобальные переменные информацию о состоянии элемента управления.
Важной частью этой процедуры являются строки, содержащие вызов метода InvalidateControl. Вызов этого метода обновляет состояние указанного элемента управления. При этом обновлении повторно вызываются все процедуры, описанные в атрибутах, начинающихся с get. В данном случае, обновляется флажок (с изменённым текстом) и кнопка (с изменённой активностью). - Кирпичик №7. Нажатие на кнопку. btnOnAction
Sub btnOnAction(control As IRibbonControl) ' 'Нажатие на кнопку ' chb1_pressed = Not chb1_pressed 'Изменяем значение переменной состояния флажка на противоположное PressCounter = PressCounter + 1 'Инкремент счётчика myRibbon.InvalidateControl "chb1" 'Обновляем флажок End Sub
Эта процедура совершенно прозрачна и, думаю, не требует пояснений.
После введения кода. Документ нужно сохранить и повторно открыть. Если всё было сделано правильно, то выглядеть это будет так:
Сразу после открытия

Первый клик по флажку, чтобы активировать кнопку.

Нажатие на кнопку, чтобы изменить состояние флажка. Событие onAction для флажка в этом случае не вызывается! Поэтому кнопка остаётся активной.

Готовый пример файла