Теперь мы уже почти профессионалы в программировании интерфейсов, и можем замахнуться аж на динамическое меню. Динамическое меню, как и динамические атрибуты, получает своё содержимое из функции обратного вызова. То есть, наша функция должна возвращать некий XML-код, который и будет формировать дочерние элементы меню.
Давайте сделаем ещё одну надстройку-демонстратор динамического меню. Создадим третий документ и откроем его в Ribbon XML Editor. Построим в нём следующий код:
В этом коде мы создаём на нашей вкладке третью группу, в которой размещаем обычное меню с тремя пунктами и динамическое меню, пункты которого мы будем получать с помощью функции «ВернутьДинамическоеМеню». Сгенерируем шаблоны функций обратного вызова и сохраним их в файле, как мы уже делали это ранее.
Кстати, если вы хотите изменить имя, предлагаемое по умолчанию, под которым сохраняются шаблоны функций, зайдите в настройки Ribbon XML Editor, и обратите внимание на окно в правом верхнем углу. Этот блок текста каждый раз помещается в начало сохраняемого файла, и вы можете отредактировать его по вашему усмотрению. В первой строке написано:
Attribute VB_Name = "RibbonCallbacks"
Мы можем поменять эту строку на:
Attribute VB_Name = "CustomUICallbacks"
и при сохранении файла нам будет предлагаться уже новое имя.
Итак, запустим документ на выполнение. Обычное меню уже работает, а для формирования пунктов динамического меню нам нужно открыть редактор Бейсика (Alt+F11) и загрузить в него модуль с сохранёнными нами ранее шаблонами функций обратного вызова.
Заполним шаблоны функций следующим кодом:
В первых трёх функциях мы просто выводим сообщение о нажатии того или иного пункта, а в последней — формируем пункты, которые должны будут вернуться из функции во время выполнения документа. Тут требуются небольшое пояснение.
Формируемые пункты возвращаются в динамическое меню не списком, а XML-структурой, объединенённой корневым элементом menu, имеющим тип CT_MenuRoot. Элемента этого типа нет в иерархии статических элементов. Но в справке Ribbon XML Editor среди приложений мы можем найти ссылку «Динамическое меню», нажав на которую, мы откроем страничку с описанием этого типа и дополнительными сведениями по нему.
Согласно справке, корневой элемент menu должен содержать атрибут xmlns с объявлением пространства имён, используемое нами в основном коде. Замечу, что несмотря на то, что ранее мы использовали этот атрибут только в корневом элементе customUI, теоретически его можно использовать в любом элементе интерфейса, хотя его и не будет среди предлагаемых вариантов в автодополнении ввиду редкости такого использования. В данном случае мы применяем его в элементе menu.
В функции «ВернутьДинамическоеМеню» мы присваиваем строковой переменной sXML сначала открывающий тег menu с атрибутом размера пунктов меню и объявлением пространства имён, затем добавляем туда коды перевода строки (vbCrLf), затем теги элементов пунктов меню с желаемыми атрибутами и, в завершение, присваиваем возвращаемой переменной содержимое полученной строки с добавлением закрывающего тега menu. Внутри строковых переменных знак кавычек делается сдвоенным, чтобы не было конфликта с синтаксисом Бейсика, использующего тот же знак для обозначения строк.
Сохраняем код, закрываем редактор Бейсика, потом документ, а затем снова открываем его и нажмём на кнопку открытия динамического меню. В момент нажатия срабатывает код формирования меню, и оно отображается. Сравните его работу с работой рядом расположенного статического меню.
Давайте сделаем ещё одну надстройку-демонстратор динамического меню. Создадим третий документ и откроем его в Ribbon XML Editor. Построим в нём следующий код:
<?xml version="1.0" standalone="yes"?> <customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" xmlns:МПИ="http://customui.blogspot.ru"> <ribbon startFromScratch="false"> <tabs> <tab idQ="МПИ:Вкладка1" label="Полезные надстройки" insertBeforeMso="TabHome" keytip="Н"> <group id="ДинамическиеМеню" label="Демонстрация меню"> <menu id="Меню1" label="Обычное меню" itemSize="large"> <button id="Кнопка1" label="Пункт 1" description="Пункт обычного меню" onAction="Сообщение1" /> <button id="Кнопка2" label="Пункт 2" description="Пункт обычного меню" onAction="Сообщение2" /> <button id="Кнопка3" label="Пункт 3" description="Пункт обычного меню" onAction="Сообщение3" /> </menu> <dynamicMenu id="ДинамическоеМеню1" label="Динкамическое меню" getContent="ВернутьДинамическоеМеню" /> </group> </tab> </tabs> </ribbon> </customUI>
В этом коде мы создаём на нашей вкладке третью группу, в которой размещаем обычное меню с тремя пунктами и динамическое меню, пункты которого мы будем получать с помощью функции «ВернутьДинамическоеМеню». Сгенерируем шаблоны функций обратного вызова и сохраним их в файле, как мы уже делали это ранее.
Кстати, если вы хотите изменить имя, предлагаемое по умолчанию, под которым сохраняются шаблоны функций, зайдите в настройки Ribbon XML Editor, и обратите внимание на окно в правом верхнем углу. Этот блок текста каждый раз помещается в начало сохраняемого файла, и вы можете отредактировать его по вашему усмотрению. В первой строке написано:
Attribute VB_Name = "RibbonCallbacks"
Мы можем поменять эту строку на:
Attribute VB_Name = "CustomUICallbacks"
и при сохранении файла нам будет предлагаться уже новое имя.
Итак, запустим документ на выполнение. Обычное меню уже работает, а для формирования пунктов динамического меню нам нужно открыть редактор Бейсика (Alt+F11) и загрузить в него модуль с сохранёнными нами ранее шаблонами функций обратного вызова.
Заполним шаблоны функций следующим кодом:
'Кнопка1 (компонент: button, атрибут: onAction), 2007 Sub Сообщение1(control As IRibbonControl) MsgBox "Был выбран пункт 1" End Sub 'Кнопка2 (компонент: button, атрибут: onAction), 2007 Sub Сообщение2(control As IRibbonControl) MsgBox "Был выбран пункт 2" End Sub 'Кнопка3 (компонент: button, атрибут: onAction), 2007 Sub Сообщение3(control As IRibbonControl) MsgBox "Был выбран пункт 3" End Sub 'ДинамическоеМеню1 (компонент: dynamicMenu, атрибут: getContent), 2007 Sub ВернутьДинамическоеМеню(control As IRibbonControl, ByRef content) Dim sXML As String sXML = "<menu itemSize=""large"" xmlns=""http://schemas.microsoft.com/office/2006/01/customui"">" & vbCrLf sXML = sXML & "<button id=""Кнопка1"" label=""Пункт 1"" description=""Пункт динамического меню"" onAction = ""Сообщение1""/>" & vbCrLf sXML = sXML & "<button id=""Кнопка2"" label=""Пункт 2"" description=""Пункт динамического меню"" onAction = ""Сообщение2""/>" & vbCrLf sXML = sXML & "<button id=""Кнопка3"" label=""Пункт 3"" description=""Пункт динамического меню"" onAction = ""Сообщение3""/>" & vbCrLf content = sXML & "</menu>" End Sub
В первых трёх функциях мы просто выводим сообщение о нажатии того или иного пункта, а в последней — формируем пункты, которые должны будут вернуться из функции во время выполнения документа. Тут требуются небольшое пояснение.
Формируемые пункты возвращаются в динамическое меню не списком, а XML-структурой, объединенённой корневым элементом menu, имеющим тип CT_MenuRoot. Элемента этого типа нет в иерархии статических элементов. Но в справке Ribbon XML Editor среди приложений мы можем найти ссылку «Динамическое меню», нажав на которую, мы откроем страничку с описанием этого типа и дополнительными сведениями по нему.
Согласно справке, корневой элемент menu должен содержать атрибут xmlns с объявлением пространства имён, используемое нами в основном коде. Замечу, что несмотря на то, что ранее мы использовали этот атрибут только в корневом элементе customUI, теоретически его можно использовать в любом элементе интерфейса, хотя его и не будет среди предлагаемых вариантов в автодополнении ввиду редкости такого использования. В данном случае мы применяем его в элементе menu.
В функции «ВернутьДинамическоеМеню» мы присваиваем строковой переменной sXML сначала открывающий тег menu с атрибутом размера пунктов меню и объявлением пространства имён, затем добавляем туда коды перевода строки (vbCrLf), затем теги элементов пунктов меню с желаемыми атрибутами и, в завершение, присваиваем возвращаемой переменной содержимое полученной строки с добавлением закрывающего тега menu. Внутри строковых переменных знак кавычек делается сдвоенным, чтобы не было конфликта с синтаксисом Бейсика, использующего тот же знак для обозначения строк.
Сохраняем код, закрываем редактор Бейсика, потом документ, а затем снова открываем его и нажмём на кнопку открытия динамического меню. В момент нажатия срабатывает код формирования меню, и оно отображается. Сравните его работу с работой рядом расположенного статического меню.
Динамическое меню получает свой контент не при открытии документа, а при своём открытии. Именно с этим связана небольшая задержка при открытии насыщенных стандартных меню, вроде галереи стилей, номеров страниц и т.п.
ОтветитьУдалитьОчень хороший материал у вас. По-доброму завидую :)
Спасибо, поправил.
УдалитьБлагодарю за положительный отзыв! )
Спасибо за полезную информацию. Есть у меня такой вопрос. Судя по всему функция ВернутьДинамическоеМеню вызывается только один раз при первом обращении. Как сделать, чтобы она вызывалась каждый раз, когда открывают динамическое меню? Это было бы полезно, когда меню зависит от каких-нибудь условий.
ОтветитьУдалитьЯ не знаю... спросите у Александра Витера (предыдущий комментарий), он, судя по всему, знает про динамическое меню побольше моего.
УдалитьНужно обновлять ленту методом Invalidate или отдельный элемент управления Invalidate(control.Id)
УдалитьПочитайте мой блог, посвящённый настройке интерфейса. Я как раз подвёл итог работе с динамическими меню: Элемент управления dynamicMenu
Скажите, а как называется и настраивается элемент интерфейса в виде текстового поля с кнопками увеличить и уменьшить значение?
ОтветитьУдалитьКак стандартный элемент для задания интервала между строками, например
Это который на вкладке "разметка страницы? Интересный вопрос... В распоряжении пользователя такого элемента нет. Как и, по моему, некоторых других составных элементов, имеющихся на стандартных лентах. Сами применяют, а нам не дают (((
УдалитьНагуглил такое решение проблемы:
Удалитьhttps://social.msdn.microsoft.com/Forums/office/en-US/04dd2304-26e8-44dc-b2c8-2fc541738e86/how-to-add-a-spinner-spin-box-control-to-a-custom-ribbon-in-excel-2007?forum=exceldev
Ну да, только если так - текстовое поле и справа две стандартные кнопки, расположенные горизонтально.
УдалитьСпасибо за ссылку!
Перешёл по ссылке, посмотрел, почитал. Поклацал, что то работает а что-то нет.
УдалитьНе совсем понял для чего это но очень интригует? Объясните для чего вы используете?
На сайте как я понял самый последний оставленный код свежий. Но для него нужен скрипт/макрос для вставки в "VBA" у меня не получается пока клепать я недавно начал...
Помогите плиз!!!
Этот комментарий был удален автором.
ОтветитьУдалитьЕсли хотите обратиться к Алексею Малькову, то и пишите в ответах под его комментарием. Тогда к нему придёт уведомление. Вероятность того, что он увидит ваше обращение к нему в корневой ветке крайне мала.
УдалитьIf possible please release in English version of Ribbon XML Editor. Thank you.
ОтветитьУдалитьIt is difficult technically because the text is not separated from the code. Maybe someday in the future.
УдалитьДобрый день Максим.
ОтветитьУдалитьПодскажите пожалуйста можно ли сделать видимым меню из других файлов НЕ применяя надстройки.
Ну то есть запустил условный xlsm -- получил меню, выполнил действия над другими файлами, затем закрыл файл, меню закрылось.
В данный момент меню доступно только в файле в котором создавалось.
В тоже время если делать меню по старинке на VBA, оно становится доступным для всех файлов.