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