Кнопка в подменю формы 1С из кода: команда, элемент, обработчик
Содержание
Кнопка в подменю на управляемой форме создаётся в три действия: команда формы, элемент-кнопка с привязкой к этой команде, родитель элемента — группа вида «Подменю». Всё это делается на сервере в процедуре ПриСозданииНаСервере, а обработчик нажатия пишется отдельной клиентской процедурой.
Сложности начинаются в мелочах. Если забыть привязать команду, получите кнопку-пустышку. Если вызвать код не в то время, форма откажет в добавлении. Если назвать два элемента одинаково, форма не откроется. Ниже разобрано всё по порядку, с рабочим кодом.
Из чего состоит командный интерфейс формы
В управляемой форме кнопка не умеет ничего сама. Она лишь ссылается на команду, а команда хранит заголовок, картинку и имя процедуры-обработчика.
Поэтому для одной новой кнопки создаются три связанных объекта:
- 🔹 Команда формы — коллекция
Команды. Здесь живёт действие. - 🔹 Элемент формы типа «Кнопка» — коллекция
Элементы. Это то, что видит пользователь. - 🔹 Группа-родитель — элемент типа «Группа формы» с видом «Подменю». В неё кнопка и попадает.
Подменю бывает двух происхождений. Либо вы создали его в конфигураторе на вкладке «Командный интерфейс» формы, либо вы создаёте его кодом. Первый вариант проще для постоянного состава, второй нужен, когда состав кнопок зависит от данных, прав или настроек.
Если набор кнопок известен заранее и не меняется, не пишите код. Добавьте команду в конфигураторе и управляйте только видимостью через Элементы.ИмяКнопки.Видимость. Динамическое создание нужно там, где состав заранее неизвестен.
Для обычных (неуправляемых) форм механика другая: у командной панели есть коллекция Кнопки, и кнопки добавляются методом Кнопки.Добавить. Такие формы остались в старых конфигурациях, а всё ниже относится к управляемым.
Где в модуле формы вызывать код
Менять состав формы можно только в серверном контексте модуля формы. Обычно для этого берут ПриСозданииНаСервере: форма ещё не показана, и пользователь не увидит мерцания.
Есть и второй путь. Серверную процедуру формы можно вызвать с клиента уже на открытой форме, и Элементы.Добавить в ней тоже сработает. Это нужно для кнопок, состав которых зависит от выбора пользователя.
Скелет модуля выглядит так:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ДобавитьПодменюИКнопки();
КонецПроцедуры
&НаСервере
Процедура ДобавитьПодменюИКнопки()
// здесь создаём группу, команды и кнопки
КонецПроцедуры
При перестройке на открытой форме сначала удалите созданные ранее элементы и команды, затем создайте заново. Имена добавленного храните в реквизите формы или собирайте по общему префиксу.
Платформа не даст вызвать Элементы.Добавить из клиентской процедуры. Метод есть только на сервере. Ошибка при попытке выглядит как «Метод объекта не обнаружен» или «Поле объекта не обнаружено», и причина не в опечатке.
Создаём подменю и первую кнопку
Начните с группы-подменю. Укажите родителя — командную панель формы или другую группу. Командная панель формы доступна как Элементы.ФормаКоманднаяПанель (если у формы есть автоматическая панель) либо как собственная группа, которую вы создали в конфигураторе.
&НаСервере
Процедура ДобавитьПодменюИКнопки()
// 1. Группа-подменю
Подменю = Элементы.Добавить("ПодменюДействия", Тип("ГруппаФормы"), Элементы.ФормаКоманднаяПанель);
Подменю.Вид = ВидГруппыФормы.Подменю;
Подменю.Заголовок = "Ещё";
// 2. Команда
Команда = Команды.Добавить("ПечатьСправки");
Команда.Действие = "ПечатьСправкиОбработчик";
Команда.Заголовок = "Напечатать справку";
// 3. Кнопка, привязанная к команде
Кнопка = Элементы.Добавить("ПодменюПечатьСправки", Тип("КнопкаФормы"), Подменю);
Кнопка.Вид = ВидКнопкиФормы.КнопкаКоманднойПанели;
Кнопка.ИмяКоманды = "ПечатьСправки";
КонецПроцедуры
Что здесь важно:
- Имя в
Элементы.Добавитьуникально в пределах формы. Дублирование имён с реквизитами, командами и другими элементами не допускается. Действие— это строка с именем процедуры, а не вызов. Кавычки обязательны.ИмяКоманды— тоже строка, совпадающая с именем команды, которое вы дали вКоманды.Добавить.- Заголовок кнопки берётся из команды, если свой не задан. Менять его можно и на кнопке.
Для кнопки в выпадающем списке подменю достаточно вида «Кнопка командной панели». Вид «Гиперссылка командной панели» подходит для панелей, где кнопки выглядят как ссылки.
Какие свойства настроить, чтобы кнопка выглядела по-человечески
После создания кнопка работает, но выглядит скромно. Настройки делятся на два уровня: часть лежит на команде, часть на кнопке.
| Что настроить | Где | Свойство |
|---|---|---|
| Надпись | команда или кнопка | Заголовок |
| Всплывающая подсказка | команда | Подсказка |
| Значок | команда | Картинка |
| Что показывать: значок, текст или оба | команда или кнопка | Отображение |
| Горячая клавиша | команда | СочетаниеКлавиш |
| Показать или скрыть | кнопка | Видимость |
| Серая или доступная | кнопка | Доступность |
Картинки берутся из библиотеки стандартных: БиблиотекаКартинок.Печать, БиблиотекаКартинок.Обновить и так далее. Добавьте нужную строкой в код:
Команда.Картинка = БиблиотекаКартинок.Печать;
Команда.Отображение = ОтображениеКнопки.КартинкаИТекст;
Горячую клавишу задают значением типа СочетаниеКлавиш: конструктор принимает клавишу и признаки Alt, Ctrl, Shift. Если сочетание уже занято другой командой формы, приоритет у более «ближней» к фокусу. Поэтому проверяйте, что новая комбинация не перекрывает стандартные вроде Ctrl+C.
Видимостью и доступностью по ролям управляйте на сервере, прямо при создании: Кнопка.Видимость = РольДоступна("ПечатьСправок");. Лишние кнопки лучше не создавать совсем, чем потом прятать.
Пишем обработчик нажатия
Обработчик — обычная процедура в модуле формы с директивой &НаКлиенте. Имя совпадает со строкой из Команда.Действие.
&НаКлиенте
Процедура ПечатьСправкиОбработчик(Команда)
Если Объект.Ссылка.Пустая() Тогда
ПоказатьПредупреждение(, "Сначала запишите документ.");
Возврат;
КонецЕсли;
ПечатьНаСервере();
КонецПроцедуры
Три замечания по практике:
- 🔸 Параметр
Командаобработчика есть всегда, даже если вы им не пользуетесь. Он содержит команду, вызвавшую процедуру. - 🔸 Если процедуры с таким именем в модуле нет, форма выдаст ошибку при открытии, а не при нажатии. Для разработчика это плюс: опечатку видно сразу.
- 🔸 Когда команде нужен контекст на сервере, передавайте в серверную процедуру только необходимое. Не тащите всю форму.
Если одна процедура обслуживает несколько кнопок, назначьте её в Действие для каждой команды и различайте по Команда.Имя:
&НаКлиенте
Процедура ОбщийОбработчик(Команда)
Если Команда.Имя = "ПечатьСправки" Тогда
// ...
ИначеЕсли Команда.Имя = "ВыгрузитьСправки" Тогда
// ...
КонецЕсли;
КонецПроцедуры
Для небольшого набора это удобно. Когда веток больше четырёх-пяти, лучше завести по процедуре на кнопку: код проще читать и отлаживать.
Если нужно создать кнопки пачкой по данным, делайте это в цикле. Имя формируйте из ключа, а ключ сохраняйте, чтобы потом найти нужную кнопку:
Для Каждого Строка Из ТаблицаШаблонов Цикл
ИмяКоманды = "Шаблон_" + Строка.Код;
К = Команды.Добавить(ИмяКоманды);
К.Действие = "ШаблонОбработчик";
К.Заголовок = Строка.Наименование;
Б = Элементы.Добавить("Кнопка_" + ИмяКоманды, Тип("КнопкаФормы"), Подменю);
Б.ИмяКоманды = ИмяКоманды;
КонецЦикла;
В общем обработчике ШаблонОбработчик код шаблона достаётся из имени: Сред(Команда.Имя, 8) отрезает префикс Шаблон_ из семи символов.
Порядок и группировка кнопок в подменю
Новый элемент встаёт в конец группы. Чтобы поставить его выше, используйте Элементы.Переместить:
Элементы.Переместить(Кнопка, Подменю, Элементы.ПодменюСуществующаяКнопка);
Третий параметр — элемент, перед которым нужно вставить. Если пропустить его, кнопка уйдёт в конец. Это же нужно, когда добавляете кнопку в уже существующее подменю: сначала решите, где она должна стоять, и только потом вызывайте перемещение.
Для визуального разделения кнопок внутри подменю создайте вложенную группу вида «Группа кнопок»:
Раздел = Элементы.Добавить("ГруппаОтчёты", Тип("ГруппаФормы"), Подменю);
Раздел.Вид = ВидГруппыФормы.ГруппаКнопок;
В выпадающем списке платформа проведёт линию-разделитель между такими группами. Кнопки раскладывайте по смыслу: «Печать» в одну группу, «Выгрузка» в другую.
Ещё два приёма:
- Удаление.
Элементы.Удалить(Элементы.Кнопка)убирает кнопку, но команда остаётся. Её удаляют отдельно:Команды.Удалить(Команды.ПечатьСправки). Если оставить, получите неиспользуемую команду в форме. - Проверка перед добавлением.
Элементы.Найти("ИмяКнопки")вернётНеопределено, когда элемента нет. Используйте перед созданием, если код может отработать дважды.
Если форма принадлежит типовой конфигурации и вы дорабатываете её в расширении, добавляйте кнопки в обработчике ПриСозданииНаСервере с вставкой кода через &После. Правка типового модуля снимет конфигурацию с поддержки.
Подменю, зависящее от данных: готовый приём
Типичная задача: в подменю «Печать» нужны кнопки по числу шаблонов, которые лежат в справочнике. Состав меняется, переписывать код каждый раз не хочется.
Рабочая схема из четырёх шагов:
- В
ПриСозданииНаСерверевыберите шаблоны запросом и положите в таблицу значений. - Для каждой строки создайте команду с префиксом, например
Шаблон_+ код. - К каждой команде добавьте кнопку в подменю, заголовок возьмите из наименования шаблона.
- Один общий обработчик по
Команда.Имяопределяет шаблон и запускает печать.
Так при 12 шаблонах в справочнике вы получите 12 кнопок, а при добавлении тринадцатого кнопка появится сама при следующем открытии формы. Код не меняется.
Отдельно проверьте работу в тонком клиенте и в веб-клиенте. Поведение подменю одинаковое, но картинки и горячие клавиши в браузере могут вести себя иначе: часть сочетаний перехватывает сам браузер.
Что ломается чаще всего
Ошибки здесь однотипные, и почти все видны в сообщении при открытии формы.
| Симптом | Причина | Что сделать |
|---|---|---|
| Форма не открывается, «Дублирование имён» | Имя элемента или команды уже занято | Добавьте префикс или проверьте Элементы.Найти |
| Кнопка есть, но ничего не происходит | Не задан ИмяКоманды или процедура без &НаКлиенте | Проверьте привязку и директиву |
| «Процедура не найдена» при открытии | В Действие другое имя, чем у процедуры | Сверьте буква в букву, регистр не важен |
| Кнопка не видна в подменю | Родитель — не та группа или Видимость = Ложь | Проверьте родителя и настройки |
«Метод не обнаружен» у Элементы.Добавить | Вызов из клиентской процедуры | Перенесите на сервер |
| Кнопка падает в конец списка | Не использован Элементы.Переместить | Укажите третий параметр |
Для поиска проблемы полезно открыть форму в режиме отладки и посмотреть содержимое Элементы и Команды в окне «Вычислить выражение». Вызов Элементы.Подменю.ПодчинённыеЭлементы.Количество() покажет, сколько кнопок реально оказалось в группе.
ИмяКоманды. Пустое значение значит, что команда не привязана. Затем убедитесь, что процедура-обработчик помечена &НаКлиенте и её имя совпадает со строкой в Действие.Действие.Элементы.Добавить для кнопки идёт после создания группы, а не раньше.Частые вопросы
Можно ли добавить кнопку в подменю уже открытой формы?
Нужно ли удалять команду вместе с кнопкой?
Элементы.Удалить не трогает команду, и она остаётся в коллекции Команды формы. Удалите её отдельным вызовом Команды.Удалить.Чем кнопка в подменю отличается от обычной кнопки формы?
Как сделать так, чтобы кнопка работала для нескольких форм?
ПриСозданииНаСервере каждой формы. Обработчик команды при этом остаётся в модуле самой формы.Можно ли указать обработчик вне модуля формы?
Действие ищет процедуру в модуле формы. Если логика общая, пишите в форме короткую обёртку, которая вызывает общий модуль.