При разработке интерфейсов на управляемых формах 1С 8.3 программисты часто сталкиваются с задачей вывода списка товаров, содержащего изображения. Типичный сценарий — интерактивный выбор позиций, при котором пользователю необходимо визуально идентифицировать товар по фотографии и отметить его флажком. Однако стандартное размещение элемента Поле картинки внутри ячейки таблицы (будь то таблица значений или динамический список) сталкивается с серьезными ограничениями платформы.
В этой статье мы подробно разберем, почему возникает проблема искажения размеров картинок в строках таблиц, проанализируем доступные обходные пути и реализуем оптимальные технические решения.
Стандартный элемент управления Поле картинки, находящийся непосредственно на управляемой форме, обладает широким набором свойств масштабирования. Однако при его переносе внутрь ячейки таблицы поведение кардинально меняется. Мы сталкиваемся со следующими особенностями платформы:
РазмерКартинки (такие как Пропорционально или Растянуть) часто не отрабатывают внутри строк таблицы.Выяснив причину ограничений, рассмотрим два основных и наиболее эффективных способа решения этой задачи.
Поскольку платформа не способна качественно масштабировать тяжелые изображения "на лету" внутри ячеек табличной части, мы применим метод предварительной подготовки картинок. Мы будем генерировать уменьшенные копии (миниатюры) нужного размера на стороне сервера и передавать в таблицу их навигационные ссылки.
Для изменения разрешения картинки воспользуемся встроенным объектом платформы 1С 8.3 — ОбрабатываемаяКартинка. Это позволит нам обойтись без внешних компонент и библиотек.
Разберем по шагам серверный код, выполняющий сжатие картинки под заданный размер ячейки:
&НаСервере
Функция ПолучитьАдресМиниатюры(ИсходныеДанныеКартинки, ТребуемаяШирина)
Если НЕ ЗначениеЗаполнено(ИсходныеДанныеКартинки) Тогда
Возврат "";
КонецЕсли;
Попытка
// Извлекаем исходную картинку из двоичных данных или ХранилищаЗначений
Если ТипЗнч(ИсходныеДанныеКартинки) = Тип("ХранилищеЗначений") Тогда
ДвоичныеДанные = ИсходныеДанныеКартинки.Получить();
Иначе
ДвоичныеДанные = ИсходныеДанныеКартинки;
КонецЕсли;
ИсходнаяКартинка = Новый Картинка(ДвоичныеДанные);
// Инициализируем объект обработки изображения
ОбработкаИзображения = Новый ОбрабатываемаяКартинка(ИсходнаяКартинка);
// Устанавливаем размер. Передавая "Неопределено" во второй параметр,
// мы заставляем платформу автоматически рассчитать высоту с сохранением пропорций.
ОбработкаИзображения.УстановитьРазмер(ТребуемаяШирина, Неопределено);
// Получаем уменьшенное изображение
Миниатюра = ОбработкаИзображения.ПолучитьКартинку();
// Помещаем полученную миниатюру во временное хранилище формы
АдресХранилища = ПоместитьВоВременноеХранилище(Миниатюра, УникальныйИдентификатор);
Возврат АдресХранилища;
Исключение
// В случае ошибки формата возвращаем пустую строку
Возврат "";
КонецПопытки;
КонецФункции
Проанализируем этот алгоритм: полученный адрес временного хранилища мы записываем в колонку таблицы значений, которая имеет тип Строка, а на форме этот элемент отображается как Поле картинки. Для корректного вывода нам достаточно установить высоту строк таблицы равной, например, 3 или 4, а ширину колонки сопоставить с переданным параметром ТребуемаяШирина (например, 80–100 пикселей). Теперь картинка идеально впишется в отведенную ячейку без искажения пропорций.
Важный совет по оптимизации: Сжатие сотен изображений при каждом открытии формы может привести к заметным задержкам интерфейса. Если список товаров велик, рекомендуется кэшировать миниатюры. Например, генерировать уменьшенные копии один раз при записи карточки номенклатуры и сохранять их в отдельный реквизит или регистр сведений.
Если вам требуется максимальная гибкость в оформлении, выводе галочек и картинок, рассмотрим альтернативный вариант — замену стандартной таблицы значений на элемент формы Поле HTML-документа. С помощью HTML и CSS мы можем легко управлять масштабированием изображений, позиционированием флажков выбора и стилизацией строк.
Посмотрим на пример формирования HTML-кода таблицы на сервере:
&НаСервере
Функция СформироватьHTMLТаблицу(ТаблицаТоваров)
ТекстHTML = "<html><head><style>
|table { width: 100%; border-collapse: collapse; }
|td { padding: 8px; border-bottom: 1px solid #ddd; text-align: left; }
|img { max-width: 100px; height: auto; border-radius: 4px; }
|.checkbox-col { width: 40px; text-align: center; }
|</style></head><body>";
ТекстHTML = ТекстHTML + "<table>";
Для Каждого СтрокаТовара Из ТаблицаТоваров Цикл
// Получаем навигационную ссылку на картинку
АдресКартинки = ПоместитьВоВременноеХранилище(СтрокаТовара.Картинка.Получить(), УникальныйИдентификатор);
СостояниеФлажка = ?(СтрокаТовара.Выбран, "checked", "");
IDТовара = СтрокаТовара.Товар.УникальныйИдентификатор();
ТекстHTML = ТекстHTML + "<tr>";
// Колонка с интерактивным флажком
ТекстHTML = ТекстHTML + "<td class='checkbox-col'>";
ТекстHTML = ТекстHTML + "<input type='checkbox' " + СостояниеФлажка + " onclick='window.location.href=""v8action:select_row?id=" + IDТовара + """ "'>";
ТекстHTML = ТекстHTML + "</td>";
// Колонка с картинкой
ТекстHTML = ТекстHTML + "<td><img src='" + АдресКартинки + "'></td>";
// Колонка с наименованием
ТекстHTML = ТекстHTML + "<td><strong>" + СтрокаТовара.ТоварНаименование + "</strong></td>";
ТекстHTML = ТекстHTML + "</tr>";
КонецЦикла;
ТекстHTML = ТекстHTML + "</table></body></html>";
Возврат ТекстHTML;
КонецФункции
Для того чтобы управляемая форма 1С могла реагировать на действия пользователя внутри HTML-документа (в данном случае — на нажатие по чекбоксу), мы используем специальную схему URL v8action:. При нажатии на флажок срабатывает событие перехода по ссылке.
Разберем по шагам, как перехватить это событие на клиенте в модуле управляемой формы:
&НаКлиенте
Процедура ПолеHTMLПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
// Получаем адрес перехода
АдресПерехода = ДанныеСобытия.Href;
// Проверяем, наше ли это событие
Если Найти(АдресПерехода, "v8action:select_row") > 0 Тогда
// Отменяем стандартный переход браузера по ссылке
СтандартнаяОбработка = Ложь;
// Выделяем идентификатор нажатого товара
ПозицияПараметра = Найти(АдресПерехода, "?id=");
ИдентификаторСтроки = Сред(АдресПерехода, ПозицияПараметра + 4);
// Обрабатываем выбор на сервере
ОбработатьВыборТовараНаСервере(ИдентификаторСтроки);
// Обновляем HTML-поле для визуализации изменений
ОбновитьОтображениеHTML();
КонецЕсли;
КонецПроцедуры
Такой подход полностью развязывает руки разработчику в плане верстки: картинки будут масштабироваться плавно и красиво средствами веб-движка, а пользователь получит быстрый и отзывчивый интерфейс.
Если количество товаров в списке измеряется сотнями или тысячами, вывод всех картинок одновременно в таблицу (даже в сжатом виде) неизбежно приведет к перерасходу оперативной памяти и замедлению работы веб-клиента. В таких случаях мы рекомендуем использовать классический паттерн проектирования интерфейсов:
Поле картинки.ПриАктивизацииСтроки на клиенте мы динамически получаем адрес картинки текущего выделенного товара и помещаем его в эту область просмотра.Этот способ гарантирует мгновенный отклик интерфейса при навигации и избавляет от необходимости решать сложные проблемы группового масштабирования графики в ячейках.