Подменю с командами в управляемой форме: создаём из кода в ПриСозданииНаСервере
Содержание
Чтобы программно добавить подменю в командную панель формы 1С, в ПриСозданииНаСервере создайте элемент типа ГруппаФормы с родителем КоманднаяПанель и задайте ему Вид = ВидГруппыФормы.Подменю. Затем добавьте команды через Команды.Добавить() и кнопки типа КнопкаФормы внутрь этой группы. Всё делается на сервере, при открытии формы.
Подход общий для платформы 8.3 и управляемых форм любой конфигурации: БП 3.0, ЗУП 3.1, УТ 11 или своей. Ниже — рабочий код, разбор свойств, приём с расширением конфигурации и ответ на частый вопрос про панель навигации .
Из чего состоит командная панель и где тут подменю
В управляемой форме всё видимое — элементы коллекции Элементы. Командная панель формы тоже элемент: группа вида КоманднаяПанель. Получить её в модуле формы проще всего через свойство самой формы КоманднаяПанель.
Подменю — это тоже группа формы, только вида Подменю. На экране она выглядит как кнопка со стрелкой: по клику раскрывается список вложенных кнопок.
Цепочка объектов всегда одна:
- 🧩 Команда формы (
КомандаФормы) — что делать: заголовок, картинка, имя процедуры-обработчика. - 🔘 Кнопка (
КнопкаФормы) — где показать команду. Связана с командой через свойствоИмяКоманды. - 📂 Подменю (
ГруппаФормывидаПодменю) — контейнер для кнопок. - 🧱 Командная панель — родитель подменю.
Команда без кнопки не видна. Кнопка без команды неактивна. Поэтому подменю наполняют сразу после создания, в той же серверной процедуре.
Подменю можно вкладывать друг в друга. Если родителем нового подменю указать уже созданное, получится второй уровень. Больше двух уровней пользователи обычно не осваивают — держите структуру плоской.
Командная панель и панель навигации — не одно и то же
Командная панель — строка кнопок над полями формы. Панель навигации — ссылки на связанные объекты («Перейти»), обычно слева или сверху от содержимого.
Командную панель вы меняете кодом через Элементы. Панель навигации формы среди элементов не числится: её состав задаётся в конфигураторе, на вкладке «Командный интерфейс» редактора формы. Подробнее — в разделе про ограничения ниже.
Что решить до того, как писать код
Несколько вопросов, от которых зависит, куда и как писать:
- Форма типовая или своя? В типовую конфигурацию на поддержке код лучше добавлять через расширение. В свою — прямо в модуль формы.
- Чья командная панель нужна? У формы своя панель, у каждой таблицы формы — своя (
Элементы.Список.КоманднаяПанель). - Набор пунктов постоянный или меняется? Постоянный проще нарисовать в редакторе формы. Код нужен, когда пункты зависят от прав, настроек или данных.
- Есть ли в конфигурации БСП? Тогда форма может уже строить свои подменю («Печать», «Создать на основании») подсистемой подключаемых команд. Не создавайте элементы с теми же именами.
Имена элементов и команд в форме уникальны. Если имя уже занято, Элементы.Добавить вызовет исключение и форма не откроется. Давайте своим элементам префикс, например Расш1_ или Мой_.
Шаг 1. Создаём группу-подменю в командной панели
Элементы формы добавляются только на сервере. Поэтому код пишем в процедуре с директивой &НаСервере, а вызываем из ПриСозданииНаСервере.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
СоздатьПодменюСервис();
КонецПроцедуры
&НаСервере
Процедура СоздатьПодменюСервис()
// Защита от повторного создания
Если Элементы.Найти("Мой_ПодменюСервис") <> Неопределено Тогда
Возврат;
КонецЕсли;
Подменю = Элементы.Добавить("Мой_ПодменюСервис", Тип("ГруппаФормы"), КоманднаяПанель);
Подменю.Вид = ВидГруппыФормы.Подменю;
Подменю.Заголовок = "Сервис";
Подменю.Подсказка = "Дополнительные действия с документом";
ЗаполнитьПодменюСервис(Подменю);
КонецПроцедуры
Третий параметр Элементы.Добавить — родитель. Здесь это КоманднаяПанель, свойство самой формы. Для панели табличной части или списка передайте Элементы.ИмяТаблицы.КоманднаяПанель.
Как поставить подменю в нужное место
Добавить кладёт элемент в конец группы. Если подменю должно стоять перед определённой кнопкой, используйте Элементы.Вставить. Четвёртый параметр — элемент, перед которым встанет новый:
КнопкаЗаписать = Элементы.Найти("ФормаЗаписать");
Подменю = Элементы.Вставить("Мой_ПодменюСервис", Тип("ГруппаФормы"), КоманднаяПанель, КнопкаЗаписать);
Точное имя стандартной кнопки посмотрите в дереве элементов формы в конфигураторе. Если Найти вернёт Неопределено, Вставить просто добавит элемент в конец.
Уже созданный элемент переносит метод Элементы.Переместить(Элемент, Родитель, ПередЭлементом).
Шаг 2. Наполняем подменю командами и кнопками
Каждому пункту подменю нужна пара «команда + кнопка». Удобно описать пункты массивом и создать всё в цикле:
&НаСервере
Процедура ЗаполнитьПодменюСервис(Подменю)
Пункты = Новый Массив;
Пункты.Добавить(Новый Структура("Имя, Заголовок", "Мой_ПроверитьЗаполнение", "Проверить заполнение"));
Пункты.Добавить(Новый Структура("Имя, Заголовок", "Мой_ЗаписатьБезЗакрытия", "Записать, не закрывая"));
Пункты.Добавить(Новый Структура("Имя, Заголовок", "Мой_ПоказатьСсылку", "Показать ссылку на объект"));
Для Каждого Пункт Из Пункты Цикл
Команда = Команды.Добавить(Пункт.Имя);
Команда.Заголовок = Пункт.Заголовок;
Команда.Действие = "Мой_ВыполнитьКомандуСервиса";
Кнопка = Элементы.Добавить("Кнопка" + Пункт.Имя, Тип("КнопкаФормы"), Подменю);
Кнопка.Вид = ВидКнопкиФормы.КнопкаКоманднойПанели;
Кнопка.ИмяКоманды = Пункт.Имя;
КонецЦикла;
КонецПроцедуры
Ключевые моменты:
- 🔗
Кнопка.ИмяКоманды— строка с именем команды, а не сама команда. - 🏷️ Заголовок кнопки можно не задавать: он берётся из команды.
- 📌
Действие— имя клиентской процедуры в модуле формы. Строкой, без скобок.
Разделители внутри подменю
Чтобы отделить группы пунктов чертой, создайте внутри подменю группу вида ГруппаКнопок и кладите кнопки уже в неё:
Группа = Элементы.Добавить("Мой_ГруппаОпасное", Тип("ГруппаФормы"), Подменю);
Группа.Вид = ВидГруппыФормы.ГруппаКнопок;
Соседние группы кнопок платформа отделяет друг от друга разделителем. Так удобно отсечь «безопасные» команды от тех, что меняют данные.
Шаг 3. Пишем один обработчик на все пункты подменю
Процедура, указанная в Действие, должна уже существовать в модуле формы на момент компиляции. Создать её «на лету» нельзя. Поэтому для динамических команд пишут один общий обработчик и ветвятся по Команда.Имя:
&НаКлиенте
Процедура Мой_ВыполнитьКомандуСервиса(Команда)
Если Команда.Имя = "Мой_ПроверитьЗаполнение" Тогда
Если ПроверитьЗаполнение() Тогда
ПоказатьПредупреждение(, "Ошибок заполнения нет.");
КонецЕсли;
ИначеЕсли Команда.Имя = "Мой_ЗаписатьБезЗакрытия" Тогда
Записать();
ИначеЕсли Команда.Имя = "Мой_ПоказатьСсылку" Тогда
Если Объект.Ссылка.Пустая() Тогда
ПоказатьПредупреждение(, "Объект ещё не записан.");
Иначе
ПоказатьПредупреждение(, ПолучитьНавигационнуюСсылку(Объект.Ссылка));
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Если ошибки заполнения есть, ПроверитьЗаполнение() сама выведет сообщения под полями. Предупреждение показываем только для успешной проверки.
Когда пункты строятся из данных (например, список шаблонов из справочника), по имени команды ветвиться неудобно. Тогда кодируйте номер в имени (Мой_Шаблон1, Мой_Шаблон2), а соответствие «номер → ссылка» храните в реквизите формы типа СписокЗначений. В обработчике отрежьте префикс, получите номер и найдите элемент списка.
Тяжёлую логику выносите в процедуру &НаСервере или в общий модуль и вызывайте из обработчика. Клиентский обработчик должен только решить, что запускать.
Свойства подменю, команды и кнопки: справочная таблица
| Объект | Свойство | Что задаёт |
|---|---|---|
Подменю (ГруппаФормы) | Вид | ВидГруппыФормы.Подменю — обязательно, иначе получится обычная группа |
| Подменю | Заголовок | Текст на кнопке подменю |
| Подменю | Картинка | Значок из БиблиотекаКартинок |
| Подменю | Видимость, Доступность | Показать или заблокировать всё подменю целиком |
Команда (КомандаФормы) | Действие | Имя клиентской процедуры-обработчика |
| Команда | Заголовок, Подсказка | Текст пункта и всплывающая подсказка |
| Команда | Картинка | Значок пункта |
| Команда | Отображение | ОтображениеКнопки: картинка, текст или оба |
Кнопка (КнопкаФормы) | ИмяКоманды | Связь кнопки с командой (строка) |
| Кнопка | Вид | ВидКнопкиФормы.КнопкаКоманднойПанели для панели и подменю |
| Кнопка | ТолькоВоВсехДействиях | Показывать кнопку только в меню «Ещё» |
| Командная панель | Автозаполнение | Добавлять ли стандартные команды формы |
Видимость пунктов по правам удобнее всего решать прямо при создании: не создавайте команду, если у пользователя нет нужной роли (РольДоступна("ИмяРоли")).
Добавление подменю в типовую форму через расширение
Менять модуль формы типовой конфигурации на поддержке — значит усложнить себе каждое обновление. Тот же код без снятия с поддержки встраивается расширением конфигурации (доступны с платформы 8.3.6).
Порядок действий:
- В конфигураторе откройте
Конфигурация → Расширения конфигурациии создайте расширение или откройте имеющееся. - В дереве основной конфигурации найдите объект, правой кнопкой — «Добавить в расширение». Затем так же добавьте его форму.
- В модуле формы расширения создайте обработчик с аннотацией
&После:
&НаСервере
&После("ПриСозданииНаСервере")
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
СоздатьПодменюСервис();
КонецПроцедуры
- Процедуры
СоздатьПодменюСервис,ЗаполнитьПодменюСервиси обработчик команд поместите в тот же модуль формы расширения. Префикс в именах (Расш1_,Мой_) защитит от совпадения с элементами, которые разработчики конфигурации добавят в будущих релизах. - Сохраните расширение и обновите его в базе.
&После важен: к моменту вызова типовой код уже отработал, и подсистемы вроде подключаемых команд построили свои элементы. Ваше подменю не помешает им, а они — вам.
Если в форме нет события ПриСозданииНаСервере или оно не назначено в свойствах формы, аннотация &После не сработает. Тогда назначьте обработчик события в свойствах формы расширения.
Где программное подменю не сработает и что делать вместо него
Панель навигации формы
Подменю в панели навигации кодом не создаётся: это не элемент формы, и Элементы.Добавить к ней не применить. Варианты:
- 🧭 Ссылки на связанные объекты настройте в редакторе формы, вкладка «Командный интерфейс» → «Панель навигации». Там же видимость каждой ссылки по ролям.
- 📂 Если нужен именно раскрывающийся список переходов — сделайте подменю в командной панели. В обработчике откройте нужную форму через
ОткрытьФорму. - 🔗 Для пары переходов подойдёт декорация-надпись с гиперссылкой прямо в форме.
Глобальный командный интерфейс
Разделы, панель действий раздела, меню функций — это командный интерфейс приложения, а не формы. Его состав определяется командами и подсистемами в конфигураторе. Код модуля формы на него не влияет.
Изменение подменю после открытия формы
Пересобрать подменю можно и позже, например после смены вида операции. Вызовите из клиентского события серверную процедуру формы, удалите старые кнопки и команды и создайте новые:
&НаСервере
Процедура ПересоздатьПодменюСервис()
Подменю = Элементы.Найти("Мой_ПодменюСервис");
Если Подменю = Неопределено Тогда
Возврат;
КонецЕсли;
Для Сч = 1 По Подменю.ПодчиненныеЭлементы.Количество() Цикл
Элемент = Подменю.ПодчиненныеЭлементы[Подменю.ПодчиненныеЭлементы.Количество() - Сч];
ИмяКоманды = "";
Если ТипЗнч(Элемент) = Тип("КнопкаФормы") Тогда
ИмяКоманды = Элемент.ИмяКоманды;
КонецЕсли;
Элементы.Удалить(Элемент);
Если ЗначениеЗаполнено(ИмяКоманды) И Команды.Найти(ИмяКоманды) <> Неопределено Тогда
Команды.Удалить(Команды.Найти(ИмяКоманды));
КонецЕсли;
КонецЦикла;
ЗаполнитьПодменюСервис(Подменю);
КонецПроцедуры
Обход идёт с конца коллекции: при удалении элемента индексы оставшихся не сдвигаются под ногами. Команды удаляем вместе с кнопками, иначе повторное Команды.Добавить с тем же именем упадёт.
Каждый такой вызов — серверный вызов. Не пересобирайте подменю при каждом изменении поля, только когда набор пунктов действительно поменялся.
Отладка: подменю не появилось или не работает
Частые вопросы
Можно ли добавить подменю с клиента, без серверного вызова?
Элементы.Добавить и Команды.Добавить работают на сервере. С клиента вызовите процедуру формы с директивой &НаСервере.Сохранятся ли созданные из кода элементы после закрытия формы?
ПриСозданииНаСервере строит их заново.Чем программное подменю хуже нарисованного в редакторе?
Работает ли этот код в обычных формах 8.2?
ВидГруппыФормы к ним не применяется. Описанное относится к управляемым формам.