Свой пункт в меню по правой кнопке: команды формы, кнопки и расширения
Содержание
Чтобы программно добавить команду в контекстное меню 1С, в ПриСозданииНаСервере создают команду формы через Команды.Добавить(), а затем кнопку через Элементы.Добавить() с типом КнопкаФормы. Родителем кнопки указывают группу Элементы.<ИмяТаблицы>.КонтекстноеМеню. Обработчик команды — клиентская процедура в модуле формы, её имя записывают в свойство Действие.
Так работает любая управляемая форма платформы 1С:Предприятие 8.3, конфигурация роли не играет. В типовых базах код размещают в расширении, чтобы не снимать конфигурацию с поддержки. Тот же приём подходит и для меню поля ввода: у поля тоже есть своя группа КонтекстноеМеню, меняется только родитель кнопки.
Как устроено меню по правой кнопке в управляемой форме
У каждой таблицы формы (ТаблицаФормы) и у поля ввода есть свойство КонтекстноеМеню. Это группа формы особого вида — «Контекстное меню». Она живёт в дереве элементов формы как подчинённый элемент таблицы или поля, и в неё можно класть кнопки, как в обычную командную панель.
Из чего собирается меню, которое видит пользователь:
- 📌 Стандартные команды таблицы: «Добавить», «Скопировать», «Изменить», «Удалить», поиск, вывод списка. Они появляются, когда у группы контекстного меню включено свойство
Автозаполнение. - 🧩 Кнопки, добавленные разработчиком в редакторе формы — в конфигураторе или в расширении.
- ⚙️ Кнопки, созданные кодом при открытии формы. Именно о них эта статья.
Кнопка сама по себе ничего не делает. Она ссылается на команду через свойство ИмяКоманды. Команда — отдельный объект: заголовок, картинка, сочетание клавиш и имя процедуры-обработчика. Одну команду можно вывести сразу в несколько мест: в командную панель, в контекстное меню таблицы и в меню поля.
Отдельного события «перед открытием контекстного меню» в управляемых формах нет. Меню собирается заранее, а его содержимое меняют через свойства кнопок Видимость и Доступность — обычно при смене текущей строки.
Какой способ выбрать
| Способ | Когда подходит | Риски |
|---|---|---|
| Кнопка в редакторе формы | Своя конфигурация, состав меню постоянный | Правка типовой формы мешает обновлениям |
Код в ПриСозданииНаСервере | Состав команд зависит от прав, настроек, вида объекта | Ошибка в коде ломает открытие формы |
| Расширение конфигурации | Типовая конфигурация на поддержке | Расширение надо проверять после каждого обновления |
Создаём команду формы и кнопку в контекстном меню кодом
Возьмём форму списка справочника с таблицей Список. Задача — добавить в меню по правой кнопке пункт «Отправить на проверку».
Шаг 1. Команда и кнопка при создании формы
Код пишут в обработчике ПриСозданииНаСервере, потому что Элементы.Добавить() и Команды.Добавить() доступны только на сервере.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ДобавитьКомандуВКонтекстноеМеню();
КонецПроцедуры
&НаСервере
Процедура ДобавитьКомандуВКонтекстноеМеню()
ИмяКоманды = "ОтправитьНаПроверку";
// Команда формы
Команда = Команды.Добавить(ИмяКоманды);
Команда.Заголовок = "Отправить на проверку";
Команда.Подсказка = "Отметить выделенные элементы для проверки";
Команда.Действие = "ОтправитьНаПроверкуОбработка";
// Кнопка в контекстном меню таблицы Список
Кнопка = Элементы.Добавить("Кнопка" + ИмяКоманды, Тип("КнопкаФормы"),
Элементы.Список.КонтекстноеМеню);
Кнопка.ИмяКоманды = ИмяКоманды;
КонецПроцедуры
Свойство Действие — это строка с именем процедуры, а не ссылка на неё. Платформа ищет процедуру в модуле формы по имени, когда пользователь нажимает пункт.
Шаг 2. Место пункта в меню
Элементы.Добавить() ставит кнопку в конец группы. Чтобы пункт оказался выше стандартных команд, используют Элементы.Вставить() с четвёртым параметром — элементом, перед которым встаёт новый:
ПервыйЭлемент = Неопределено;
Если Элементы.Список.КонтекстноеМеню.ПодчиненныеЭлементы.Количество() > 0 Тогда
ПервыйЭлемент = Элементы.Список.КонтекстноеМеню.ПодчиненныеЭлементы[0];
КонецЕсли;
Кнопка = Элементы.Вставить("Кнопка" + ИмяКоманды, Тип("КнопкаФормы"),
Элементы.Список.КонтекстноеМеню, ПервыйЭлемент);
Если ПервыйЭлемент равен Неопределено, кнопка просто окажется в конце — ошибки не будет.
Шаг 3. Несколько команд одним циклом
Когда пунктов три-четыре, удобнее описать их структурой и создать в цикле. Имена кнопок должны быть уникальными в пределах формы, иначе Элементы.Добавить() вызовет исключение.
&НаСервере
Процедура ДобавитьКомандыВКонтекстноеМеню()
Описания = Новый Массив;
Описания.Добавить(Новый Структура("Имя, Заголовок", "ОтправитьНаПроверку", "Отправить на проверку"));
Описания.Добавить(Новый Структура("Имя, Заголовок", "СнятьСПроверки", "Снять с проверки"));
Для Каждого Описание Из Описания Цикл
Команда = Команды.Добавить(Описание.Имя);
Команда.Заголовок = Описание.Заголовок;
Команда.Действие = "КомандаКонтекстногоМенюОбработка";
Кнопка = Элементы.Добавить("Кнопка" + Описание.Имя, Тип("КнопкаФормы"),
Элементы.Список.КонтекстноеМеню);
Кнопка.ИмяКоманды = Описание.Имя;
КонецЦикла;
КонецПроцедуры
Здесь у всех команд один обработчик. Какая команда нажата, он узнаёт из параметра Команда по свойству Имя — пример в разделе про логику.
Управляем пунктами меню через события формы
Пункт часто нужен не всегда: например, «Отправить на проверку» имеет смысл только для непомеченных на удаление элементов. Для этого используют событие таблицы ПриАктивизацииСтроки.
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
ПодключитьОбработчикОжидания("ОбновитьДоступностьКоманд", 0.2, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьДоступностьКоманд()
ТекущиеДанные = Элементы.Список.ТекущиеДанные;
Доступна = ТекущиеДанные <> Неопределено
И Не ТекущиеДанные.ПометкаУдаления;
Элементы.КнопкаОтправитьНаПроверку.Доступность = Доступна;
КонецПроцедуры
Зачем обработчик ожидания: при прокрутке списка стрелками событие срабатывает на каждой строке. Задержка в 0,2 секунды и однократный вызов убирают лишнюю работу и подтормаживания.
Что ещё удобно делать в событиях формы:
- 🔐 В
ПриСозданииНаСервере— проверять права. Если у пользователя нет роли, кнопку не создают вовсе или ставят ейВидимость = Ложь. - 🔄 В
ПриАктивизацииСтроки— менятьДоступностьиЗаголовоккнопки в зависимости от строки. - 🧷 В
ОбработкаОповещения— обновлять доступность после того, как другая форма изменила данные.
В ТекущиеДанные динамического списка видны только поля, которые есть в списке или в его запросе. Если обращаться к полю, которого там нет, будет ошибка. Нужное поле добавляют в запрос динамического списка или включают его использование в настройках списка.
Команда в контекстном меню через расширение конфигурации
В типовой БП 3.0, ЗУП 3.1 или УТ 11 менять форму напрямую невыгодно: каждое обновление превратится в ручное объединение. Расширение решает задачу без снятия с поддержки. Расширения появились в платформе 8.3.6, на актуальных версиях с формами в них работают без ограничений.
Вариант А. Без кода, в редакторе формы
- Откройте конфигуратор:
Конфигурация → Расширения конфигурации, создайте расширение. - В дереве основной конфигурации найдите нужную форму, в контекстном меню выберите
Добавить в расширение. - Откройте заимствованную форму в расширении, на вкладке «Команды» создайте команду и назначьте ей действие — платформа сама создаст процедуру в модуле формы расширения.
- Перетащите команду в дереве элементов на группу «Контекстное меню» под нужной таблицей.
- Сохраните расширение и проверьте в пользовательском режиме.
Вариант Б. Кодом в модуле расширенной формы
Здесь есть тонкость, о которую спотыкаются чаще всего. Аннотация &После("ПриСозданииНаСервере") работает, только если в исходной форме такой обработчик уже есть. Если его нет, обработчик события назначают в палитре свойств заимствованной формы расширения.
&НаСервере
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
Команда = Команды.Добавить("Расш1_ОтправитьНаПроверку");
Команда.Заголовок = "Отправить на проверку";
Команда.Действие = "Расш1_ОтправитьНаПроверкуОбработка";
Кнопка = Элементы.Добавить("Расш1_КнопкаОтправитьНаПроверку", Тип("КнопкаФормы"),
Элементы.Список.КонтекстноеМеню);
Кнопка.ИмяКоманды = "Расш1_ОтправитьНаПроверку";
КонецПроцедуры
Процедура Расш1_ОтправитьНаПроверкуОбработка должна лежать в модуле формы расширения. Префикс Расш1_ в именах команд, кнопок и процедур защищает от совпадения с элементами, которые разработчики типовой могут добавить в следующих релизах.
В типовых на БСП печать, заполнение и создание на основании выводятся подсистемой «Подключаемые команды» и внешними обработками через «Дополнительные отчёты и обработки». Если пункт по смыслу относится к этим подменю, логичнее подключить его этими механизмами, а не строить кнопку руками.
Пишем обработчик: что делает команда после нажатия
Обработчик команды формы — клиентская процедура с одним параметром. Работу с базой выносят в серверную процедуру.
&НаКлиенте
Процедура КомандаКонтекстногоМенюОбработка(Команда)
Выделенные = Элементы.Список.ВыделенныеСтроки;
Если Выделенные.Количество() = 0 Тогда
ПоказатьПредупреждение(, "Выделите хотя бы одну строку.");
Возврат;
КонецЕсли;
НаПроверку = (Команда.Имя = "ОтправитьНаПроверку");
Обработано = ИзменитьПризнакПроверки(Выделенные, НаПроверку);
Элементы.Список.Обновить();
ПоказатьОповещениеПользователя("Готово", ,
СтрШаблон("Обработано элементов: %1", Формат(Обработано, "ЧГ=0")));
КонецПроцедуры
&НаСервереБезКонтекста
Функция ИзменитьПризнакПроверки(Ссылки, НаПроверку)
Обработано = 0;
Для Каждого Ссылка Из Ссылки Цикл
Объект = Ссылка.ПолучитьОбъект();
Объект.НаПроверке = НаПроверку; // реквизит вашего справочника
Объект.Записать();
Обработано = Обработано + 1;
КонецЦикла;
Возврат Обработано;
КонецФункции
Почему так:
- 📋
ВыделенныеСтрокиу динамического списка возвращает массив ссылок. Пользователь может выделить с Shift или Ctrl несколько строк — команда обработает все. - 🖥️
&НаСервереБезКонтекстане гоняет данные формы на сервер. Для списка из сотен строк разница в скорости заметна. - 🔢
Формат(..., "ЧГ=0")убирает разделитель групп разрядов: без него 1500 превратится в «1 500».
Для таблицы значений или табличной части ВыделенныеСтроки возвращает идентификаторы строк, а не ссылки. Строку получают так: Объект.Товары.НайтиПоИдентификатору(Идентификатор).
Запись объектов из команды меняет рабочие данные — сначала проверьте её на копии базы. Если реквизит участвует в проведении документов, вместо простой записи может понадобиться перепроведение.
Отладка и проверка нового пункта
Код короткий, но мест, где он молча не работает , хватает. Порядок проверки:
- Поставьте точку останова на первой строке
ПриСозданииНаСервереи запустите отладку (F5). Убедитесь, что процедура вообще вызывается — в расширении это главный подозреваемый. - В табло посмотрите
Элементы.Список.КонтекстноеМеню.ПодчиненныеЭлементы.Количество()до и после добавления кнопки. - Поставьте точку останова в клиентском обработчике команды и нажмите пункт меню в пользовательском режиме.
- Проверьте поведение при выделении нескольких строк, пустом списке и строке, помеченной на удаление.
- Зайдите под пользователем с урезанными правами: пункт должен скрываться или не делать запрещённого.
Если форма открывается заметно медленнее после доработки, запустите отладку и включите в конфигураторе Отладка → Замер производительности, затем откройте форму и посмотрите, сколько времени занимает ПриСозданииНаСервере.
Если форма обычная, а не управляемая
В старых конфигурациях на обычных формах (например, УПП 1.3 в толстом клиенте) объектная модель другая. Там у табличного поля свойство КонтекстноеМеню — это командная панель, и пункт добавляют через её коллекцию кнопок:
Меню = ЭлементыФормы.ТабличноеПоле1.КонтекстноеМеню;
Если Меню <> Неопределено Тогда
Меню.Кнопки.Добавить("ОтправитьНаПроверку", ТипКнопкиКоманднойПанели.Действие,
"Отправить на проверку", Новый Действие("ОтправитьНаПроверкуНажатие"));
КонецЕсли;
Обработчик — процедура модуля формы с параметром Кнопка. Если у поля своего меню нет, проще создать его в редакторе обычной формы, чем собирать кодом. Код управляемых форм (Команды.Добавить, КнопкаФормы) в обычных формах не работает, и наоборот.
Частые вопросы
Можно ли добавить пункт в контекстное меню всех форм сразу?
ПриСозданииНаСервере каждой формы, передавая форму параметром.Как добавить подменю в контекстное меню?
Элементы.Добавить("ГруппаПроверка", Тип("ГруппаФормы"), Элементы.Список.КонтекстноеМеню), задайте ей Вид = ВидГруппыФормы.Подменю и заголовок. Кнопки затем добавляйте с родителем — этой группой.Как назначить пункту горячую клавишу?
СочетаниеКлавиш: Команда.СочетаниеКлавиш = Новый СочетаниеКлавиш(Клавиша.F9, , Истина) — это Ctrl+F9. Проверьте, что сочетание не занято стандартной командой таблицы.Можно ли убрать стандартные пункты и оставить только свои?
Автозаполнение в редакторе формы или кодом. Стандартные команды пропадут, останутся только добавленные вами кнопки.