При разработке отчетов в 1С программисты часто сталкиваются с ситуацией, когда при повторном нажатии на кнопку «Сформировать» табличный документ начинает заполняться с ошибками: ячейки смещаются вниз или вправо, а новые данные выводятся не с первой строки, даже если предварительно вызывается метод Очистить().
Разберем подробнее причинно-следственную связь этой проблемы, изучим механики платформы 1С при работе с табличными документами и рассмотрим верные варианты алгоритма вывода данных.
Проанализируем ситуацию, с которой сталкивается разработчик. В исходном коде вывода областей логика была построена следующим образом:
Если Счетчик < 5 Тогда
ЭлементыФормы.Результат.Присоединить(ОбластьТорговыйОбъект);
Счетчик = Счетчик + 1;
Иначе
ЭлементыФормы.Результат.Вывести(ОбластьТорговыйОбъект);
Счетчик = 1;
КонецЕсли;
Главная ошибка здесь заключается в попытке вызвать метод Присоединить() на еще чистом (или только что очищенном) табличном документе до первого вызова метода Вывести().
Рассмотрим, как платформа 1С обрабатывает эти методы:
Вывести() создает новую строку в табличном документе снизу и фиксирует текущий контекст строки (координату Y).Присоединить() добавляет область по горизонтали в ту же строку, где находится текущий контекст вывода.Если вызвать Присоединить() на пустом табличном документе, платформа не имеет зафиксированной строки-ориентира. В результате возникает сбой позиционирования: первое же добавление элемента «съезжает» вниз или формирует некорректные координаты для всех последующих выведенных строк.
Чтобы исключить смещение табличного документа, необходимо соблюдать правило: первый элемент в каждой новой строке всегда выводится через метод Вывести(), и только последующие колонки этой же строки — через Присоединить().
Перепишем условие так, чтобы первая колонка создавала новую строку:
Если Счетчик = 1 Тогда
ЭлементыФормы.Результат.Вывести(ОбластьТорговыйОбъект);
Счетчик = Счетчик + 1;
ИначеЕсли Счетчик = 5 Тогда
ЭлементыФормы.Результат.Присоединить(ОбластьТорговыйОбъект);
Счетчик = 1;
Иначе
ЭлементыФормы.Результат.Присоединить(ОбластьТорговыйОбъект);
Счетчик = Счетчик + 1;
КонецЕсли;
Разберем более красивый и лаконичный вариант написания этого же условия. Вместо громоздких конструкций Если...ИначеЕсли удобнее использовать математический оператор получения остатка от деления %:
Если Счетчик % 5 = 1 Тогда
ЭлементыФормы.Результат.Вывести(ОбластьТорговыйОбъект);
Иначе
ЭлементыФормы.Результат.Присоединить(ОбластьТорговыйОбъект);
КонецЕсли;
Счетчик = Счетчик + 1;
В этом случае при Счетчик = 1 выражение 1 % 5 дает 1, поэтому вызывается Вывести(). Для значений 2, 3, 4 и 5 вызывается Присоединить(). На 6-й итерации 6 % 5 снова дает 1, и начинает формироваться следующая строка.
При работе с табличными документами в 1С рекомендуется придерживаться нескольких правил, которые предотвращают ошибки интерфейса и ускоряют работу программы:
ЭлементыФормы.Результат внутри цикла. Каждая операция Вывести() или Присоединить() на форме вызывает перерисовку интерфейса. Правильнее сначала сформировать документ в локальной переменной типа ТабличныйДокумент, а затем вывести результат целиком.
СоздатьФорматСтрок() у выводимой области, чтобы ширины колонок новых строк не искажали уже выведенную часть таблицы.
Посмотрим на итоговый пример кода с учетом всех лучших практик:
// Создаем табличный документ в памяти
ТабДок = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("Макет");
ОбластьТорговыйОбъект = Макет.ПолучитьОбласть("Шапка|ТорговыйОбъект");
ТО = Справочники.ТорговыеОбъекты.Выбрать();
Счетчик = 1;
Пока ТО.Следующий() Цикл
// Заполнение параметров макета
ОбластьТорговыйОбъект.Параметры.НаСкладеПО = ТаблицаБаланса.Строки[0]["ДатаПО" + ТО.Код];
ОбластьТорговыйОбъект.Параметры.НаСкладеС = ТаблицаБаланса.Строки[0]["ДатаС" + ТО.Код];
ОбластьТорговыйОбъект.Параметры.НаСкладеРАЗ = ТаблицаБаланса.Строки[0]["ДатаРАЗ" + ТО.Код];
// Вывод областей
Если Счетчик % 5 = 1 Тогда
ТабДок.Вывести(ОбластьТорговыйОбъект);
Иначе
ТабДок.Присоединить(ОбластьТорговыйОбъект);
КонецЕсли;
Счетчик = Счетчик + 1;
КонецЦикла;
// Выводим готовый результат на форму за одну операцию
ЭлементыФормы.Результат.Очистить();
ЭлементыФормы.Результат.Вывести(ТабДок);
Использование этого подхода гарантирует, что табличный документ сформируется корректно, без сдвигов и с высокой скоростью выполнения.