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