При разработке отчетов в системе компоновки данных (СКД) часто возникает задача визуализации данных. Например, при формировании каталога товаров или списка сотрудников пользователям гораздо удобнее видеть небольшие изображения прямо в строках отчета. Однако просто вывести миниатюру — это лишь половина дела. Полноценный интерфейс предполагает, что при клике на миниатюру пользователь сможет открыть картинку в исходном, высоком разрешении.
В этой статье мы подробно разберем, как решить эту задачу в системе 1С:Предприятие 8. Мы рассмотрим как современные платформенные методы, так и более гибкий программный способ реализации с использованием механизма расшифровки табличного документа.
Начиная с версии платформы 8.3.14, разработчики получили возможность выводить изображения в отчеты СКД без написания сложного программного кода. Если в вашем наборе данных (например, в результате запроса) присутствует поле, содержащее двоичные данные картинки (извлеченные из ХранилищаЗначения) или ссылку на элемент справочника с файлом, мы можем воспользоваться механизмом условного оформления.
Разберем этот процесс по шагам:
При таком подходе платформа самостоятельно отрисует миниатюру в ячейке. Двойной клик по этой миниатюре вызовет стандартное действие расшифровки для данного поля (например, откроет карточку файла или номенклатуры).
Если нам требуется реализовать сложную логику, обеспечить совместимость со старыми версиями платформы или динамически генерировать изображения «на лету» (например, масштабировать их программно), стандартного условного оформления может быть недостаточно. В этом случае мы переходим к программной компоновке отчета.
Для этого в модуле объекта отчета переопределим предопределенную процедуру ПриКомпоновкеРезультата. Установим параметр СтандартнаяОбработка в значение Ложь, чтобы самостоятельно управлять процессом вывода данных.
Проанализируем пример кода, реализующий обход сформированного табличного документа и добавление объектов рисунков с назначением расшифровки:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Инициализируем процессор компоновки и выполняем вывод во временный табличный документ
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
КомпоновщикНастроек = ЭтотОбъект.КомпоновщикНастроек;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.НачатьВывод();
Пока Истина Цикл
ЭлементРезультата = ПроцессорКомпоновки.Следующий();
Если ЭлементРезультата = Неопределено Тогда
Прервать;
КонецЕсли;
ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
КонецЦикла;
ПроцессорВывода.ЗакончитьВывод();
// Переходим к постобработке ячеек табличного документа
ШиринаТаблицы = ДокументРезультат.ШиринаТаблицы;
ВысотаТаблицы = ДокументРезультат.ВысотаТаблицы;
Для СтрокаИндекс = 1 По ВысотаТаблицы Цикл
Для КолонкаИндекс = 1 По ШиринаТаблицы Цикл
ТекущаяЯчейка = ДокументРезультат.Область(СтрокаИндекс, КолонкаИндекс);
ИдентификаторРасшифровки = ТекущаяЯчейка.Расшифровка;
Если ЗначениеЗаполнено(ИдентификаторРасшифровки) Тогда
// Проверяем, что это наш тип расшифровки из структуры данных
Если ТипЗнч(ДанныеРасшифровки) = Тип("ДанныеРасшифровкиКомпоновкиДанных") Тогда
ЭлементРасшифровки = ДанныеРасшифровки.Элементы[ИдентификаторРасшифровки];
Если ТипЗнч(ЭлементРасшифровки) = Тип("ЭлементРасшифровкиКомпоновкиДанныхПоля") Тогда
ПоляРасшифровки = ЭлементРасшифровки.ПолучитьПоля();
ПолеКартинка = ПоляРасшифровки.Найти("ХранилищеКартинки");
Если ПолеКартинка <> Неопределено И ЗначениеЗаполнено(ПолеКартинка.Значение) Тогда
// Получаем двоичные данные из ХранилищаЗначения
ДвоичныеДанные = ПолеКартинка.Значение.Получить();
Если ТипЗнч(ДвоичныеДанные) = Тип("ДвоичныеДанные") Тогда
Попытка
НоваяКартинка = Новый Картинка(ДвоичныеДанные);
// Динамически добавляем рисунок в ячейку табличного документа
РисунокТД = ДокументРезультат.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
РисунокТД.Картинка = НоваяКартинка;
РисунокТД.Расположить(ТекущаяЯчейка);
// КЛЮЧЕВОЙ МОМЕНТ: Назначаем рисунку расшифровку ячейки
РисунокТД.Расшифровка = ИдентификаторРасшифровки;
// Скрываем текст самой ячейки, чтобы он не накладывался под картинку
ТекущаяЯчейка.Текст = "";
Исключение
// Обработка некорректного формата двоичных данных
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
В приведенном коде критически важным является присвоение значения свойству РисунокТД.Расшифровка. По умолчанию динамически добавляемые на форму рисунки табличного документа не имеют привязки к расшифровке компоновки данных. Присвоив свойству Расшифровка идентификатор расшифровки текущей ячейки, мы связываем графический объект с контекстом данных отчета.
После того как отчет сформирован, нам необходимо перехватить клик пользователя по рисунку миниатюры. Для этого мы задействуем обработчик события поля табличного документа на управляемой форме отчета (обычно это поле называется Результат).
Создадим на клиенте обработчик события РезультатОбработкаРасшифровки. Проанализируем алгоритм обработки:
&НаКлиенте
Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка, ДополнительныеПараметры)
// Отменяем стандартное открытие расшифровки платформой
СтандартнаяОбработка = Ложь;
// Получаем адрес временного хранилища, куда поместим полноразмерное изображение
АдресКартинки = ПолучитьАдресКартинкиНаСервере(Расшифровка, АдресДанныхРасшифровки);
Если ЗначениеЗаполнено(АдресКартинки) Тогда
// Открываем вспомогательную форму для просмотра полноразмерного изображения
ПараметрыОткрытия = Новый Структура;
ПараметрыОткрытия.Вставить("АдресКартинки", АдресКартинки);
ОткрытьФорму("ОбщаяФорма.ПросмотрИзображения", ПараметрыОткрытия, ЭтотОбъект);
КонецЕсли;
КонецПроцедуры
Теперь напишем серверную функцию ПолучитьАдресКартинкиНаСервере. Она принимает идентификатор расшифровки, считывает данные из временного хранилища расшифровки СКД, находит исходную тяжелую картинку (или ссылку на нее) и помещает двоичные данные во временное хранилище, возвращая строку-адрес для клиента. Такой подход оптимизирует передачу тяжелых объектов между сервером и клиентом.
&НаСервереБезКонтекста
Функция ПолучитьАдресКартинкиНаСервере(Знач ИдентификаторРасшифровки, Знач АдресДанныхРасшифровки)
ДанныеДетализации = ПолучитьИзВременногоХранилища(АдресДанныхРасшифровки);
Если ДанныеДетализации = Неопределено Тогда
Возврат "";
КонецЕсли;
ЭлементРасшифровки = ДанныеДетализации.Элементы.Получить(ИдентификаторРасшифровки);
Если ЭлементРасшифровки = Неопределено Тогда
Возврат "";
КонецЕсли;
ПоляРасшифровки = ЭлементРасшифровки.ПолучитьПоля();
ПолеСсылка = ПоляРасшифровки.Найти("СсылкаНаФайл"); // Имя вашего поля в СКД
Если ПолеСсылка <> Неопределено И ЗначениеЗаполнено(ПолеСсылка.Value) Тогда
// Извлекаем двоичные данные оригинального файла (например, из регистра или справочника)
ДвоичныеДанныеФайла = ПолучитьДвоичныеДанныеОригинала(ПолеСсылка.Value);
Если ДвоичныеДанныеФайла <> Неопределено Тогда
// Помещаем во временное хранилище и возвращаем адрес
Возврат ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла);
КонецЕсли;
КонецЕсли;
Возврат "";
КонецФункции
При тестировании разработанного функционала вы можете столкнуться с тем, что клик по картинке не вызывает процедуру РезультатОбработкаРасшифровки, а лишь выделяет рисунок рамкой. Выясним основные причины подобного поведения:
ТолькоПросмотр = Истина или Защита = Истина. Если документ открыт для редактирования, платформа считает клик по картинке действием по ее выделению/перемещению. Обязательно устанавливайте это свойство при выводе отчета.ДокументРезультат.Очистить(). Данный метод корректно удаляет не только текстовые значения ячеек, но и всю связанную коллекцию динамически сгенерированных рисунков. В противном случае старые картинки будут наслаиваться друг на друга, что приведет к катастрофическому падению производительности.ТабличногоДокумента является ресурсоемкой процедурой. Если ваш отчет предполагает вывод тысяч строк с картинками, храните в базе данных готовые легкие миниатюры (например, с разрешением 100х100 пикселей) отдельно от оригинальных тяжелых файлов. Выводите в отчет именно легкие миниатюры, а при расшифровке считывайте исходный тяжелый файл с диска или из СУБД.Используя предложенные методики, мы можем гибко управлять выводом графических элементов в отчетах СКД, обеспечивая пользователям удобный и интерактивный интерфейс для работы с изображениями.