Как вывести все прикрепленные фотографии на форму 1С с прокруткой?

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

При разработке информационных систем на платформе 1С:Предприятие 8.3 часто возникает задача отображения большого количества графических файлов, прикрепленных к какому-либо объекту (например, к документу, справочнику или записи регистра). В случаях, когда таких файлов много, их необходимо выводить с возможностью прокрутки, чтобы пользователь мог комфортно просматривать все изображения, не переходя на отдельные формы для каждого из них. Типовые механизмы 1С предоставляют базовые возможности для работы с одним изображением или их последовательного переключения, но для создания полноценной галереи с прокруткой требуются дополнительные шаги.

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

Подход 1: Использование Поля HTML документа

Одним из мощных и гибких способов отображения интерактивного контента на формах 1С является использование элемента


Поле HTML документа
. Этот элемент фактически представляет собой встроенный браузер WebKit, позволяющий отображать HTML-код, включая изображения, с использованием всех возможностей HTML и CSS.

Принцип работы: Мы генерируем HTML-строку, которая содержит теги <img> для каждого изображения, а затем присваиваем эту строку свойству


Значение
или используем метод

УстановитьHTML()
элемента

Поле HTML документа
. Прокрутка в этом случае будет обеспечиваться стандартными механизмами браузера.

Преимущества:

  1. Гибкость и дизайн: Полный контроль над внешним видом галереи с помощью HTML и CSS. Мы можем создавать сложные макеты, добавлять эффекты при наведении, анимации и т.д.
  2. Интерактивность: Возможность встраивания JavaScript для более сложной логики (например, увеличения изображения при клике, перехода к следующему/предыдущему).
  3. Стандартные веб-технологии: Разработчики, знакомые с веб-разработкой, смогут легко применять свои навыки.

Недостатки:

  1. Ресурсоемкость: Как упоминалось в обсуждении,
    
    Поле HTML документа
    
    может быть "тяжеловатым", поскольку это полноценный встроенный браузер, потребляющий значительные системные ресурсы, особенно при большом количестве изображений.
  2. Производительность: Возможна медленная отрисовка при очень большом объеме HTML-кода или большом количестве изображений.
  3. Зависимость от WebKit: Работа элемента может незначительно отличаться в разных версиях платформы или операционных системах.

Пример генерации HTML-кода и его установки:

Для отображения изображений в


Поле HTML документа
их необходимо сделать доступными по URL. Это может быть либо временный файл на диске, либо навигационная ссылка на двоичные данные, либо ссылка на веб-сервер, если файлы опубликованы.

Предположим, у нас есть массив путей или навигационных ссылок на изображения:


Функция СформироватьHTMLГалерею(МассивСсылокНаИзображения)

    HTMLТекст = "
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <style>
            body { font-family: sans-serif; margin: 0; padding: 10px; overflow-y: scroll; background-color: #f0f2f5; }
            .gallery-container {
                display: flex; /* Для горизонтальной прокрутки */
                flex-wrap: wrap; /* Для перехода на новую строку, если нужно */
                gap: 15px; /* Расстояние между элементами */
                padding: 15px;
                overflow-x: auto; /* Горизонтальная прокрутка, если элементы расположены в ряд */
                /* Если мы хотим вертикальную прокрутку, используем flex-direction: column; и overflow-y: auto; */
                max-height: 450px; /* Ограничиваем высоту контейнера для появления вертикальной прокрутки */
                border: 1px solid #dcdcdc;
                border-radius: 8px;
                background-color: #ffffff;
                box-shadow: 0 4px 8px rgba(0,0,0,0.05);
            }
            .image-wrapper {
                border: 1px solid #eaeaea;
                border-radius: 5px;
                padding: 8px;
                text-align: center;
                background-color: #fff;
                box-shadow: 1px 1px 3px rgba(0,0,0,0.08);
                flex-shrink: 0; /* Чтобы элементы не сжимались при горизонтальной прокрутке */
                transition: transform 0.2s ease-in-out;
            }
            .image-wrapper:hover {
                transform: translateY(-3px);
                box-shadow: 2px 2px 6px rgba(0,0,0,0.1);
            }
            .gallery-image {
                max-width: 180px; /* Увеличим размер миниатюр */
                max-height: 180px;
                height: auto;
                width: auto;
                display: block;
                margin: 0 auto;
                cursor: pointer;
                border-radius: 3px;
            }
            .image-title {
                margin-top: 8px;
                font-size: 0.9em;
                color: #555;
            }
        </style>
        <script>
            function openImage(url) {
                // В реальном приложении можно открыть новое окно с изображением или модальное окно
                window.open(url, '_blank');
            }
        </script>
    </head>
    <body>
        <div class="gallery-container">";

    НомерКартинки = 1;
    Для Каждого СсылкаИзображения Из МассивСсылокНаИзображения Цикл
        HTMLТекст = HTMLТекст + "
            <div class="image-wrapper">
                <img src="" + СсылкаИзображения + "" class="gallery-image" onclick="openImage('" + СсылкаИзображения + "');">
                <div class="image-title">Фото " + НомерКартинки + "</div>
            </div>";
        НомерКартинки = НомерКартинки + 1;
    КонецЦикла;

    HTMLТекст = HTMLТекст + "
        </div>
    </body>
    </html>";

    Возврат HTMLТекст;

КонецФункции

// Пример использования на форме 1С:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Предположим, мы как-то получили массивНавигационныхСсылокНаИзображения.
    // Например, из справочника присоединенных файлов или временных файлов.
    МассивНавигационныхСсылокНаИзображения = Новый Массив;
    // ... Заполняем массив реальными ссылками или путями ...

    // Для демонстрации используем заглушки или реальные ссылки
    // (например, ссылки на внешние ресурсы или навигационные ссылки 1С)
    МассивНавигационныхСсылокНаИзображения.Добавить("https://via.placeholder.com/180/FF0000/FFFFFF?text=Photo1");
    МассивНавигационныхСсылокНаИзображения.Добавить("https://via.placeholder.com/180/00FF00/FFFFFF?text=Photo2");
    МассивНавигационныхСсылокНаИзображения.Добавить("https://via.placeholder.com/180/0000FF/FFFFFF?text=Photo3");
    МассивНавигационныхСсылокНаИзображения.Добавить("https://via.placeholder.com/180/FFFF00/000000?text=Photo4");
    МассивНавигационныхСсылокНаИзображения.Добавить("https://via.placeholder.com/180/00FFFF/000000?text=Photo5");
    МассивНавигационныхСсылокНаИзображения.Добавить("https://via.placeholder.com/180/FF00FF/FFFFFF?text=Photo6");
    МассивНавигационныхСсылокНаИзображения.Добавить("https://via.placeholder.com/180/808080/FFFFFF?text=Photo7");
    МассивНавигационныхСсылокНаИзображения.Добавить("https://via.placeholder.com/180/ADD8E6/000000?text=Photo8");
    МассивНавигационныхСсылокНаИзображения.Добавить("https://via.placeholder.com/180/8A2BE2/FFFFFF?text=Photo9");
    МассивНавигационныхСсылокНаИзображения.Добавить("https://via.placeholder.com/180/A52A2A/FFFFFF?text=Photo10");


    // Элемент 'ПолеHTML' должен быть добавлен на форму и привязан к реквизиту формы типа 'Строка'
    // или использоваться метод УстановитьHTML() для непривязанного поля.
    ЭтаФорма.Элементы.ПолеHTML.Значение = СформироватьHTMLГалерею(МассивНавигационныхСсылокНаИзображения);
    // Для непривязанного поля: ЭтаФорма.Элементы.ПолеHTML.УстановитьHTML(СформироватьHTMLГалерею(МассивНавигационныхСсылокНаИзображения));
КонецПроцедуры

Для корректной работы этого подхода необходимо, чтобы


Поле HTML документа
было добавлено на форму (например, с именем

ПолеHTML
), и его свойство

РежимОтображения
было установлено в

Просмотр
или

Редактирование
.

Подход 2: Использование Табличного документа (ТабДок)

Элемент формы


Табличный документ
(или просто

ТабДок
) также предоставляет удобные возможности для отображения структурированных данных, включая изображения, с поддержкой прокрутки. Этот подход может быть более производительным по сравнению с

Полем HTML документа
, особенно при работе с большим объемом данных, так как он использует нативные механизмы платформы.

Принцип работы: Мы динамически формируем табличный документ, вставляя каждое изображение в отдельную ячейку или группу ячеек. Затем этот табличный документ выводится на форму. Прокрутка осуществляется средствами самого элемента


Табличный документ
.

Преимущества:

  1. Производительность: Часто работает быстрее, чем
    
    Поле HTML документа
    
    , так как не требует запуска встроенного браузерного движка.
  2. Нативный интерфейс: Интегрируется с остальными элементами 1С, обеспечивая единообразный пользовательский опыт.
  3. Простота реализации: Относительно простая вставка изображений и управление их расположением через программный интерфейс
    
    Табличного документа
    
    .

Недостатки:

  1. Ограничения форматирования: Возможности по дизайну и интерактивности более ограничены по сравнению с HTML/CSS. Сложные визуальные эффекты могут быть недоступны или требовать значительных усилий.
  2. Ручная компоновка: Требуется более детальная программная настройка размеров ячеек, строк и столбцов для достижения желаемого расположения.

Пример размещения изображений в Табличном документе:

Для начала, у нас на форме должен быть элемент


ПолеТабличногоДокумента
(например, с именем

ТабДокКартинки
), связанный с реквизитом формы типа

ТабличныйДокумент
.


// Реквизит формы: ТабличныйДокументКартинки, Тип: ТабличныйДокумент

&НаСервере
Процедура ВывестиКартинкиВТабДокНаСервере()
    // Создаем новый ТабличныйДокумент
    ТабДок = Новый ТабличныйДокумент;
    ТабДок.ОтображатьСетку = Ложь;
    ТабДок.Защита = Ложь; // Если нужно разрешить взаимодействие
    ТабДок.ТолькоПросмотр = Истина;
    ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Портрет;

    // Оптимальная ширина колонки для миниатюры
    ШиринаКолонки = 25; // В условных единицах
    ВысотаСтроки = 15;  // В условных единицах

    // Задаем ширину колонок (например, три колонки для картинок)
    КоличествоКолонокВРяду = 3; 
    Для Инд = 1 По КоличествоКолонокВРяду Цикл
        ТабДок.Область("1:" + (ТабДок.ВысотаТаблицы > 0 ? ТабДок.ВысотаТаблицы : 1)).Колонки.Добавить();
        ТабДок.Область("1:" + (ТабДок.ВысотаТаблицы > 0 ? ТабДок.ВысотаТаблицы : 1)).Колонки[Инд-1].Ширина = ШиринаКолонки;
    КонецЦикла;

    // Получаем ссылки на прикрепленные файлы
    ВладелецФайла = Объект.Ссылка; // Или любой другой владелец
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    ПрисоединенныеФайлы.Ссылка КАК Ссылка
    |ИЗ
    |    Справочник.ИсследованиеЭндоскопическоеПрисоединенныеФайлы КАК ПрисоединенныеФайлы
    |ГДЕ
    |    ПрисоединенныеФайлы.ВладелецФайла = &ВладелецФайла
    |УПОРЯДОЧИТЬ ПО
    |    ПрисоединенныеФайлы.ДатаСоздания";
    Запрос.УстановитьПараметр("ВладелецФайла", ВладелецФайла);
    РезультатЗапроса = Запрос.Выполнить();
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();

    СтрокаТаблицы = 1;
    КолонкаТаблицы = 1;

    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        СсылкаНаФайл = ВыборкаДетальныеЗаписи.Ссылка;

        // Получаем двоичные данные файла. 
        // В типовых конфигурациях обычно используются регистры сведений типа "ДвоичныеДанныеФайлов".
        КлючЗаписиДвоичныхДанных = РегистрыСведений.ДвоичныеДанныеФайлов.СоздатьКлючЗаписи(Новый Структура("Файл", СсылкаНаФайл));
        ХранилищеДвоичныхДанных = РегистрыСведений.ДвоичныеДанныеФайлов.Получить(КлючЗаписиДвоичныхДанных);
        
        ДвоичныеДанные = Неопределено;
        Если ХранилищеДвоичныхДанных <> Неопределено Тогда
            ДвоичныеДанные = ХранилищеДвоичныхДанных.Хранилище.Получить(); // Получаем двоичные данные из хранилища
        КонецЕсли;

        Если ДвоичныеДанные <> Неопределено И ДвоичныеДанные.Размер() > 0 Тогда
            Поток = Новый ПотокДвоичныхДанных(ДвоичныеДанные);
            Попытка
                КартинкаОбъект = Новый Картинка(Поток);
            Исключение
                КартинкаОбъект = Неопределено; // Не удалось создать Картинку (например, неверный формат)
            КонецПопытки;

            // Если КартинкаОбъект успешно создан, вставляем ее в ТабДок
            Если КартинкаОбъект <> Неопределено Тогда
                ОбластьДляКартинки = ТабДок.Область(СтрокаТаблицы, КолонкаТаблицы);
                ОбластьДляКартинки.Картинка = КартинкаОбъект;
                ОбластьДляКартинки.РазмерКартинки = РазмерКартинки.Пропорционально;
                ОбластьДляКартинки.РасположениеКартинки = РасположениеКартинки.Центр;
                
                // Добавляем текст под картинкой или в ее угол, если нужно
                ОбластьДляКартинки.Текст = СсылкаНаФайл.Наименование; // Пример: выводим имя файла
                ОбластьДляКартинки.РасположениеТекста = РасположениеТекстаТабличногоДокумента.Низ;
                ОбластьДляКартинки.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Центр;

                // Устанавливаем высоту строки, если это начало новой строки
                Если КолонкаТаблицы = 1 Тогда
                    ТабДок.Область(СтрокаТаблицы, 1, СтрокаТаблицы, ТабДок.ШиринаТаблицы).ВысотаСтроки = ВысотаСтроки;
                КонецЕсли;

                КолонкаТаблицы = КолонкаТаблицы + 1;
                Если КолонкаТаблицы > КоличествоКолонокВРяду Тогда
                    КолонкаТаблицы = 1;
                    СтрокаТаблицы = СтрокаТаблицы + 1;
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;

    // Присваиваем сформированный ТабДок реквизиту формы
    ЭтаФорма.ТабличныйДокументКартинки = ТабДок;
КонецПроцедуры

Для обработки нажатий на изображения в


ТабДок
мы можем использовать событие

Выбор
элемента

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

ТабДок
или в параллельной структуре.

Подход 3: Динамическое создание элементов "Поле картинки"

Этот подход предполагает динамическое создание на форме элементов типа


ПолеФормы
с видом

ПолеКартинки
и их размещение внутри группы с возможностью прокрутки. Это позволяет получить нативный интерфейс 1С, сохраняя при этом гибкость в управлении расположением и количеством изображений. В сообщении 6 темы форума был предложен именно такой вариант реализации.

Принцип работы: Мы создаем элементы


ПолеФормы
в коде, привязываем их к динамически созданным реквизитам формы, устанавливаем им вид

ПолеКартинки
и помещаем в предварительно созданную (или также динамически созданную) группу, для которой включена прокрутка.

Преимущества:

  1. Нативный интерфейс: Изображения отображаются как стандартные элементы 1С, что обеспечивает высокую скорость отрисовки и предсказуемое поведение.
  2. Гибкий контроль: Полный программный контроль над каждым элементом изображения, включая его размер, положение, интерактивность (гиперссылка, контекстное меню).
  3. Эффективное использование ресурсов: Каждый элемент
    
    ПолеКартинки
    
    легче, чем целый встроенный браузер, что может привести к лучшей производительности при грамотной реализации.

Недостатки:

  1. Сложность кода: Динамическое создание элементов и реквизитов требует более сложной логики и тщательного управления.
  2. Управление ресурсами: При очень большом количестве элементов (сотни и тысячи) на одной форме может сказаться на производительности и потреблении памяти.

Рассмотрим подробнее пошаговую реализацию на основе примера кода из сообщения 6:

  1. Запрос данных о файлах

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

    
    Процедура ПолучитьФайлы()
        ВладелецФайла = Объект.Ссылка; // Предполагается, что форма имеет реквизит 'Объект' типа Ссылка
    
        Запрос = Новый Запрос;
        Запрос.Текст = 
        "ВЫБРАТЬ
        |    ИсследованиеЭндоскопическоеПрисоединенныеФайлы.Ссылка КАК Ссылка
        |ИЗ
        |    Справочник.ИсследованиеЭндоскопическоеПрисоединенныеФайлы КАК ИсследованиеЭндоскопическоеПрисоединенныеФайлы
        |ГДЕ
        |    ИсследованиеЭндоскопическоеПрисоединенныеФайлы.ВладелецФайла = &ВладелецФайла
        |
        |УПОРЯДОЧИТЬ ПО
        |    ИсследованиеЭндоскопическоеПрисоединенныеФайлы.ДатаСоздания";
    
        Запрос.УстановитьПараметр("ВладелецФайла", ВладелецФайла);
    
        РезультатЗапроса = Запрос.Выполнить();
        ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
    

    Обратите внимание, что название справочника

    
    ИсследованиеЭндоскопическоеПрисоединенныеФайлы
    
    является специфичным для примера и может отличаться в вашей конфигурации. Используйте ваш справочник присоединенных файлов.

  2. Динамическое добавление реквизитов формы

    Каждое динамически создаваемое

    
    ПолеФормы
    
    должно быть привязано к существующему реквизиту формы. Если элементов много и они создаются "на лету", то и реквизиты для них нужно создавать динамически.

    Мы создаем два реквизита для каждого файла:

    • Реквизит с именем
      
      ИдентификаторФайла
      
      типа
      
      Строка
      
      , который будет хранить навигационную ссылку на изображение.
    • Реквизит с именем
      
      СсылкаИдентификаторФайла
      
      типа
      
      СправочникСсылка.ИсследованиеЭндоскопическоеПрисоединенныеФайлы
      
      , который будет хранить ссылку на сам объект файла. Это удобно для дальнейшей работы с файлом (например, открытия).
    
    // Внутри цикла Пока ВыборкаДетальныеЗаписи.Следующий()
    СсылкаНаФайл = ВыборкаДетальныеЗаписи.Ссылка;
    ИдентификаторФайла = "Файл" + СтрЗаменить(СсылкаНаФайл.УникальныйИдентификатор(),"-","");
    
    Если Элементы.Найти(ИдентификаторФайла) = Неопределено Тогда // Проверяем, не создан ли уже такой элемент
        МассивДобавляемыхРеквизитов = Новый Массив;
        МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы(ИдентификаторФайла, Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(0)), , "Файл", Ложь));
        МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы("Ссылка" + ИдентификаторФайла, Новый ОписаниеТипов("СправочникСсылка.ИсследованиеЭндоскопическоеПрисоединенныеФайлы", ,), , "Файл", Ложь));
    
        ЭтаФорма.ИзменитьРеквизиты(МассивДобавляемыхРеквизитов);
    
        // Сохраняем ссылку на файл в динамический реквизит
        ЭтаФорма["Ссылка" + ИдентификаторФайла] = ВыборкаДетальныеЗаписи.Ссылка;
        // ... (дальнейший код)
    КонецЕсли;
    
  3. Организация групп для размещения элементов

    Чтобы получить прокрутку, все

    
    Поля картинки
    
    должны быть размещены в элементе
    
    ГруппаФормы
    
    , который имеет соответствующий вид. В данном случае, автор использует группу
    
    ГруппаФайлы
    
    на форме и динамически добавляет в нее подгруппы, каждая из которых содержит до 4 картинок. Такая структура позволит создать сетку из изображений и получить прокрутку для основной группы.

    Важно: Для того чтобы прокрутка появилась, родительская группа (например,

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

    
    // Внутри цикла Пока ВыборкаДетальныеЗаписи.Следующий()
    // ... (код выше)
    
    Если Элементы.Найти(ИдентификаторФайла) = Неопределено Тогда
        СвободнаяГруппа = Неопределено;
    
        // Ищем свободную группу для размещения картинок (до 4 картинок в ряд)
        Для Каждого ГруппаФайловИзПодчиненных Из Элементы.ГруппаФайлы.ПодчиненныеЭлементы Цикл
            Если ТипЗнч(ГруппаФайловИзПодчиненных) <> Тип("ГруппаФормы") Тогда
                Продолжить;    
            КонецЕсли;
    
            Если ГруппаФайловИзПодчиненных.ПодчиненныеЭлементы.Количество() < 4 Тогда
                СвободнаяГруппа = ГруппаФайловИзПодчиненных;
                Прервать;
            КонецЕсли;
        КонецЦикла;
    
        // Если свободной группы нет, создаем новую
        Если СвободнаяГруппа = Неопределено Тогда
            СвободнаяГруппа = Элементы.Добавить("Группа" + ИдентификаторФайла, Тип("ГруппаФормы"), Элементы.ГруппаФайлы);
            СвободнаяГруппа.Вид = ВидГруппыФормы.ОбычнаяГруппа;
            СвободнаяГруппа.Группировка = ГруппировкаЭлементовФормы.Горизонтальная; // Размещаем картинки в ряд
            СвободнаяГруппа.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет; // Без заголовка группы
        КонецЕсли;
    
        // ... (дальнейший код для добавления поля картинки)
    КонецЕсли;
    
  4. Динамическое создание элементов "ПолеФормы" (Поле картинки)

    После создания реквизитов и определения группы для размещения, мы можем создать сам элемент

    
    ПолеФормы
    
    и настроить его свойства для отображения картинки.

    
    // Внутри цикла Пока ВыборкаДетальныеЗаписи.Следующий()
    // ... (код выше)
    
    Если Элементы.Найти(ИдентификаторФайла) = Неопределено Тогда
        // ... (код по поиску/созданию группы)
    
        Элемент = Элементы.Добавить(ИдентификаторФайла, Тип("ПолеФормы"), СвободнаяГруппа);
        Элемент.ПутьКДанным = ИдентификаторФайла; // Привязка к динамическому реквизиту
                
        Элемент.Вид = ВидПоляФормы.ПолеКартинки;
                
        // Настройка размеров и отображения
        Элемент.Ширина = 17;
        Элемент.Высота = 6;
                
        Элемент.РастягиватьПоВертикали = Ложь;
        Элемент.РастягиватьПоГоризонтали = Ложь;
                
        Элемент.РазмерКартинки = РазмерКартинки.Пропорционально; // Сохраняем пропорции
                
        Элемент.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет; // Без заголовка
                
        // ... (дальнейший код для интерактивности)
    КонецЕсли;
    
  5. Отображение картинки

    Для того чтобы картинка отобразилась в созданном

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

    В данном случае, в исходном коде используется функция

    
    ПолучитьНавигационнуюСсылкуКартинки
    
    , которая, вероятно, является собственной разработкой автора. Мы рассмотрим стандартный способ получения навигационной ссылки на двоичные данные присоединенного файла, хранящегося в регистре сведений
    
    ДвоичныеДанныеФайлов
    
    , как это было показано в закомментированном примере из того же сообщения:

    
    // Внутри цикла Пока ВыборкаДетальныеЗаписи.Следующий()
    // ... (код выше)
    
    // Присваиваем навигационную ссылку реквизиту, к которому привязано ПолеКартинки
    // Предполагается, что СсылкаНаФайл содержит ссылку на объект справочника присоединенных файлов
    // А в конфигурации используется стандартный регистр ДвоичныеДанныеФайлов для хранения содержимого.
    
    КлючЗаписиДвоичныхДанных = РегистрыСведений.ДвоичныеДанныеФайлов.СоздатьКлючЗаписи(Новый Структура("Файл", СсылкаНаФайла));
    ЭтаФорма[ИдентификаторФайла] = ПолучитьНавигационнуюСсылку(КлючЗаписиДвоичныхДанных, "ДвоичныеДанныеФайла");
    

    Если в вашей конфигурации используются другие механизмы хранения или нужно отобразить изображение из временного файла, можно использовать путь к временному файлу:

    
    // Пример сохранения двоичных данных во временный файл и получение пути
    // Получение двоичных данных аналогично примеру с Табличным документом
    ДвоичныеДанныеФайла = Неопределено; // Здесь получаем ДвоичныеДанные, например, из регистра
    
    Если ДвоичныеДанныеФайла <> Неопределено Тогда
        ИмяВременногоФайла = ПолучитьИмяВременногоФайла("jpg"); // Или другого расширения, соответствующего файлу
        ДвоичныеДанныеФайла.Записать(ИмяВременногоФайла);
        ЭтаФорма[ИдентификаторФайла] = ИмяВременногоФайла;
    КонецЕсли;
    

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

  6. Добавление интерактивности

    Для обеспечения взаимодействия с изображениями (например, открытие полноразмерного просмотра при клике) мы можем установить обработчики событий для элементов

    
    ПолеКартинки
    
    и добавить контекстное меню.

    
            // Внутри цикла Пока ВыборкаДетальныеЗаписи.Следующий()
            // ... (код выше)
    
            Элемент.Гиперссылка = Истина; // Делаем элемент интерактивным
            Элемент.УстановитьДействие("Нажатие", "ФайлНажатие"); // Обработчик нажатия на картинку
    
            // Добавляем команды в контекстное меню
            ЭлементКомандаОткрыть = Элементы.Добавить("ОткрытьФайл" + ИдентификаторФайла, Тип("КнопкаФормы"), Элемент.КонтекстноеМеню);
            ЭлементКомандаОткрыть.ИмяКоманды = "ОткрытьИзображение"; // Имя команды для дальнейшей обработки
            ЭлементКомандаОткрыть.Заголовок = "Открыть";
    
            ЭлементКомандаРедактировать = Элементы.Добавить("РедактироватьФайл" + ИдентификаторФайла, Тип("КнопкаФормы"), Элемент.КонтекстноеМеню);
            ЭлементКомандаРедактировать.ИмяКоманды = "РедактироватьИзображение"; // Имя команды для дальнейшей обработки
            ЭлементКомандаРедактировать.Заголовок = "Редактировать";
            КонецЕсли; // Закрытие Если Элементы.Найти(ИдентификаторФайла) = Неопределено
            КонецЦикла; // Закрытие Пока ВыборкаДетальныеЗаписи.Следующий()
    КонецПроцедуры
    

    На стороне формы необходимо реализовать процедуры

    
    ФайлНажатие
    
    ,
    
    ОткрытьИзображение
    
    и
    
    РедактироватьИзображение
    
    , которые будут выполнять необходимые действия, используя ссылку на файл, хранящуюся в динамическом реквизите
    
    СсылкаИдентификаторФайла
    
    . Например, для
    
    ФайлНажатие
    
    можно получить имя элемента и, зная его, обратиться к соответствующему реквизиту:

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

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

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

  1. Генерация миниатюр (превью)

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

    
    ДвоичныеДанныеФайлов
    
    с отдельным ресурсом для миниатюры или в отдельном справочнике/регистре).

    
    // Пример получения миниатюры, если она хранится (для справочника с полем Миниатюра)
    Если СсылкаНаФайл.Миниатюра <> Неопределено Тогда
        // Используем двоичные данные миниатюры
        ДвоичныеДанныеМиниатюры = СсылкаНаФайл.Миниатюра; 
        // ... и далее создаем Картинку или навигационную ссылку для миниатюры
    Иначе
        // Генерируем миниатюру из полного изображения, если ее нет, и сохраняем
        ДвоичныеДанныеПолногоИзображения = ПолучитьДвоичныеДанныеФайла(СсылкаНаФайл); // Ваша функция
        Если ДвоичныеДанныеПолногоИзображения <> Неопределено Тогда
            ПолнаяКартинка = Новый Картинка(Новый ПотокДвоичныхДанных(ДвоичныеДанныеПолногоИзображения));
            // Получаем миниатюру размером 150x150
            МиниатюраОбъект = ПолнаяКартинка.ПолучитьКартинкуДляОтображения(150, 150, РежимПропорциональности.МасштабироватьССохранениемПропорций);
            // Если МиниатюраОбъект получен, ее двоичные данные можно получить и сохранить
            ДвоичныеДанныеМиниатюры = МиниатюраОбъект.ПолучитьДвоичныеДанные();
            // Сохраните ДвоичныеДанныеМиниатюры в базе
        КонецЕсли;
        // Используем ДвоичныеДанныеМиниатюры для отображения
    КонецЕсли;
    
  2. Отложенная загрузка (Lazy Loading)

    Реализуйте механизм отложенной загрузки изображений. Это означает, что изображения загружаются и отображаются только тогда, когда они становятся видимыми в области прокрутки формы. Это особенно полезно, когда изображений очень много, и не все из них помещаются на экране одновременно. Для этого можно использовать обработчик события прокрутки родительской группы или контейнера, чтобы динамически загружать данные для тех

    
    Полей картинки
    
    , которые попадают в видимую область. Это снижает нагрузку на сеть и память при первоначальной загрузке.

  3. Кэширование изображений

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

  4. Асинхронная загрузка

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

    
    Картинку
    
    объект.

Заключение:

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


Поле HTML документа
предлагает максимальную гибкость дизайна,

Табличный документ
– хорошую производительность для структурированного вывода, а динамическое создание элементов

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

← На главную