Как реализовать фотогалерею с пагинацией и динамической загрузкой картинок на управляемой форме?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов в 1С часто возникает задача визуализации данных, например, создания каталога товаров или, как в нашем случае, фотогалереи сотрудников или событий. Задача кажется тривиальной, пока мы не сталкиваемся с ограничениями и особенностями управляемых форм.

В этой статье мы подробно разберем, как правильно организовать вывод изображений из справочника на форму, реализуем механизм перелистывания страниц (пагинацию) и исправим распространенные ошибки, возникающие при попытке программного присвоения картинок элементам формы.

Анализ задачи и типичные ошибки

Рассмотрим исходную ситуацию. У нас есть справочник Фотографии, в котором хранятся изображения (в реквизите типа ХранилищеЗначения). Нам необходимо создать общую форму, которая будет отображать по 12 фотографий на странице с возможностью перелистывания.

Частая ошибка, которую допускают разработчики, заключается в попытке обратиться к данным картинки через коллекцию Элементы. Рассмотрим ошибочный код:


// ОШИБКА: Попытка присвоить данные свойству элемента
Элементы["Фото" + Номер].Данные = ТекущееФото.ХранилищеКартинки.Получить();

При выполнении этого кода платформа выдаст ошибку: "Поле объекта не обнаружено (Данные)". Давайте разберемся, почему это происходит.

Архитектура управляемых форм разделяет данные (Реквизиты формы) и интерфейс (Элементы формы). Свойство ПутьКДанным у элемента формы задается в конфигураторе и связывает элемент с реквизитом. В режиме предприятия мы не можем менять привязку данных (свойство DataPath или Данные у элемента часто доступно только для чтения или вообще отсутствует в контексте выполнения).

Правильный подход: Чтобы изменить картинку на экране, нужно изменить значение реквизита формы, к которому привязан элемент. Сам элемент (поле картинки) автоматически обновится, как только изменятся данные в реквизите.

Подготовка формы для галереи

Для реализации галереи из 12 фото нам потребуется:

  1. Создать на форме 12 реквизитов типа Строка. Назовем их, например, АдресФото1, АдресФото2 ... АдресФото12. Почему строка, а не картинка? Потому что управляемая форма оперирует адресами во временном хранилище или навигационными ссылками, а не двоичными данными напрямую.
  2. Создать 12 элементов формы вида Поле картинки.
  3. В свойстве ПутьКДанным каждого элемента указать соответствующий строковый реквизит (АдресФото1 и т.д.).

Способ 1: Использование навигационных ссылок (Рекомендуемый)

Если фотографии уже сохранены в базе данных (в справочнике), самым эффективным способом их отображения является использование навигационных ссылок. Этот метод не требует передачи тяжелых двоичных данных с сервера на клиент при формировании формы. Браузер (или тонкий клиент) сам подгрузит картинку по ссылке в момент отрисовки.

Рассмотрим, как это реализовать в коде.


&НаКлиенте
Процедура ОбновитьГалерею()
    
    // Очищаем старые данные перед заполнением
    Для Номер = 1 По 12 Цикл
        ЭтаФорма["АдресФото" + Номер] = "";
        Элементы["Фото" + Номер].Видимость = Ложь;
    КонецЦикла;
    
    // Получаем выборку ссылок для текущей страницы
    // Предположим, у нас есть массив ссылок МассивВсехФото и мы знаем текущий индекс
    
    ИндексВМассиве = (НомерТекущейСтраницы - 1) * 12;
    Для Номер = 1 По 12 Цикл
        
        Если ИндексВМассиве > МассивВсехФото.ВГраница() Тогда
            Прервать;
        КонецЕсли;
        
        СсылкаНаФотографию = МассивВсехФото[ИндексВМассиве];
        
        // Получаем навигационную ссылку на реквизит "ХранилищеКартинки"
        // Формат: e1cib/data/Справочник.Фотографии.ХранилищеКартинки?ref=...
        НавСсылка = ПолучитьНавигационнуюСсылку(СсылкаНаФотографию, "ХранилищеКартинки");
        
        // Присваиваем ссылку РЕКВИЗИТУ формы (через ЭтаФорма или ЭтотОбъект)
        ЭтаФорма["АдресФото" + Номер] = НавСсылка;
        
        // Включаем видимость элемента
        Элементы["Фото" + Номер].Видимость = Истина;
        
        ИндексВМассиве = ИндексВМассиве + 1;
        
    КонецЦикла;

КонецПроцедуры

Обратите внимание на использование функции ПолучитьНавигационнуюСсылку. Она работает на клиенте и не требует серверного вызова, если у вас уже есть ссылка на объект.

Способ 2: Использование Временного Хранилища

Иногда требуется отобразить картинку, которая еще не записана в базу, или была программно обработана перед показом. В этом случае навигационная ссылка не сработает, и нужно использовать временное хранилище.

Этот код должен выполняться на сервере, так как метод Получить() у хранилища значения доступен только там.


&НаСервере
Процедура ЗаполнитьКартинкиНаСервере(МассивСсылок)
    
    Для Индекс = 0 По МассивСсылок.ВГраница() Цикл
        
        Если Индекс >= 12 Тогда Прервать; КонецЕсли;
        
        ТекущееФотоОбъект = МассивСсылок[Индекс].ПолучитьОбъект();
        ДвоичныеДанные = ТекущееФотоОбъект.ХранилищеКартинки.Получить();
        
        Если ДвоичныеДанные <> Неопределено Тогда
            // Помещаем данные во временное хранилище, привязывая к УИД формы
            Адрес = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);
            
            // Присваиваем адрес реквизиту формы
            ИмяРеквизита = "АдресФото" + (Индекс + 1);
            ЭтаФорма[ИмяРеквизита] = Адрес;
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Важно: Этот метод менее производителен для простых галерей, так как требует передачи самих данных картинки на сервер, помещения их в память, а затем передачи адреса на клиент. Используйте его только при необходимости.

Реализация пагинации (Листания страниц)

Разберем логику кнопок навигации. Чтобы галерея работала быстро, не стоит каждый раз запрашивать все данные. Но для простой реализации (если фото не миллионы) можно получить массив всех ссылок при открытии формы.

Добавим реквизиты формы:

Логика кнопок:


&НаКлиенте
Процедура СледующаяСтраница(Команда)
    Если НомерТекущейСтраницы < ВсегоСтраниц Тогда
        НомерТекущейСтраницы = НомерТекущейСтраницы + 1;
        ОбновитьГалерею();
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПредыдущаяСтраница(Команда)
    Если НомерТекущейСтраницы > 1 Тогда
        НомерТекущейСтраницы = НомерТекущейСтраницы - 1;
        ОбновитьГалерею();
    КонецЕсли;
КонецПроцедуры

При вычислении общего количества страниц используйте формулу с округлением вверх:


ВсегоСтраниц = Окр(МассивВсехФото.Количество() / 12 + 0.49, 0, РежимОкругления.Окр15как10);
// Или математически: Цел((Количество - 1) / 12) + 1

Альтернативный подход: Поле HTML документа

В теме обсуждения справедливо заметили, что создание 12 фиксированных элементов на форме — это "жесткий" подход. Если вы хотите более гибкий интерфейс, современный дизайн и адаптивность, стоит рассмотреть использование поля HTML-документа.

В этом случае вы создаете всего один реквизит формы (строка неограниченной длины) с HTML-кодом. И один элемент формы вида Поле HTML документа.

Принцип действия:

  1. На сервере вы формируете строку HTML, содержащую теги <img>.
  2. В атрибут src тегов img вы подставляете те же самые навигационные ссылки.

&НаСервере
Процедура СформироватьHTMLГалерею()
    
    HTMLТекст = "<html><body style='display:flex; flex-wrap:wrap;'>";
    
    Для Каждого СсылкаНаФото Из ВыборкаФотографий Цикл
        СсылкаНаКартинку = ПолучитьНавигационнуюСсылку(СсылкаНаФото, "ХранилищеКартинки");
        HTMLТекст = HTMLТекст + 
            "<div style='margin:10px;'>" +
            "<img src='" + СсылкаНаКартинку + "' width='200' height='200' />" +
            "</div>";
    КонецЦикла;
    
    HTMLТекст = HTMLТекст + "</body></html>";
    
    // Присваиваем реквизиту, связанному с полем HTML
    РеквизитHTMLПоле = HTMLТекст;
    
КонецПроцедуры

Этот метод позволяет делать галерею резиновой, автоматически переносить картинки на новые строки в зависимости от ширины экрана и использовать всю мощь CSS для оформления рамок, теней и анимации.

Оптимизация производительности

При работе с изображениями всегда помните о размере трафика. Если пользователи загружают фото по 10 Мб, то страница из 12 фото будет весить более 100 Мб, что "повесит" клиентское приложение.

Рекомендация: В справочнике Фотографии создайте два реквизита:

  1. Оригинал (ХранилищеЗначения) — исходное фото высокого качества.
  2. Миниатюра (ХранилищеЗначения) — уменьшенная копия (например, 200x200 пикселей).

При загрузке фото создавайте миниатюру программно (используя объект ОбработкаКартинок). В списке галереи выводите навигационные ссылки именно на реквизит Миниатюра. А оригинал показывайте только при клике на конкретное фото в отдельном окне.

← На главную