В процессе разработки интерфейсов в среде 1С:Предприятие часто возникает задача кастомизации элементов управления. Например, при создании рабочего места кассира, официанта или менеджера по продажам (в стиле систем наподобие R-Keeper) требуется выводить индивидуальные изображения номенклатуры непосредственно на кнопки выбора товаров. Это делает интерфейс интуитивно понятным и ускоряет работу пользователей.
Однако при попытке реализовать это стандартными методами многие разработчики сталкиваются с трудностями и приходят к ошибочному выводу, что динамически назначить произвольную картинку кнопке или команде управляемой формы невозможно, и платформа позволяет использовать только статические изображения из встроенной библиотеки картинок метаданных. Давайте подробно разберем эту проблему, опровергнем популярные мифы и рассмотрим работающие программные механизмы для решения этой задачи.
Проанализируем типичную ошибку программистов при попытке динамического изменения картинки на кнопке. Обычно код выглядит следующим образом: разработчик получает навигационную ссылку или адрес во временном хранилище для файла картинки номенклатуры и пытается напрямую присвоить это значение свойству элемента формы:
// Ошибочный код, вызывающий ошибку "Несоответствие типов"
АдресКартинки = ПолучитьНавигационнуюСсылку(Номенклатура.ФайлКартинки, "Данные");
Элементы.КнопкаНоменклатуры.Картинка = АдресКартинки;
Этот подход всегда приводит к завершению работы процедуры с ошибкой времени выполнения. Выясним причину этой ошибки. Свойство кнопки или команды Картинка ожидает на вход готовый объект типа Картинка, в то время как разработчик пытается передать туда переменную типа Строка, содержащую адрес во временном хранилище. Для исправления этой ситуации нам нужно предварительно сконструировать сам объект картинки из имеющихся бинарных данных.
Ниже мы рассмотрим три надежных метода динамического размещения изображений на элементах управления управляемой формы.
Для того чтобы честно и без обходных путей установить картинку из базы данных или временного хранилища на кнопку, нам необходимо выполнить преобразование двоичных данных в объект Картинка в серверном контексте. Рассмотрим по шагам, как это реализовать.
Пусть у нас в справочнике Номенклатура есть реквизит ФайлКартинки, имеющий тип ХранилищеЗначения (или ссылка на справочник присоединенных файлов, откуда мы можем извлечь двоичные данные).
Напишем процедуру, которая будет выполняться на сервере и динамически изменять картинку у кнопки Элементы.КнопкаТовара (или у соответствующей команды формы Команды.ВыбратьТовар):
&НаСервере
Процедура УстановитьИзображениеНаКнопкуНаСервере(СсылкаНаНоменклатуру)
// 1. Получаем двоичные данные картинки из ХранилищаЗначения
ДвоичныеДанныеКартинки = СсылкаНаНоменклатуру.ФайлКартинки.Получить();
Если ДвоичныеДанныеКартинки <> Неопределено Тогда
Попытка
// 2. Создаем объект "Картинка" на основе полученных двоичных данных
НовоеИзображение = Новый Картинка(ДвоичныеДанныеКартинки);
// 3. Назначаем созданный объект свойству Картинка нашей команды
// Рекомендуется назначать картинку именно команде, связанной с кнопкой
Команды.ВыбратьТовар.Картинка = НовоеИзображение;
// Также можно назначить картинку напрямую элементу формы (кнопке)
Элементы.КнопкаТовара.Картинка = НовоеИзображение;
Исключение
// Обработка исключения, если переданные данные не являются корректным изображением
ЗаписьЖурналаРегистрации("ОформлениеКнопки", УровеньЖурналаРегистрации.Предупреждение,,,
"Не удалось создать объект Картинка из данных номенклатуры: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Этот способ является наиболее чистым и правильным с точки зрения архитектуры платформы. Он работает в рамках штатных механизмов управляемого приложения и не требует создания дополнительных элементов на форме.
Если по какой-то причине прямое назначение картинки кнопке неудобно (например, при частой динамической смене картинок на клиенте без лишних серверных вызовов для перерисовки всей формы), мы можем применить популярный прием с использованием элемента формы Поле картинки, работающего в режиме гиперссылки. Этот метод отлично зарекомендовал себя в веб-клиенте и на мобильной платформе 1С.
Разберем данный подход по шагам:
АдресИзображенияТовара и типом данных Строка.Истина. Это заставит поле реагировать на клики мыши как обычная кнопка, а курсор при наведении будет принимать форму "указательного пальца".Нажатие.Теперь посмотрим на программную реализацию логики этого метода:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Получаем двоичные данные файла (например, из макета, присоединенного файла или реквизита)
ДвоичныеДанныеИзображения = Объект.СсылкаНаНоменклатуру.ФайлКартинки.Получить();
Если ДвоичныеДанныеИзображения <> Неопределено Тогда
// Создаем объект Картинка и помещаем его во Временное Хранилище
ОбъектКартинка = Новый Картинка(ДвоичныеДанныеИзображения);
// Присваиваем реквизиту формы адрес во временном хранилище
// Платформа автоматически считает изображение по этому адресу и отобразит его в поле
АдресИзображенияТовара = ПоместитьВоВременноеХранилище(ОбъектКартинка, УникальныйИдентификатор);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура АдресИзображенияТовараНажатие(Элемент, СтандартнаяОбработка)
// Отменяем стандартное поведение открытия картинки для просмотра
СтандартнаяОбработка = Ложь;
// Реализуем логику нажатия "кнопки"
ПоказатьПредупреждение(, "Вы нажали на картинку товара! Выполняется действие команды...");
КонецПроцедуры
Преимущество этого метода заключается в том, что для обновления изображения на форме нам достаточно обновить строковое значение реквизита АдресИзображенияТовара на клиенте (если адрес уже получен), и форма мгновенно перерисуется без необходимости повторного вызова контекстных серверных процедур для изменения свойств элементов интерфейса.
Современные версии платформы 1С:Предприятие предоставляют расширенные возможности для создания красивых графических интерфейсов. Проанализируем несколько мощных инструментов, которые могут быть полезны при проектировании плиточных меню (например, для фронт-офиса ресторана или магазина):
ОтображатьКакКарточку. Если включить этот режим, кнопка превращается в полноценную плитку. Мы можем задать для нее свойство ФоноваяКартинка. Платформа также позволяет накладывать эффекты размытия или полупрозрачности на фоновое изображение для обеспечения читаемости текста, расположенного поверх картинки.
ПриСозданииНаСервере) мы можем динамически обойти список популярных товаров и сгенерировать сетку кнопок на лету. Посмотрим на пример реализации динамического создания команд и кнопок:
&НаСервере
Процедура СгенерироватьМенюТоваров()
ВыборкаТоваров = Справочники.Номенклатура.Выбрать();
Индекс = 0;
Пока ВыборкаТоваров.Следующий() Цикл
// Проверяем наличие картинки у товара
Если ВыборкаТоваров.ФайлКартинки.Пустая() Тогда
Продолжить;
КонецЕсли;
Индекс = Индекс + 1;
ИмяКоманды = "КомандаТовара_" + Индекс;
ИмяКнопки = "КнопкаТовара_" + Индекс;
// 1. Создаем команду формы
НоваяКоманда = Команды.Добавить(ИмяКоманды);
НоваяКоманда.Заголовок = ВыборкаТоваров.Наименование;
НоваяКоманда.Действие = "ОбработчикНажатияДинамическойКнопки";
// Получаем изображение и преобразуем его
ДвоичныеДанные = ВыборкаТоваров.ФайлКартинки.Получить();
Если ДвоичныеДанные <> Неопределено Тогда
НоваяКоманда.Картинка = Новый Картинка(ДвоичныеДанные);
КонецЕсли;
// 2. Создаем кнопку на форме и связываем ее с командой
НовыйЭлемент = Элементы.Добавить(ИмяКнопки, Тип("КнопкаФормы"), Элементы.ГруппаПлиткаТоваров);
НовыйЭлемент.ИмяКоманды = ИмяКоманды;
НовыйЭлемент.Отображение = ОтображениеКнопки.КартинкаИТекст;
КонецЦикла;
КонецПроцедуры
Для обработки кликов по таким динамическим кнопкам на клиенте используется единый обработчик ОбработчикНажатияДинамическойКнопки, внутри которого разработчик может определить, какая именно кнопка была нажата, проанализировав имя элемента-отправителя.
Мы детально изучили проблему динамического назначения изображений на кнопки управляемых форм и убедились, что утверждения о невозможности такой реализации — не более чем миф. Чтобы успешно применять графические элементы на формах 1С, придерживайтесь следующих правил:
Картинка перед тем, как присвоить их свойствам кнопки или команды на сервере.Команда.Картинка или Элемент.Картинка.