Почему при формировании отчета съезжает табличный документ в 1С и как это исправить?

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

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

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

Причина некорректного поведения: механика Вывести() и Присоединить()

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


Если Счетчик < 5 Тогда
    ЭлементыФормы.Результат.Присоединить(ОбластьТорговыйОбъект);
    Счетчик = Счетчик + 1;
Иначе
    ЭлементыФормы.Результат.Вывести(ОбластьТорговыйОбъект);
    Счетчик = 1;
КонецЕсли;

Главная ошибка здесь заключается в попытке вызвать метод Присоединить() на еще чистом (или только что очищенном) табличном документе до первого вызова метода Вывести().

Рассмотрим, как платформа 1С обрабатывает эти методы:

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

Если вызвать Присоединить() на пустом табличном документе, платформа не имеет зафиксированной строки-ориентира. В результате возникает сбой позиционирования: первое же добавление элемента «съезжает» вниз или формирует некорректные координаты для всех последующих выведенных строк.

Способ 1. Исправление порядка вызова методов

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

Перепишем условие так, чтобы первая колонка создавала новую строку:


Если Счетчик = 1 Тогда 
    ЭлементыФормы.Результат.Вывести(ОбластьТорговыйОбъект);
    Счетчик = Счетчик + 1;
ИначеЕсли Счетчик = 5 Тогда            
    ЭлементыФормы.Результат.Присоединить(ОбластьТорговыйОбъект);
    Счетчик = 1;
Иначе            
    ЭлементыФормы.Результат.Присоединить(ОбластьТорговыйОбъект);
    Счетчик = Счетчик + 1;
КонецЕсли;

Способ 2. Оптимизация алгоритма через остаток от деления

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


Если Счетчик % 5 = 1 Тогда
    ЭлементыФормы.Результат.Вывести(ОбластьТорговыйОбъект);
Иначе
    ЭлементыФормы.Результат.Присоединить(ОбластьТорговыйОбъект);
КонецЕсли;

Счетчик = Счетчик + 1;

В этом случае при Счетчик = 1 выражение 1 % 5 дает 1, поэтому вызывается Вывести(). Для значений 2, 3, 4 и 5 вызывается Присоединить(). На 6-й итерации 6 % 5 снова дает 1, и начинает формироваться следующая строка.

Рекомендации по повышению производительности (Best Practices)

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

  1. Формирование документа в памяти: Не следует выводить данные напрямую в элемент формы ЭлементыФормы.Результат внутри цикла. Каждая операция Вывести() или Присоединить() на форме вызывает перерисовку интерфейса. Правильнее сначала сформировать документ в локальной переменной типа ТабличныйДокумент, а затем вывести результат целиком.
  2. Сохранение форматирования колонок: Если вы выводите блоки разной ширины, используйте метод СоздатьФорматСтрок() у выводимой области, чтобы ширины колонок новых строк не искажали уже выведенную часть таблицы.

Посмотрим на итоговый пример кода с учетом всех лучших практик:


// Создаем табличный документ в памяти
ТабДок = Новый ТабличныйДокумент;

Макет = ПолучитьМакет("Макет");
ОбластьТорговыйОбъект = Макет.ПолучитьОбласть("Шапка|ТорговыйОбъект");

ТО = Справочники.ТорговыеОбъекты.Выбрать();
Счетчик = 1;

Пока ТО.Следующий() Цикл
    
    // Заполнение параметров макета
    ОбластьТорговыйОбъект.Параметры.НаСкладеПО = ТаблицаБаланса.Строки[0]["ДатаПО" + ТО.Код];
    ОбластьТорговыйОбъект.Параметры.НаСкладеС = ТаблицаБаланса.Строки[0]["ДатаС" + ТО.Код];
    ОбластьТорговыйОбъект.Параметры.НаСкладеРАЗ = ТаблицаБаланса.Строки[0]["ДатаРАЗ" + ТО.Код];

    // Вывод областей
    Если Счетчик % 5 = 1 Тогда
        ТабДок.Вывести(ОбластьТорговыйОбъект);
    Иначе
        ТабДок.Присоединить(ОбластьТорговыйОбъект);
    КонецЕсли;

    Счетчик = Счетчик + 1;
    
КонецЦикла;

// Выводим готовый результат на форму за одну операцию
ЭлементыФормы.Результат.Очистить();
ЭлементыФормы.Результат.Вывести(ТабДок);

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

← На главную