При разработке внешних обработок в 1С:Предприятии часто возникает необходимость создания гибких и адаптивных печатных форм. Это может включать динамическое размещение различных информационных блоков, каждый из которых содержит текст, штрихкоды и графические элементы, например, стрелки. Нередко требуется программно изменять свойства этих элементов, такие как направление стрелки или количество блоков в строке. Давайте разберем, как мы можем решить эти задачи, используя стандартные средства платформы 1С.
Один из ключевых вопросов, который часто возникает, — это возможность программного поворота графических изображений. Например, если у нас есть стандартная картинка стрелки, и нам нужно изменить её направление (влево, вправо, вверх, вниз), не прибегая к хранению множества предварительно повернутых вариантов. Несмотря на то, что многие разработчики сталкиваются с мнением о невозможности такой операции стандартными средствами, на самом деле платформа 1С предоставляет мощный инструмент для этого — объект ОбрабатываемаяКартинка (в некоторых контекстах и версиях может упоминаться как ОбрабатываемоеИзображение).
Объект ОбрабатываемаяКартинка специально разработан для программной манипуляции изображениями. Он позволяет нам не только поворачивать, но и масштабировать, обрезать и применять другие трансформации к графике непосредственно из кода 1С.
Повернуть()Для поворота изображения мы будем использовать метод Повернуть(Угол: Число). Этот метод позволяет повернуть изображение по часовой стрелке на указанное число градусов.
ОбрабатываемаяКартинка на основе нашего исходного изображения. Это может быть картинка из макета, из встроенных картинок обработки или из внешнего файла.Повернуть(), передавая ему необходимый угол в градусах. Например, для поворота на 90 градусов по часовой стрелке мы передадим 90.Повернуть() возвращает новый объект ОбрабатываемаяКартинка, содержащий повернутое изображение. Мы можем затем использовать его для вывода в табличный документ или сохранения.Важно учитывать некоторые особенности при повороте:
Shape.Rotation). Однако для работы непосредственно внутри 1С для вывода в табличный документ ОбрабатываемаяКартинка является наиболее подходящим и универсальным решением.Давайте рассмотрим пример кода, как можно повернуть картинку:
// Предположим, у нас есть картинка в макете обработки
Макет = ПолучитьМакет("МакетДляПечати");
ОбластьМакетаСКартинкой = Макет.ПолучитьОбласть("КартинкаСтрелкаПоУмолчанию");
ИсходнаяКартинка = ОбластьМакетаСКартинкой.Рисунки.Найти("Стрелка").Картинка;
// Создаем обрабатываемый объект на основе исходной картинки
Обрабатываемая = Новый ОбрабатываемаяКартинка(ИсходнаяКартинка);
// Определяем угол поворота, например, 90 градусов по часовой стрелке
УголПоворота = 90;
// Выполняем поворот
ПовернутаяКартинка = Обрабатываемая.Повернуть(УголПоворота);
// Теперь ПовернутаяКартинка содержит изображение, повернутое на 90 градусов.
// Мы можем присвоить ее другому элементу Рисунок в области вывода
// или непосредственно использовать для вывода.
// Пример присвоения повернутой картинки элементу Рисунок в области вывода
ОбластьБлокаДляВывода = Макет.ПолучитьОбласть("Блок");
Если ОбластьБлокаДляВывода.Рисунки.Найти("РисунокСтрелка") <> Неопределено Тогда
ОбластьБлокаДляВывода.Рисунки.Найти("РисунокСтрелка").Картинка = ПовернутаяКартинка;
КонецЕсли;
// Далее мы можем вывести ОбластьБлокаДляВывода в табличный документ.
Следующая задача, с которой мы часто сталкиваемся, — это необходимость динамически "размножать" блоки как по горизонтали, так и по вертикали в печатной форме, формируя своего рода сетку. Стандартный подход с использованием метода Вывести() позволяет нам добавлять области только по вертикали, каждая новая область начинается с новой строки. Однако для создания строк из нескольких блоков нам потребуется использовать комбинацию методов.
Вывести() и Присоединить()Для создания гибких макетов, где блоки располагаются в несколько столбцов и строк, мы будем использовать два основных метода табличного документа:
Вывести(Область: ТабличныйДокументОбласть): Этот метод выводит указанную область в табличный документ, начиная с новой строки. Он обычно используется для вертикального добавления строк, например, при выводе строк табличной части.Присоединить(Область: ТабличныйДокументОбласть): Этот метод является ключевым для горизонтального размещения. Он добавляет указанную область справа от предыдущей выведенной или присоединенной области в текущей строке. Если текущая строка пуста или предыдущая область была выведена методом Вывести(), то Присоединить() начнет новую группу присоединяемых областей с текущей позиции.Для реализации вывода блоков по горизонтали и вертикали (например, "блок1 | блок2 | блок3", затем новая строка "блок4 | блок5 | блок6") мы будем использовать следующую логику:
Вывести(). Это гарантирует, что блок начнется с новой строки.Присоединить(). Это позволит нам разместить их рядом с первым блоком по горизонтали.Вывести() для первого блока новой строки.Мы также можем использовать метод ПроверитьПрисоединение(СписокОбластей: Массив). Этот метод позволяет нам проверить, поместится ли список областей по горизонтали на текущей странице, не увеличивая количество страниц. Это полезно для предварительной оценки компоновки и предотвращения нежелательных переносов.
Давайте рассмотрим пример формирования табличного документа с блоками в несколько столбцов:
// Параметры для формирования макета
КоличествоБлоковВСтроке = 2; // Или 4, или 8
ВсеБлокиДляВывода = Новый Массив(); // Здесь будут наши подготовленные области "Блок"
// Предположим, мы уже подготовили 6 областей "Блок"
// и добавили их в массив ВсеБлокиДляВывода.
// Например:
// Для Каждого ДанныеБлока Из СписокДанныхПоБлокам Цикл
// ОбластьБлок = Макет.ПолучитьОбласть("Блок");
// ЗаполнитьПараметрыОбластиБлока(ОбластьБлок, ДанныеБлока);
// ВсеБлокиДляВывода.Добавить(ОбластьБлок);
// КонецЦикла;
ТабДок = Новый ТабличныйДокумент;
СчетчикБлоковВСтроке = 0;
Для Каждого ТекущийБлок Из ВсеБлокиДляВывода Цикл
Если СчетчикБлоковВСтроке = 0 Тогда
// Это первый блок в новой строке, выводим его
ТабДок.Вывести(ТекущийБлок);
Иначе
// Это последующий блок в текущей строке, присоединяем его
ТабДок.Присоединить(ТекущийБлок);
КонецЕсли;
СчетчикБлоковВСтроке = СчетчикБлоковВСтроке + 1;
Если СчетчикБлоковВСтроке = КоличествоБлоковВСтроке Тогда
// Достигнуто максимальное количество блоков в строке,
// сбрасываем счетчик для начала новой строки
СчетчикБлоковВСтроке = 0;
КонецЕсли;
КонецЦикла;
// Дополнительные настройки табличного документа, если необходимо
// ТабДок.Показать();
Этот подход позволяет нам гибко управлять количеством блоков в каждой строке и легко адаптировать макет под различные требования, используя всего одну базовую область "Блок" в макете.
Если мы решаем не использовать программный поворот изображений или хотим иметь готовые варианты для повышения производительности или упрощения кода, возникает вопрос об оптимальном хранении множества вариаций картинок (например, стрелок, повернутых в разные стороны). Особенно это актуально для внешних обработок, которые должны быть самодостаточными.
Давайте рассмотрим несколько эффективных способов реализации "библиотеки" картинок во внешней обработке:
Это самый простой и часто наиболее удобный способ. Мы можем добавить все необходимые варианты картинок (стрелки влево, вправо, вверх, вниз и т.д.) непосредственно в объект конфигурации "Картинки" внутри самой внешней обработки. В конфигураторе 1С для внешней обработки есть раздел "Картинки". Мы просто добавляем туда нужные изображения, даем им осмысленные имена (например, "СтрелкаВверх", "СтрелкаВниз").
Преимущества: Простота реализации, картинки всегда доступны вместе с обработкой, не нужно управлять внешними файлами.
Как использовать: Обращение к таким картинкам происходит по их имени из кода:
// Для встроенных картинок 1С
КартинкаДляБлока = БиблиотекаКартинок.Получить("СтрелкаВверх");
// Или, если картинка в составе внешней обработки:
// Здесь "ИмяВашейОбработки" нужно заменить на фактическое имя внешней обработки в ИБ
КартинкаДляБлока = ВнешниеОбработки.Получить("ИмяВашейОбработки").Картинки.Получить("СтрелкаВверх");
Идея, предложенная в исходном сообщении, является весьма жизнеспособной. Мы можем создать в макете обработки специальную область (например, "БиблиотекаКартинок"), где разместим все необходимые варианты стрелок как отдельные элементы "Рисунок". Каждому такому элементу "Рисунок" внутри этой области мы присваиваем уникальное имя (например, "СтрелкаНаправо", "СтрелкаВлево").
Как использовать: При формировании печатной формы, в зависимости от выбранного параметра, мы получаем нужную картинку из этой "библиотечной" области и присваиваем её элементу "Рисунок" в области, предназначенной для вывода.
// Получаем макет обработки
Макет = ПолучитьМакет("МакетДляПечати");
// Получаем область с библиотекой картинок
ОбластьБиблиотеки = Макет.ПолучитьОбласть("БиблиотекаКартинок");
// Выбираем нужную картинку по условию
ПеременнаяНаправлениеСтрелки = "Вправо"; // Предположим, этот параметр пришел из формы
ВыбраннаяКартинка = Неопределено;
Если ПеременнаяНаправлениеСтрелки = "Вправо" Тогда
Если ОбластьБиблиотеки.Рисунки.Найти("СтрелкаНаправо") <> Неопределено Тогда
ВыбраннаяКартинка = ОбластьБиблиотеки.Рисунки.Найти("СтрелкаНаправо").Картинка;
КонецЕсли;
ИначеЕсли ПеременнаяНаправлениеСтрелки = "Влево" Тогда
Если ОбластьБиблиотеки.Рисунки.Найти("СтрелкаВлево") <> Неопределено Тогда
ВыбраннаяКартинка = ОбластьБиблиотеки.Рисунки.Найти("СтрелкаВлево").Картинка;
КонецЕсли;
КонецЕсли;
// ... и так далее для других направлений
// Получаем область блока для вывода и присваиваем ей выбранную картинку
Если ВыбраннаяКартинка <> Неопределено Тогда
ОбластьБлокаДляВывода = Макет.ПолучитьОбласть("Блок");
Если ОбластьБлокаДляВывода.Рисунки.Найти("РисунокСтрелка") <> Неопределено Тогда
ОбластьБлокаДляВывода.Рисунки.Найти("РисунокСтрелка").Картинка = ВыбраннаяКартинка;
КонецЕсли;
КонецЕсли;
Преимущества: Картинки находятся внутри макета, что удобно для визуального контроля и редактирования. Обработка остается самодостаточной.
Недостатки: Может усложнить структуру макета, если картинок очень много.
Если картинок очень много, или они должны быть доступны не только из текущей обработки, или же они генерируются динамически и их нужно сохранять, мы можем использовать тип данных ХранилищеЗначений. Это может быть реквизит на форме обработки или реквизит объекта метаданных (например, регистра сведений или справочника), если обработка взаимодействует с данными.
Как использовать: Картинка помещается в ХранилищеЗначений, а при необходимости извлекается. Для вывода на форму или в табличный документ, картинка из хранилища обычно помещается во временное хранилище, а затем используется адрес временного хранилища.
// Сохранение картинки в хранилище значений
МояКартинка = Новый Картинка("ПутьКФайлу.png"); // Или из макета
ХранилищеКартинки = Новый ХранилищеЗначений(МояКартинка);
// Извлечение картинки из хранилища значений и помещение во временное хранилище для вывода
ИзвлеченнаяКартинка = ХранилищеКартинки.Получить();
АдресВоВременномХранилище = ПоместитьВоВременноеХранилище(ИзвлеченнаяКартинка);
// Присваиваем адрес элементу формы типа ПолеКартинки или Рисунку в табличном документе
// Элементы.ПолеКартинкиНаФорме.Картинка = АдресВоВременномХранилище;
// ОбластьБлокаДляВывода.Рисунки.Найти("РисунокСтрелка").Картинка = АдресВоВременномХранилище;
Преимущества: Гибкость, возможность хранения больших объемов данных, интеграция с базой данных.
Недостатки: Более сложная логика работы с хранилищем и временным хранилищем.
Этот подход особенно удобен, когда картинка изменяется "на лету" (например, после поворота с помощью ОбрабатываемаяКартинка) и её нужно отобразить на форме или вывести в табличный документ без постоянного сохранения. Результат работы с ОбрабатываемаяКартинка можно сразу поместить во временное хранилище.
Как использовать: Метод ПоместитьВоВременноеХранилище() возвращает уникальный адрес, который можно присвоить строковому реквизиту формы, связанному с полем картинки, или использовать для элемента Рисунок табличного документа.
// ПовернутаяКартинка - это результат работы ОбрабатываемаяКартинка.Повернуть()
АдресВХранилище = ПоместитьВоВременноеХранилище(ПовернутаяКартинка, УникальныйИдентификаторФормы);
// Присвоение картинке в табличном документе по адресу временного хранилища
// ОбластьБлокаДляВывода.Рисунки.Найти("РисунокСтрелка").Картинка = АдресВХранилище;
Преимущества: Оптимально для временных картинок, не требует постоянного сохранения.
Недостатки: Данные хранятся только на время сеанса или пока не будут удалены.
Для очень большого количества изображений, или если требуется обмен изображениями с внешними системами, можно хранить их в отдельном каталоге на диске. В 1С в этом случае мы будем сохранять только пути к файлам.
Преимущества: Легкое управление большими объемами, возможность использования внешними приложениями.
Недостатки: Требует отдельного резервного копирования файлов, контроль целостности данных, доступность файлов по указанному пути для всех пользователей, которые будут печатать.
Base64Строка для HTML-полей (специфический случай):
Если блоки выводятся в HTML-поле (например, для отображения в веб-клиенте), и прямая ссылка на картинку из библиотеки или временного хранилища по какой-либо причине не работает, можно закодировать двоичные данные картинки в строку Base64 и вставить её непосредственно в HTML-код как Data URI. Например: <img src="data:image/png;base64,iVBORw0KGgo...">.
Преимущества: Картинка встроена прямо в HTML, не требует отдельных запросов к серверу для каждого изображения.
Недостатки: Увеличивает размер HTML-кода, не всегда удобно для большого количества изображений, поддерживается не всеми браузерами и не всеми версиями 1С.
При выборе способа хранения важно оценить объем картинок, частоту их использования, необходимость динамического изменения и особенности среды выполнения (тонкий/толстый/веб-клиент).
Мы рассмотрели различные подходы к решению задач динамического размещения блоков и манипуляции изображениями в макетах 1С. Комбинируя эти методы, мы можем создавать высокофункциональные и адаптивные печатные формы, которые будут отвечать самым сложным требованиям. Для доработки уже сформированных типовых документов конфигурации подойдёт обработка для постобработки печатных форм на базе БСП.