Как правильно загрузить картинки из Excel в 1С: обходим ограничения ОформленияСтрок

Программист 1С v8.3 (Обычные формы) Торговля и дистрибуция
← На главную

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

Анализируем проблему: почему события оформления строк не подходят для загрузки

Рассмотрим ситуацию: разработчик читает файл Excel в ТабличныйДокумент, выводит его в табличное поле на форме и пытается в процедуре ПриВыводеСтроки создать элементы справочника Номенклатура и привязать к ним картинки. Основные проблемы этого метода:

  1. Многократные вызовы: Событие ПриВыводеСтроки срабатывает каждый раз, когда строка отрисовывается на экране. Прокрутка списка, изменение размера окна или даже наведение курсора могут вызвать это событие повторно. Это приводит к попыткам создания дублей данных и бесконечным циклам обновления.
  2. Хаотичный порядок: Система отрисовывает только те строки, которые видит пользователь. Это значит, что загрузка будет идти не по порядку (от 1 до N), а в зависимости от того, как пользователь листает экран.
  3. Производительность: Внутри события интерфейса выполняются методы Прочитать() для файла и Записать() для справочника. Это вызывает катастрофические задержки в работе интерфейса.

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

Решение №1: Программный перебор табличного документа

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

  1. Прочитать файл Excel в объект ТабличныйДокумент.
  2. Определить количество строк и колонок.
  3. Запустить цикл по строкам документа.
  4. Внутри каждой строки искать текст и соответствующие рисунки.

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


// Создаем объект и читаем файл
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ПутьКФайлу);

// Запускаем основной цикл по строкам (со 2-й строки, если первая - шапка)
Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл
    
    // Получаем текстовые данные
    Артикул = СокрЛП(ТабДок.Область(НомерСтроки, КолонкаАртикула).Текст);
    Наименование = СокрЛП(ТабДок.Область(НомерСтроки, КолонкаНаименования).Текст);
    
    // Поиск картинки для текущей строки
    КартинкаОбъект = Неопределено;
    Для Каждого ТекущийРисунок Из ТабДок.Рисунки Цикл
        // Проверяем, находится ли рисунок в текущей строке
        Если ТипЗнч(ТекущийРисунок.Объект) = Тип("Картинка") И ТекущийРисунок.ВерхняяЯчейка.НомерСтроки = НомерСтроки Тогда
            КартинкаОбъект = ТекущийРисунок.Картинка;
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    // Обрабатываем полученные данные
    Если ЗначениеЗаполнено(Наименование) Тогда
        ЗагрузитьНоменклатуруСКартинкой(Артикул, Наименование, КартинкаОбъект);
    КонецЕсли;
    
КонецЦикла;

Важный нюанс: Картинка в Excel не всегда идеально "лежит" внутри одной ячейки. Она может занимать несколько ячеек или слегка выходить за границы. В коде выше мы используем свойство ВерхняяЯчейка, которое определяет, к какой строке "примагничено" начало изображения.

Работа с картинками и их хранение в базе

После того как мы получили объект Картинка из табличного документа, его необходимо правильно сохранить. Обычно в типовых конфигурациях (например, УТ 10.3) изображения хранятся в справочнике ХранилищеДополнительнойИнформации. Разберем по шагам процесс сохранения:

  1. Создаем или находим элемент справочника Номенклатура.
  2. Создаем новый элемент в справочнике ХранилищеДополнительнойИнформации.
  3. Помещаем картинку в ХранилищеЗначения с использованием сжатия.
  4. Устанавливаем владельца (ссылку на номенклатуру) и вид данных (Изображение).

Рассмотрим пример функции для сохранения:


Процедура ЗагрузитьНоменклатуруСКартинкой(Артикул, Наименование, КартинкаОбъект)
    
    // 1. Поиск номенклатуры
    СсылкаНоменклатура = Справочники.Номенклатура.НайтиПоАртикулу(Артикул);
    Если СсылкаНоменклатура.Пустая() Тогда
        НовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();
        НовыйЭлемент.Артикул = Артикул;
        НовыйЭлемент.Наименование = Наименование;
        НовыйЭлемент.Записать();
        СсылкаНоменклатура = НовыйЭлемент.Ссылка;
    КонецЕсли;
    
    // 2. Если есть картинка - сохраняем ее
    Если КартинкаОбъект <> Неопределено Тогда
        НовоеХранилище = Справочники.ХранилищеДополнительнойИнформации.СоздатьЭлемент();
        НовоеХранилище.Объект = СсылкаНоменклатура;
        НовоеХранилище.ВидДанных = Перечисления.ВидыДополнительнойИнформацииОбъектов.Изображение;
        НовоеХранилище.Наименование = "Основное изображение";
        
        // Помещаем картинку в хранилище значений
        НовоеХранилище.Хранилище = Новый ХранилищеЗначения(КартинкаОбъект, Новый СжатиеДанных(9));
        НовоеХранилище.Записать();
        
        // Устанавливаем основное изображение в номенклатуре (если есть такой реквизит)
        ОбъектНоменклатура = СсылкаНоменклатура.ПолучитьОбъект();
        ОбъектНоменклатура.ОсновноеИзображение = НовоеХранилище.Ссылка;
        ОбъектНоменклатура.Записать();
    КонецЕсли;
    
КонецПроцедуры

Оптимизация и обработка типичных ошибок

Проанализируем ситуацию, когда файлов много или они содержат тысячи строк. В этом случае прямой перебор коллекции Рисунки внутри цикла по строкам может замедлить работу (сложность алгоритма составит O(N*M), где N — строки, M — рисунки).

Рассмотрим способ оптимизации через индексацию:

Перед началом основного цикла загрузки создадим Соответствие, где ключом будет номер строки, а значением — объект картинки. Пройдем по коллекции Рисунки один раз, заполним соответствие, а затем в основном цикле будем получать картинку мгновенно по номеру строки.


// Индексация рисунков
КартинкиПоСтрокам = Новый Соответствие;
Для Каждого Рисунок Из ТабДок.Рисунки Цикл
    Если Рисунок.ТипРисунка = ТипРисункаТабличногоДокумента.Картинка Тогда
        НомерСтр = Рисунок.ВерхняяЯчейка.НомерСтроки;
        КартинкиПоСтрокам.Вставить(НомерСтр, Рисунок.Картинка);
    КонецЕсли;
КонецЦикла;

// Теперь в основном цикле
Для НомерСтроки = 1 По Высота Цикл
    ТекущаяКартинка = КартинкиПоСтрокам.Получить(НомерСтроки);
    // ... дальнейшая логика
КонецЦикла;

Также стоит помнить о следующих моментах:

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

← На главную