Как реализовать добавление нескольких фотографий к элементу справочника в 1С?

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

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

Анализ исходной проблемы и поиск ошибок в коде

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


// ОШИБОЧНЫЙ ВАРИАНТ
Если СписокФото.Количество > 0 Тогда;
    НоваяСтрока = ТекущийОбъект.Фотографии.Добавить(); // Строка добавляется ОДИН раз вне цикла
    Для Элемент = 0 по СписокФото.Количество - 1 Цикл
        НоваяСтрока.ДвоичныеДанныеФото = ПолучитьИзВременногоХранилища(СписокФото[Элемент]); // Каждая итерация затирает предыдущее значение
    КонецЦикла;
КонецЕсли;

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

Исправление кода для записи нескольких изображений

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


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    // Проверяем, есть ли новые фото во временном хранилище (СписокФото)
    Если СписокФото.Количество() > 0 Тогда
        
        // Если нужно заменить старые фото новыми, очищаем табличную часть
        ТекущийОбъект.Фотографии.Очистить();
        
        Для Каждого ЭлементСписка Из СписокФото Цикл
            // Создаем НОВУЮ строку для каждого файла
            НоваяСтрока = ТекущийОбъект.Фотографии.Добавить();
            
            // Помещаем двоичные данные из временного хранилища в ХранилищеЗначения
            НоваяСтрока.ДвоичныеДанныеФото = Новый ХранилищеЗначения(ПолучитьИзВременногоХранилища(ЭлементСписка.Значение));
        КонецЦикла;
        
        // Очищаем список на форме, чтобы избежать дублирования при повторной записи
        СписокФото.Очистить();
        
    КонецЕсли;
    
КонецПроцедуры

Обратите внимание на использование объекта Новый ХранилищеЗначения. В реквизиты табличной части с типом ХранилищеЗначения данные должны попадать именно в упакованном виде, а не как «сырые» двоичные данные.

Отображение фотографий из табличной части на управляемой форме

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

Стандартный синтаксис функции ПолучитьНавигационнуюСсылку для табличной части выглядит так: ПолучитьНавигационнуюСсылку(ОбъектСсылка, "ИмяТабличнойЧасти.ИмяРеквизита", ИндексСтроки).

Однако, использование индекса строки (0, 1, 2...) — не самый надежный метод, так как при сортировке или удалении строк индексы меняются. Рассмотрим более универсальный способ: вывод списка фотографий через таблицу на форме.

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

&НаКлиенте
Процедура ФотографииПриАктивизацииСтроки(Элемент)
    ТекущиеДанные = Элементы.Фотографии.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        // Формируем ссылку на конкретную строку по уникальному идентификатору (ID) строки
        Фото = ПолучитьНавигационнуюСсылку(Объект.Ссылка, "Фотографии.ДвоичныеДанныеФото", ТекущиеДанные.НомерСтроки - 1);
    КонецЕсли;
КонецПроцедуры

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

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

  1. Раздувание объема объекта: В 1С при обращении к справочнику (например, через ПолучитьОбъект()) система считывает из БД все данные, включая табличные части. Если у вас в ТЧ лежит 10 фотографий по 5 Мб каждая, то простое переименование элемента справочника в коде заставит сервер «прокачать» через память 50 Мб лишних данных.
  2. Замедление списков: Динамические списки будут работать значительно медленнее, если им придется обрабатывать тяжелые объекты.
  3. Ограничения базы данных: База данных SQL будет расти очень быстро, что усложнит создание бэкапов.

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

Реализация галереи через подчиненный справочник

Если вы не используете БСП, можно реализовать упрощенный аналог. Создадим подчиненный справочник ФайлыОбъектов с владельцем — вашим основным справочником. В нем создадим реквизит ФайлХранилище (тип ХранилищеЗначения).

Теперь, чтобы отобразить галерею, мы разместим на форме основного объекта Динамический список, указывающий на справочник ФайлыОбъектов с отбором по владельцу. Это позволит:

  1. Мгновенно открывать карточку основного объекта (фотографии не грузятся заранее).
  2. Загружать фото только тогда, когда пользователь нажал на конкретную строку в списке.
  3. Легко добавлять неограниченное количество изображений без риска замедлить работу системы.

Оптимизация: Работа с превью (миниатюрами)

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

Алгоритм оптимизации:

  1. При загрузке фото на сервер программно создавайте две копии: оригинал и уменьшенную копию (например, 100x100 пикселей).
  2. Обе копии сохраняйте в базу (или в тома).
  3. В списке на форме отображайте только миниатюры.
  4. Полноразмерное фото открывайте в отдельном окне только при нажатии на миниатюру.

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

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

← На главную