Кнопка из кода: команда формы, элемент и обработчик в управляемой форме

· 9 мин

Содержание

Чтобы программно добавить кнопку в командную панель управляемой формы 1С, нужны два вызова в ПриСозданииНаСервере: Команды.Добавить() создаёт команду формы и связывает её с процедурой-обработчиком, а Элементы.Добавить() с типом КнопкаФормы кладёт кнопку в нужную панель и указывает на эту команду. Сама процедура-обработчик должна уже существовать в модуле формы.

Такой приём нужен, когда форму нельзя или не хочется менять в редакторе: в расширении конфигурации, в общем модуле, который подключает кнопки к десятку форм сразу, или когда набор кнопок зависит от прав и настроек пользователя. Всё ниже относится к платформе 1С:Предприятие 8.3 и управляемым формам. Для обычных форм дан отдельный короткий раздел.

Из чего состоит кнопка в управляемой форме

В управляемой форме кнопка — это не самостоятельный объект, а связка трёх частей. Если не хватает хотя бы одной, кнопка либо не появится, либо не будет работать.

ЧастьГде живётЗа что отвечает
Команда формыколлекция Командызаголовок, картинка, подсказка, имя процедуры-обработчика
Кнопкаколлекция Элементы, тип КнопкаФормыместо на экране и внешний вид
Процедурамодуль формычто произойдёт по нажатию

Командная панель тоже элемент формы. У каждой формы есть своя основная панель — в коде она доступна как Элементы.ФормаКоманднаяПанель. Кроме неё, собственная панель есть у каждой таблицы формы. Для динамического списка с именем Список это Элементы.Список.КоманднаяПанель.

Отдельно существуют команды объектов метаданных — их задают в Конфигураторе у справочника, документа или общей команды. Они попадают в панели автоматически, через свойство «Группа» команды. Программно же добавляют именно команды формы: они живут, пока открыта эта форма, и нигде не сохраняются.

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

Добавление кнопки в командную панель через код формы

Базовый пример: на форму документа добавляем кнопку «Заполнить по шаблону» в основную командную панель.

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

	ДобавитьКнопкуЗаполнения();

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

&НаСервере
Процедура ДобавитьКнопкуЗаполнения()

	ИмяКоманды = "ЗаполнитьПоШаблону";

	// 1. Команда формы
	Команда = Команды.Добавить(ИмяКоманды);
	Команда.Заголовок = "Заполнить по шаблону";
	Команда.Подсказка = "Заполнить табличную часть из сохранённого шаблона";
	Команда.Действие  = "ЗаполнитьПоШаблонуОбработчик";
	Команда.Картинка  = БиблиотекаКартинок.ЗаполнитьФорму;
	Команда.Отображение = ОтображениеКнопки.КартинкаИТекст;

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

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

// 3. Обработчик
&НаКлиенте
Процедура ЗаполнитьПоШаблонуОбработчик(Команда)

	ЗаполнитьПоШаблонуНаСервере();

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

&НаСервере
Процедура ЗаполнитьПоШаблонуНаСервере()
	// заполнение табличной части
КонецПроцедуры

Что здесь происходит по шагам:

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

Картинку ЗаполнитьФорму в примере замените на ту, что точно есть в вашей конфигурации. Если такой картинки нет, модуль просто не скомпилируется. Список доступных картинок виден в Конфигураторе: Общие → Общие картинки плюс стандартная библиотека платформы в синтакс-помощнике.

Кнопка не в конец, а в нужное место

Элементы.Добавить() всегда ставит элемент последним в группе. Чтобы кнопка встала перед конкретным элементом, используйте Элементы.Вставить(): последний параметр — элемент, перед которым нужно вставить.

Кнопка = Элементы.Вставить("КнопкаЗаполнитьПоШаблону", Тип("КнопкаФормы"),
	Элементы.ФормаКоманднаяПанель, Элементы.ФормаЗаписать);

Имя ФормаЗаписать — пример. Точное имя стандартной кнопки посмотрите в дереве элементов формы в Конфигураторе: у автоматически созданных кнопок оно начинается с имени панели.

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

Кнопка в панель таблицы и в подменю

В панель табличной части или списка кнопку добавляют так же, меняется только родитель:

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

Если команд набралось больше трёх-четырёх, соберите их в подменю. Подменю — это группа формы особого вида:

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

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

Повторяющиеся строки удобно вынести в процедуру общего модуля, которая принимает форму, имя команды, заголовок и родителя. Тогда одна и та же кнопка добавляется в десяток форм одной строкой.

Кнопка через расширение конфигурации

Расширение — правильный способ добавить кнопку в типовую конфигурацию , не снимая её с поддержки. Механизм расширений появился в платформе 8.3.6. Есть два пути.

Путь 1. Визуально, без кода добавления

  1. В Конфигураторе откройте Конфигурация → Расширения конфигурации и создайте расширение. Назначение — «Адаптация» или «Дополнение».
  2. В дереве основной конфигурации найдите нужную форму, щёлкните правой кнопкой и выберите Добавить в расширение. Форма будет заимствована.
  3. Откройте заимствованную форму в расширении. На вкладке «Команды» добавьте команду, задайте ей действие — Конфигуратор сам создаст процедуру в модуле формы расширения.
  4. Перетащите команду в нужную командную панель в дереве элементов.
  5. Обновите конфигурацию базы данных расширения (F7) и запустите 1С:Предприятие.

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

Путь 2. Код в модуле заимствованной формы

Удобен, когда кнопка нужна по условию или в нескольких формах. В модуле формы расширения пишем процедуру с аннотацией &После:

&НаСервере
&После("ПриСозданииНаСервере")
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)

	Если Команды.Найти("Расш1_ЗаполнитьПоШаблону") <> Неопределено Тогда
		Возврат;
	КонецЕсли;

	Команда = Команды.Добавить("Расш1_ЗаполнитьПоШаблону");
	Команда.Заголовок = "Заполнить по шаблону";
	Команда.Действие  = "Расш1_ЗаполнитьПоШаблону";

	Кнопка = Элементы.Добавить("Расш1_КнопкаЗаполнитьПоШаблону", Тип("КнопкаФормы"),
		Элементы.ФормаКоманднаяПанель);
	Кнопка.ИмяКоманды = "Расш1_ЗаполнитьПоШаблону";

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

&НаКлиенте
Процедура Расш1_ЗаполнитьПоШаблону(Команда)
	// действие кнопки
КонецПроцедуры

Три практических правила для расширений:

  • 🏷️ Префикс в именах. Префикс расширения (Расш1_ или свой) в именах команд, элементов и процедур защищает от совпадения с тем, что поставщик добавит в следующем релизе.
  • 🔗 Аннотация привязана к обработчику. &После("ПриСозданииНаСервере") работает, только если у исходной формы есть такой обработчик. Если его нет, назначьте событию ПриСозданииНаСервере процедуру прямо в свойствах заимствованной формы.
  • 🛡️ Безопасный режим. По умолчанию расширение работает в безопасном режиме. Для простой кнопки это не мешает. Но если обработчик пишет файлы или вызывает внешние компоненты, режим придётся отключать в свойствах расширения.

Как связать кнопку с обработчиком и передать в него данные

Процедура, имя которой записано в Команда.Действие, должна:

  • 📍 лежать в модуле той же формы (для расширения — в модуле заимствованной формы);
  • 💻 иметь директиву &НаКлиенте — команда формы всегда вызывается на клиенте;
  • 🔢 принимать ровно один параметр — саму команду.

Параметр Команда пригождается, когда одна процедура обслуживает несколько кнопок. Например, вы добавили в цикле пять кнопок «Шаблон 1» … «Шаблон 5», и все они ведут в один обработчик:

&НаКлиенте
Процедура ВыбратьШаблон(Команда)

	НомерШаблона = Число(СтрЗаменить(Команда.Имя, "Шаблон", ""));
	ПрименитьШаблонНаСервере(НомерШаблона);

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

Для такого кода имена команд должны строиться как "Шаблон" + Формат(Номер, "ЧГ=0"). Без Формат число больше 999 получит разделитель групп, и разбор имени сломается.

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

Хотите, чтобы кнопка в форме объекта была недоступна в режиме «только просмотр»? Поставьте команде ИзменяетСохраняемыеДанные = Истина. Платформа сама заблокирует её, если форма открыта только на чтение.

Видимость и доступность программно добавленных кнопок

Скрыть или заблокировать кнопку можно двумя способами — через элемент или через команду.

Что меняемКодРезультат
Видимость кнопкиЭлементы.КнопкаЗаполнитьПоШаблону.Видимость = Ложькнопки нет на экране
Доступность кнопкиЭлементы.КнопкаЗаполнитьПоШаблону.Доступность = Ложькнопка серая
Доступность командыКоманды.ЗаполнитьПоШаблону.Доступность = Ложьблокируются все кнопки этой команды

Самое надёжное — вообще не создавать кнопку, если пользователю она не положена. Проверку делайте на сервере, до Команды.Добавить:

Если Не РольДоступна("ПолныеПрава") И Не РольДоступна("ЗаполнениеПоШаблону") Тогда
	Возврат;
КонецЕсли;

Роль ЗаполнениеПоШаблону в примере — ваша собственная роль, её нужно создать. Если опираться на права к объекту, используйте ПравоДоступа("Изменение", Метаданные.Документы.РеализацияТоваровУслуг) с нужным объектом метаданных.

Если доступность зависит от данных формы — статуса документа, заполненности поля, — меняйте её в двух местах: в ПриСозданииНаСервере для начального состояния и в обработчике ПриИзменении нужного поля. Свойства Видимость и Доступность можно менять и на клиенте, лишний серверный вызов для этого не нужен.

Скрытая кнопка — не защита. Если действие нельзя выполнять без прав, проверяйте права и внутри серверной процедуры-обработчика. Серверную процедуру можно вызвать и без кнопки, а проверка прав на сервере сработает всегда.

Если пользователь перенастроил панель

Пользователь может открыть «Изменить форму» и скрыть или переставить кнопки. Если после доработки кнопка «пропала» у одного человека и видна у остальных, сначала сбросьте ему настройки формы: в том же окне «Изменить форму» есть возврат к стандартным настройкам.

Обычные формы: как это делалось раньше

В конфигурациях на обычных формах (толстый клиент, старые самописные решения) модели «команда + элемент» нет. Кнопка добавляется прямо в коллекцию кнопок панели, а действие задаётся объектом Действие:

Процедура ПриОткрытии()

	ЭлементыФормы.ОсновнаяКоманднаяПанель.Кнопки.Добавить(
		"ЗаполнитьПоШаблону",
		ТипКнопкиКоманднойПанели.Действие,
		"Заполнить по шаблону",
		Новый Действие("ЗаполнитьПоШаблонуНажатие"));

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

Процедура ЗаполнитьПоШаблонуНажатие(Кнопка)
	// действие
КонецПроцедуры

В обычных формах нет директив &НаКлиенте и &НаСервере, а событие обычно используют ПриОткрытии. Расширения конфигурации обычные формы заимствовать не умеют, так что этот код пишут в самой конфигурации.

Ошибки при программном добавлении кнопки и их отладка

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

Порядок отладки, который быстро находит причину:

  1. Поставьте точку останова на первой строке процедуры добавления и откройте форму в режиме отладки (F5 из Конфигуратора). Если остановки нет — код не вызывается, проверьте, назначена ли процедура-обработчик событию формы.
  2. Пройдите код по шагам F10 и после Элементы.Добавить посмотрите в табло значение переменной Кнопка: свойства Родитель, ИмяКоманды, Видимость.
  3. Если кнопка есть, но не работает, поставьте точку останова в обработчике. Не останавливается — проверьте строку Действие и директиву &НаКлиенте.
  4. Для расширения убедитесь, что оно подключено к базе и активно в списке расширений. После правок расширения базу нужно обновить.

Ищете имя стандартной панели или кнопки, а Конфигуратора под рукой нет? Откройте форму в режиме отладки и раскройте в табло коллекцию Элементы: там видны все имена, включая автоматически созданные.

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

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