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