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