При формировании печатных форм и отчетов в среде 1С разработчики часто сталкиваются с ограничениями стандартного линейного вывода ячеек. Традиционные методы Вывести() и Присоединить() работают по строгой последовательной логике: «сверху вниз» и «слева направо». Но что делать, если вам необходимо сформировать сложную структуру, где области должны располагаться асимметрично, перекрывать друг друга или выстраиваться в виде сложной мозаики без жесткой привязки к последовательному выводу?
В этой статье мы подробно разберем, как решить проблему позиционирования областей. Мы проанализируем стандартное поведение платформы, разберем ошибки начинающих разработчиков, рассмотрим изящную критику идеи парсинга строк и изучим четыре профессиональных способа решения этой задачи.
Рассмотрим классическую ситуацию, с которой столкнулся автор темы. Нам нужно вывести три области в табличный документ:
Если мы применим «тупой» последовательный вывод:
ТабДок.Вывести(Область1);
ТабДок.Вывести(Область2);
ТабДок.Присоединить(Область3);
Результат нас разочарует. Платформа 1С выведет Область 1, затем под ней выведет Область 2. Поскольку Область 2 состоит из нескольких строк, внутренний курсор табличного документа сместится к нижней границе Области 2. Метод Присоединить() пристыкует Область 3 к крайней правой нижней точке последней выведенной строки. В итоге Область 3 уедет вниз, образовав некрасивую «ступеньку» и разорвав визуальную целостность таблицы.
Выясним причину такого поведения. Метод Присоединить() всегда начинает вывод с первой свободной колонки последней выведенной строки. Он не умеет автоматически возвращаться «назад во времени» к началу строки, если область-источник занимает по вертикали больше одной ячейки. Нам нужен инструмент для точечного позиционирования. Разберем, как его реализовать.
В ходе обсуждения автор темы пришел к идее получать адрес выведенной области в виде строки формата "R24C1:R26C5" через свойство Имя результирующей области и парсить эту строку регулярными выражениями или функциями работы со строками, чтобы вычислить координаты для следующего вывода:
ТочкаВыводаОбласти2 = ДокументРезультат.Вывести(Область2);
ТочкаВыводаОбласти2Строка = ТочкаВыводаОбласти2.Имя; // Возвращает "R24C1:R26C5"
// Далее предполагается сложный разбор строки для поиска номеров строк и колонок...
Внимание: это плохая практика! Парсинг строки адреса — избыточный, медленный и потенциально опасный путь. Координатная сетка может измениться, формат локализации строки адреса в разных версиях платформы или региональных настройках системы также может отличаться (например, использование латинских букв R и C вместо русских Ш и К).
Платформа 1С предоставляет встроенные числовые свойства для любого объекта типа ОбластьЯчеекТабличногоДокумента, которые работают мгновенно и надежно:
Верх — числовой индекс первой (верхней) строки области.Лево — числовой индекс первой (левой) колонки области.Низ — числовой индекс последней (нижней) строки области.Право — числовой индекс последней (правой) колонки области.Используя эти числовые свойства, мы можем легко и безопасно вычислить координаты любой смежной области без разбора текстовых строк.
Если вам необходимо вывести область макета в строго определенные координаты, минуя стандартную последовательную адресацию, лучшим решением будет использование метода ВставитьОбласть() табличного документа.
Этот метод позволяет скопировать фрагмент ячеек из макета и «наложить» его на произвольный диапазон ячеек результирующего документа. Давайте разберем этот процесс по шагам на практическом примере:
// 1. Выводим левую Область 2 стандартным методом и получаем объект выведенных ячеек
РезультирующаяОбласть2 = ТабДок.Вывести(Область2);
// 2. Рассчитываем координаты для правой Области 4 на основе координат выведенной Области 2
// Нам нужно, чтобы Область 4 начиналась на той же строке, где начинается Область 2
СтрокаНачала = РезультирующаяОбласть2.Верх;
// Область 4 должна располагаться сразу справа от Области 2
КолонкаНачала = РезультирующаяОбласть2.Право + 1;
// Определяем высоту и ширину Области 4, обратившись к исходному макету
ВысотаОбласти4 = Область4.ВысотаТаблицы;
ШиринаОбласти4 = Область4.ШиринаТаблицы;
// Вычисляем конечные координаты для области-приемника
СтрокаКонца = СтрокаНачала + ВысотаОбласти4 - 1;
КолонкаКонца = КолонкаНачала + ШиринаОбласти4 - 1;
// 3. Создаем область-приемник в результирующем документе по вычисленным числовым координатам
ОбластьПриемник = ТабДок.Область(СтрокаНачала, КолонкаНачала, СтрокаКонца, КолонкаКонца);
// 4. Переносим данные из макета в результирующий документ без смещения остальных ячеек
ТабДок.ВставитьОбласть(Область4, ОбластьПриемник, ТипСмещенияТабличногоДокумента.БезСмещения);
Важная деталь: Использование параметра ТипСмещенияТабличногоДокумента.БезСмещения критически важно. В этом режиме ячейки макета просто копируются поверх сетки табличного документа. Если выбрать смещение по горизонтали или вертикали, платформа сдвинет уже существующие строки и колонки, что приведет к непредсказуемому искажению внешнего вида отчета.
Программирование точных числовых координат в коде — рабочий метод, но он делает программный код жестко зависимым от структуры макета. Если в будущем вам потребуется добавить одну колонку в Область 2, программные расчеты в коде придется переписывать.
Чтобы избежать этого, в методологии 1С применяется стандартный подход — разделение макета на **именованные горизонтальные и вертикальные области** и последующий вывод их пересечений. Давайте разберем этот архитектурный прием.
В макете создаются горизонтальные именованные строки (например, СтрокаШапки, СтрокаДанных1, СтрокаДанных2) и вертикальные колонки (например, КолонкаЛевая, КолонкаПравая). При выводе мы обращаемся к пересечению этих областей с помощью оператора вертикальной черты |:
// Выводим первую строку (Шапка) на всю ширину
ТабДок.Вывести(Макет.ПолучитьОбласть("СтрокаШапки|КолонкаЛевая"));
ТабДок.Присоединить(Макет.ПолучитьОбласть("СтрокаШапки|КолонкаПравая"));
// Выводим левую часть второй строки (Область 2)
ТабДок.Вывести(Макет.ПолучитьОбласть("СтрокаДанных1|КолонкаЛевая"));
// Справа от нее мы ничего не присоединяем — там остается чистое незаполненное пространство
// Выводим третью строку (Область 3 слева и Область 4 справа)
ТабДок.Вывести(Макет.ПолучитьОбласть("СтрокаДанных2|КолонкаЛевая"));
ТабДок.Присоединить(Макет.ПолучитьОбласть("СтрокаДанных2|КолонкаПравая"));
Использование этого метода полностью избавляет разработчика от необходимости рассчитывать индексы строк и колонок в программном коде. Вся логика размещения элементов управляется интерактивно в самом макете, что значительно упрощает дальнейшую поддержку и модификацию печатной формы. Для доработки уже сформированных документов можно использовать подход к изменению печатных форм через постобработку табличного документа.
Бывают сценарии, когда левая и правая части таблицы генерируются динамически на основе разных источников данных с неизвестным заранее количеством строк. Например, слева у нас выводится список сотрудников отдела (может быть 5 человек, а может 50), а справа — график дежурств (совершенно другая таблица).
Построчный вывод пересечений здесь применить крайне сложно, так как циклы обхода данных независимы. В таких ситуациях профессиональные разработчики используют технологию временных табличных документов:
ТабДокЛевый и ТабДокПравый.Вывести() и Присоединить().Посмотрим на пример реализации такого алгоритма:
// Создаем временные буферы
ТабДокЛевый = Новый ТабличныйДокумент;
ТабДокПравый = Новый ТабличныйДокумент;
// Наполняем левую часть (Область 2 и 3)
Для Каждого СтрокаИзИсточника1 Из ДанныеИсточника1 Цикл
ОбластьСтроки = Макет.ПолучитьОбласть("СтрокаЛевая");
ЗаполнитьПараметрыОбласти(ОбластьСтроки, СтрокаИзИсточника1);
ТабДокЛевый.Вывести(ОбластьСтроки); КонецЦикла;
// Наполняем правую часть (Область 4)
Для Каждого СтрокаИзИсточника2 Из ДанныеИсточника2 Цикл
ОбластьСтроки = Макет.ПолучитьОбласть("СтрокаПравая");
ЗаполнитьПараметрыОбласти(ОбластьСтроки, СтрокаИзИсточника2);
ТабДокПравый.Вывести(ОбластьСтроки);
КонецЦикла;
// Переносим левую часть в результирующий документ
ТабДок.Вывести(ТабДокЛевый);
// Определяем область-приемник для правой части
СтрокаНачала = 2; // Например, сразу под шапкой
КолонкаНачала = ТабДокЛевый.ШиринаТаблицы + 1;
СтрокаКонца = СтрокаНачала + ТабДокПравый.ВысотаТаблицы - 1;
КолонкаКонца = КолонкаНачала + ТабДокПравый.ШиринаТаблицы - 1;
ОбластьПриемник = ТабДок.Область(СтрокаНачала, КолонкаНачала, СтрокаКонца, КолонкаКонца);
// Вставляем правую часть в результат
ТабДок.ВставитьОбласть(ТабДокПравый.Область(), ОбластьПриемник, ТипСмещенияТабличногоДокумента.БезСмещения);
Этот способ незаменим при создании сложных аналитических дашбордов и многоколоночных отчетов со слабой связанностью данных между колонками.
Иногда область, которую нужно вывести сбоку, носит чисто декоративный, пояснительный характер или представляет собой штамп/карточку подписи. Если границы этой области не должны влиять на ширину колонок основной таблицы, выводить ее в сетку ячеек не имеет практического смысла — это лишь усложнит верстку.
Для таких задач идеально подходит использование объекта Рисунок табличного документа с типом ТипРисункаТабличногоДокумента.Текст или ТипРисункаТабличногоДокумента.ТабличныйДокумент.
Объект Рисунок позиционируется не по номерам строк и колонок, а по абсолютным координатам на листе в миллиметрах или пикселях. Это позволяет разместить его поверх любой части таблицы без риска «расползания» строк или ячеек.
// Получаем область из макета, содержащую рисунок штампа
ОбластьРисунка = Макет.ПолучитьОбласть("ОбластьСоШтампом");
РисунокМакет = ОбластьРисунка.Рисунки.ШтампПечати;
// Добавляем новый рисунок в результирующий документ
НовыйРисунок = ТабДок.Рисунки.Добавить(ТипРисункаТабличногоДокумента.ТабличныйДокумент);
ЗаполнитьЗначенияСвойств(НовыйРисунок, РисунокМакет);
// Устанавливаем точные геометрические координаты размещения рисунка на листе
НовыйРисунок.Верх = 120; // Координата Y в миллиметрах
НовыйРисунок.Лево = 150; // Координата X в миллиметрах
НовыйРисунок.Ширина = 50;
НовыйРисунок.Высота = 30;
Этот подход гарантирует стабильность верстки основного документа и исключает проблемы с нестыковкой ширины колонок в параллельных блоках данных.
Мы подробно проанализировали проблему нелинейного вывода областей в табличный документ 1С и изучили лучшие практики разработки. Подведем итоги:
"R24C1". Платформа предоставляет быстрые числовые свойства Верх, Низ, Лево, Право для любой области.ВставитьОбласть() с типом смещения БезСмещения.Строка|Колонка) — это архитектурный стандарт разработки в 1С.