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