Кнопка в подменю формы 1С из кода: команда, элемент, обработчик

· 8 мин

Содержание

Кнопка в подменю на управляемой форме создаётся в три действия: команда формы, элемент-кнопка с привязкой к этой команде, родитель элемента — группа вида «Подменю». Всё это делается на сервере в процедуре ПриСозданииНаСервере, а обработчик нажатия пишется отдельной клиентской процедурой.

Сложности начинаются в мелочах. Если забыть привязать команду, получите кнопку-пустышку. Если вызвать код не в то время, форма откажет в добавлении. Если назвать два элемента одинаково, форма не откроется. Ниже разобрано всё по порядку, с рабочим кодом.

Из чего состоит командный интерфейс формы

В управляемой форме кнопка не умеет ничего сама. Она лишь ссылается на команду, а команда хранит заголовок, картинку и имя процедуры-обработчика.

Поэтому для одной новой кнопки создаются три связанных объекта:

  • 🔹 Команда формы — коллекция Команды. Здесь живёт действие.
  • 🔹 Элемент формы типа «Кнопка» — коллекция Элементы. Это то, что видит пользователь.
  • 🔹 Группа-родитель — элемент типа «Группа формы» с видом «Подменю». В неё кнопка и попадает.

Подменю бывает двух происхождений. Либо вы создали его в конфигураторе на вкладке «Командный интерфейс» формы, либо вы создаёте его кодом. Первый вариант проще для постоянного состава, второй нужен, когда состав кнопок зависит от данных, прав или настроек.

Если набор кнопок известен заранее и не меняется, не пишите код. Добавьте команду в конфигураторе и управляйте только видимостью через Элементы.ИмяКнопки.Видимость. Динамическое создание нужно там, где состав заранее неизвестен.

Для обычных (неуправляемых) форм механика другая: у командной панели есть коллекция Кнопки, и кнопки добавляются методом Кнопки.Добавить. Такие формы остались в старых конфигурациях, а всё ниже относится к управляемым.

Где в модуле формы вызывать код

Менять состав формы можно только в серверном контексте модуля формы. Обычно для этого берут ПриСозданииНаСервере: форма ещё не показана, и пользователь не увидит мерцания.

Есть и второй путь. Серверную процедуру формы можно вызвать с клиента уже на открытой форме, и Элементы.Добавить в ней тоже сработает. Это нужно для кнопок, состав которых зависит от выбора пользователя.

Скелет модуля выглядит так:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

	ДобавитьПодменюИКнопки();

КонецПроцедуры

&НаСервере
Процедура ДобавитьПодменюИКнопки()
	// здесь создаём группу, команды и кнопки
КонецПроцедуры

При перестройке на открытой форме сначала удалите созданные ранее элементы и команды, затем создайте заново. Имена добавленного храните в реквизите формы или собирайте по общему префиксу.

Платформа не даст вызвать Элементы.Добавить из клиентской процедуры. Метод есть только на сервере. Ошибка при попытке выглядит как «Метод объекта не обнаружен» или «Поле объекта не обнаружено», и причина не в опечатке.

Создаём подменю и первую кнопку

Начните с группы-подменю. Укажите родителя — командную панель формы или другую группу. Командная панель формы доступна как Элементы.ФормаКоманднаяПанель (если у формы есть автоматическая панель) либо как собственная группа, которую вы создали в конфигураторе.

&НаСервере
Процедура ДобавитьПодменюИКнопки()

	// 1. Группа-подменю
	Подменю = Элементы.Добавить("ПодменюДействия", Тип("ГруппаФормы"), Элементы.ФормаКоманднаяПанель);
	Подменю.Вид = ВидГруппыФормы.Подменю;
	Подменю.Заголовок = "Ещё";

	// 2. Команда
	Команда = Команды.Добавить("ПечатьСправки");
	Команда.Действие = "ПечатьСправкиОбработчик";
	Команда.Заголовок = "Напечатать справку";

	// 3. Кнопка, привязанная к команде
	Кнопка = Элементы.Добавить("ПодменюПечатьСправки", Тип("КнопкаФормы"), Подменю);
	Кнопка.Вид = ВидКнопкиФормы.КнопкаКоманднойПанели;
	Кнопка.ИмяКоманды = "ПечатьСправки";

КонецПроцедуры

Что здесь важно:

  1. Имя в Элементы.Добавить уникально в пределах формы. Дублирование имён с реквизитами, командами и другими элементами не допускается.
  2. Действие — это строка с именем процедуры, а не вызов. Кавычки обязательны.
  3. ИмяКоманды — тоже строка, совпадающая с именем команды, которое вы дали в Команды.Добавить.
  4. Заголовок кнопки берётся из команды, если свой не задан. Менять его можно и на кнопке.

Для кнопки в выпадающем списке подменю достаточно вида «Кнопка командной панели». Вид «Гиперссылка командной панели» подходит для панелей, где кнопки выглядят как ссылки.

Какие свойства настроить, чтобы кнопка выглядела по-человечески

После создания кнопка работает, но выглядит скромно. Настройки делятся на два уровня: часть лежит на команде, часть на кнопке.

Что настроитьГдеСвойство
Надписькоманда или кнопкаЗаголовок
Всплывающая подсказкакомандаПодсказка
ЗначоккомандаКартинка
Что показывать: значок, текст или обакоманда или кнопкаОтображение
Горячая клавишакомандаСочетаниеКлавиш
Показать или скрытькнопкаВидимость
Серая или доступнаякнопкаДоступность

Картинки берутся из библиотеки стандартных: БиблиотекаКартинок.Печать, БиблиотекаКартинок.Обновить и так далее. Добавьте нужную строкой в код:

Команда.Картинка = БиблиотекаКартинок.Печать;
Команда.Отображение = ОтображениеКнопки.КартинкаИТекст;

Горячую клавишу задают значением типа СочетаниеКлавиш: конструктор принимает клавишу и признаки Alt, Ctrl, Shift. Если сочетание уже занято другой командой формы, приоритет у более «ближней» к фокусу. Поэтому проверяйте, что новая комбинация не перекрывает стандартные вроде Ctrl+C.

Видимостью и доступностью по ролям управляйте на сервере, прямо при создании: Кнопка.Видимость = РольДоступна("ПечатьСправок");. Лишние кнопки лучше не создавать совсем, чем потом прятать.

Пишем обработчик нажатия

Обработчик — обычная процедура в модуле формы с директивой &НаКлиенте. Имя совпадает со строкой из Команда.Действие.

&НаКлиенте
Процедура ПечатьСправкиОбработчик(Команда)

	Если Объект.Ссылка.Пустая() Тогда
		ПоказатьПредупреждение(, "Сначала запишите документ.");
		Возврат;
	КонецЕсли;

	ПечатьНаСервере();

КонецПроцедуры

Три замечания по практике:

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

Если одна процедура обслуживает несколько кнопок, назначьте её в Действие для каждой команды и различайте по Команда.Имя:

&НаКлиенте
Процедура ОбщийОбработчик(Команда)

	Если Команда.Имя = "ПечатьСправки" Тогда
		// ...
	ИначеЕсли Команда.Имя = "ВыгрузитьСправки" Тогда
		// ...
	КонецЕсли;

КонецПроцедуры

Для небольшого набора это удобно. Когда веток больше четырёх-пяти, лучше завести по процедуре на кнопку: код проще читать и отлаживать.

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

Для Каждого Строка Из ТаблицаШаблонов Цикл
	ИмяКоманды = "Шаблон_" + Строка.Код;
	К = Команды.Добавить(ИмяКоманды);
	К.Действие = "ШаблонОбработчик";
	К.Заголовок = Строка.Наименование;

	Б = Элементы.Добавить("Кнопка_" + ИмяКоманды, Тип("КнопкаФормы"), Подменю);
	Б.ИмяКоманды = ИмяКоманды;
КонецЦикла;

В общем обработчике ШаблонОбработчик код шаблона достаётся из имени: Сред(Команда.Имя, 8) отрезает префикс Шаблон_ из семи символов.

Порядок и группировка кнопок в подменю

Новый элемент встаёт в конец группы. Чтобы поставить его выше, используйте Элементы.Переместить:

Элементы.Переместить(Кнопка, Подменю, Элементы.ПодменюСуществующаяКнопка);

Третий параметр — элемент, перед которым нужно вставить. Если пропустить его, кнопка уйдёт в конец. Это же нужно, когда добавляете кнопку в уже существующее подменю: сначала решите, где она должна стоять, и только потом вызывайте перемещение.

Для визуального разделения кнопок внутри подменю создайте вложенную группу вида «Группа кнопок»:

Раздел = Элементы.Добавить("ГруппаОтчёты", Тип("ГруппаФормы"), Подменю);
Раздел.Вид = ВидГруппыФормы.ГруппаКнопок;

В выпадающем списке платформа проведёт линию-разделитель между такими группами. Кнопки раскладывайте по смыслу: «Печать» в одну группу, «Выгрузка» в другую.

Ещё два приёма:

  1. Удаление. Элементы.Удалить(Элементы.Кнопка) убирает кнопку, но команда остаётся. Её удаляют отдельно: Команды.Удалить(Команды.ПечатьСправки). Если оставить, получите неиспользуемую команду в форме.
  2. Проверка перед добавлением. Элементы.Найти("ИмяКнопки") вернёт Неопределено, когда элемента нет. Используйте перед созданием, если код может отработать дважды.

Если форма принадлежит типовой конфигурации и вы дорабатываете её в расширении, добавляйте кнопки в обработчике ПриСозданииНаСервере с вставкой кода через &После. Правка типового модуля снимет конфигурацию с поддержки.

Подменю, зависящее от данных: готовый приём

Типичная задача: в подменю «Печать» нужны кнопки по числу шаблонов, которые лежат в справочнике. Состав меняется, переписывать код каждый раз не хочется.

Рабочая схема из четырёх шагов:

  1. В ПриСозданииНаСервере выберите шаблоны запросом и положите в таблицу значений.
  2. Для каждой строки создайте команду с префиксом, например Шаблон_ + код.
  3. К каждой команде добавьте кнопку в подменю, заголовок возьмите из наименования шаблона.
  4. Один общий обработчик по Команда.Имя определяет шаблон и запускает печать.

Так при 12 шаблонах в справочнике вы получите 12 кнопок, а при добавлении тринадцатого кнопка появится сама при следующем открытии формы. Код не меняется.

Проверка перед сдачей доработки
Выполнено: 0 / 6

Отдельно проверьте работу в тонком клиенте и в веб-клиенте. Поведение подменю одинаковое, но картинки и горячие клавиши в браузере могут вести себя иначе: часть сочетаний перехватывает сам браузер.

Что ломается чаще всего

Ошибки здесь однотипные, и почти все видны в сообщении при открытии формы.

СимптомПричинаЧто сделать
Форма не открывается, «Дублирование имён»Имя элемента или команды уже занятоДобавьте префикс или проверьте Элементы.Найти
Кнопка есть, но ничего не происходитНе задан ИмяКоманды или процедура без &НаКлиентеПроверьте привязку и директиву
«Процедура не найдена» при открытииВ Действие другое имя, чем у процедурыСверьте буква в букву, регистр не важен
Кнопка не видна в подменюРодитель — не та группа или Видимость = ЛожьПроверьте родителя и настройки
«Метод не обнаружен» у Элементы.ДобавитьВызов из клиентской процедурыПеренесите на сервер
Кнопка падает в конец спискаНе использован Элементы.ПереместитьУкажите третий параметр

Для поиска проблемы полезно открыть форму в режиме отладки и посмотреть содержимое Элементы и Команды в окне «Вычислить выражение». Вызов Элементы.Подменю.ПодчинённыеЭлементы.Количество() покажет, сколько кнопок реально оказалось в группе.

Диагностика: выберите симптом

Частые вопросы

Можно ли добавить кнопку в подменю уже открытой формы?
Можно, но только из серверной процедуры формы, вызванной с клиента. Прежние динамические элементы и команды сначала удалите, затем создайте нужные заново.
Нужно ли удалять команду вместе с кнопкой?
Да. Элементы.Удалить не трогает команду, и она остаётся в коллекции Команды формы. Удалите её отдельным вызовом Команды.Удалить.
Чем кнопка в подменю отличается от обычной кнопки формы?
Только родителем. Это та же кнопка формы, но в группе вида «Подменю». Свойства и принцип привязки к команде одинаковы.
Как сделать так, чтобы кнопка работала для нескольких форм?
Вынесите создание в общий модуль с экспортной процедурой, куда передаётся форма, и вызывайте из ПриСозданииНаСервере каждой формы. Обработчик команды при этом остаётся в модуле самой формы.
Можно ли указать обработчик вне модуля формы?
Напрямую нет: Действие ищет процедуру в модуле формы. Если логика общая, пишите в форме короткую обёртку, которая вызывает общий модуль.