Как в макете печатной формы 1С скрыть пустые колонки?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При разработке печатных форм документов, отчетов или обработок в 1С часто возникает задача оптимизации пространства на листе. Типичный пример: в отчете или печатной форме заложен календарный месяц (31 день), но данные есть только за несколько дней. Выводить все 31 колонку нецелесообразно, так как пустые столбцы делают таблицу громоздкой, нечитаемой и затрудняют вывод на печать. В этой статье мы подробно разберем, как решить эту проблему в обычных формах (без использования механизма компоновки данных — СКД) и скрыть пустые колонки в готовом табличном документе.

Проанализируем ситуацию: у нас есть макет печатной формы, в котором жестко задана структура колонок на 31 день. Нам необходимо определить, в каких из этих дней отсутствуют данные, и убрать эти колонки из итогового документа. Рассмотрим несколько вариантов реализации этой задачи — от простых и быстрых до наиболее архитектурно правильных.

Способ 1. Установка ширины колонки в ноль

Это самый быстрый и часто используемый разработчиками способ. Его суть заключается в том, что после формирования всего табличного документа мы находим области пустых колонок и программно устанавливаем их ширину равной нулю. При этом визуально колонка полностью исчезает с экрана и не выводится на печать.

Для реализации этого метода мы используем объект ТабличныйДокумент и его метод Область(). Посмотрим на пример кода, который скрывает конкретную колонку:


// НомерКолонки — это индекс столбца в сформированном Табличном Документе
НомерКолонки = 5; // Например, скрываем 5-й день
Область = ТабДок.Область(1, НомерКолонки, ТабДок.ВысотаТаблицы, НомерКолонки);
Область.Ширина = 0;

Преимущества метода: простота реализации. Не требуется менять логику построения самого макета.

Недостатки: при установке ширины в ноль в некоторых версиях платформы или при определенных настройках отображения могут оставаться видимыми границы ячеек (сетка), что визуально портит печатную форму. Кроме того, при экспорте в Excel такие колонки все равно физически будут присутствовать в файле, просто в скрытом виде.

Способ 2. Использование свойства «Видимость» (Рекомендуемый способ скрытия)

В платформе 1С для объектов типа ОбластьЯчеекТабличногоДокумента существует штатное свойство Видимость. Это более надежный инструмент, чем простое зануление ширины, поскольку он корректно обрабатывает границы смежных ячеек и полностью исключает колонку из структуры отображения.

Разберем по шагам, как применить это свойство ко всей вертикальной колонке сверху донизу. Обратите внимание, что в методе Область() мы можем не указывать номера строк (оставить их пустыми), чтобы получить область, состоящую из всей колонки целиком:


// Получаем область всей колонки без привязки к конкретным строкам
ОбластьКолонки = ТабДок.Область(, НомерКолонки, , НомерКолонки);
ОбластьКолонки.Видимость = Ложь;

Этот вариант является более чистым с точки зрения платформенных стандартов 1С. Колонка перестает влиять на ширину печатного листа, а сетка таблицы перестраивается автоматически без деформаций.

Способ 3. Физическое удаление пустых колонок

Если вам требуется, чтобы пустые колонки не просто скрывались, а полностью удалялись из результирующего табличного документа (что особенно критично при последующем сохранении в XLS/PDF), можно применить метод УдалитьОбласть(). При этом оставшиеся колонки автоматически сдвинутся влево.

Выясним, как правильно написать такой код:


// Определяем область колонки, которую нужно удалить
ОбластьДляУдаления = ТабДок.Область(, НомерКолонки, , НомерКолонки);

// Удаляем область с горизонтальным смещением табличного документа
ТабДок.УдалитьОбласть(ОбластьДляУдаления, ТипСмещенияТабличногоДокумента.ПоГоризонтали);

Важное примечание: при физическом удалении колонок в цикле обязательно нужно производить обход колонок справа налево (то есть от большего номера к меньшему). В противном случае после удаления первой же колонки индексы всех последующих колонок сместятся, и вы удалите не те столбцы либо вызовете ошибку выхода за границы индекса.

Способ 4. Как избежать написания 31 условия (Динамический обход данных)

Частая ошибка начинающих разработчиков — написание 31 конструкции Если...Тогда для проверки каждого дня отдельно. Это приводит к раздуванию кода и усложнению поддержки. Проанализируем, как обойти эту проблему элегантно с помощью предварительного анализа данных в ТаблицеЗначений.

Рассмотрим алгоритм динамического определения пустых колонок:

  1. Выгружаем результат запроса с данными во временную ТаблицуЗначений.
  2. Создаем список (или массив) колонок, которые потенциально могут быть пустыми (например, имена колонок от "День1" до "День31").
  3. В цикле обходим строки таблицы значений. Если в строке значение проверяемого дня заполнено, удаляем имя этого дня из нашего списка "пустых".
  4. По окончании проверки у нас останется список только тех колонок, в которых во всех строках отсутствуют данные.
  5. Проходим циклом по оставшемуся списку пустых колонок в обратном порядке и скрываем или удаляем их в ТабличномДокументе.

Посмотрим на пример реализации такого алгоритма:


// Предположим, ТаблицаДанных - это ТЗ с результатами нашего запроса
// Шаг 1. Создаем массив имен колонок, которые нужно проверить
МассивПустыхКолонок = Новый Массив;
Для День = 1 По 31 Цикл
    МассивПустыхКолонок.Добавить("День" + День);
КонецЦикла;

// Шаг 2. Исключаем из массива те колонки, где есть хотя бы одно значение
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
    Для Индекс = -МассивПустыхКолонок.ВГруппа() По 0 Цикл
        // Обходим с конца, чтобы безопасно удалять элементы из массива во время итерации
        ОбратныйИндекс = -Индекс;
        ИмяКолонки = МассивПустыхКолонок[ОбратныйИндекс];
        
        Если ЗначениеЗаполнено(СтрокаДанных[ИмяКолонки]) Тогда
            МассивПустыхКолонок.Удалить(ОбратныйИндекс);
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

// В МассивПустыхКолонок остались только те имена, по которым нет данных во всей ТЗ
// Теперь при выводе в ТабДок мы можем скрывать соответствующие области

Способ 5. Лучший архитектурный подход: Динамическое построение (Вертикальные области)

Самым профессиональным решением является отказ от статического макета на 31 день. Вместо того чтобы выводить заведомо избыточные колонки, а затем мужественно скрывать их или удалять, правильнее изначально конструировать печатную форму только из тех колонок, по которым есть данные.

Для этого в конфигураторе наш макет разбивается не только на горизонтальные строки, но и на вертикальные секции (колонки). Мы создаем:

Аналогичным образом на горизонтальные и вертикальные секции разбиваются и строки данных (например: СтрокаЛево, СтрокаДень, СтрокаПраво).

Рассмотрим подробнее логику вывода документа в коде:


// 1. Получаем список только тех дней (или дат), по которым реально есть данные
СписокДнейСДанными = ПолучитьСписокДнейСДанными(ВыборкаЗапроса);

// 2. Выводим левую фиксированную часть шапки
ОбластьШапкаЛево = Макет.ПолучитьОбласть("ШапкаЛево");
ТабДок.Вывести(ОбластьШапкаЛево);

// 3. Динамически присоединяем только нужные колонки дней в шапку
Для Каждого ТекущийДень Из СписокДнейСДанными Цикл
    ОбластьШапкаДень = Макет.ПолучитьОбласть("ШапкаДень");
    ОбластьШапкаДень.Параметры.НомерДня = ТекущийДень;
    ТабДок.Присоединить(ОбластьШапкаДень); // Метод Присоединить() дописывает область справа
КонецЦикла;

// 4. Присоединяем правую фиксированную часть шапки
ОбластьШапкаПраво = Макет.ПолучитьОбласть("ШапкаПраво");
ТабДок.Присоединить(ОбластьШапкаПраво);

// 5. Выводим строки с данными по аналогичной схеме
Пока ВыборкаСтрок.Следующий() Цикл
    
    // Выводим левую часть строки данных
    ОбластьСтрокаЛево = Макет.ПолучитьОбласть("СтрокаЛево");
    ЗаполнитьЗначенияСвойств(ОбластьСтрокаЛево.Параметры, ВыборкаСтрок);
    ТабДок.Вывести(ОбластьСтрокаЛево);
    
    // Присоединяем только те дни, которые мы определили в начале
    Для Каждого ТекущийДень Из СписокДнейСДанными Цикл
        ОбластьСтрокаДень = Макет.ПолучитьОбласть("СтрокаДень");
        // Получаем значение показателя за конкретный день из выборки
        ОбластьСтрокаДень.Параметры.ЗначениеПоказателя = ПолучитьЗначениеЗаДень(ВыборкаСтрок, ТекущийДень);
        ТабДок.Присоединить(ОбластьСтрокаДень);
    КонецЦикла;
    
    // Присоединяем правую часть строки с итогами
    ОбластьСтрокаПраво = Макет.ПолучитьОбласть("СтрокаПраво");
    ОбластьСтрокаПраво.Параметры.Итого = ВыборкаСтрок.Итого;
    ТабДок.Присоединить(ОбластьСтрокаПраво);
    
КонецЦикла;

При таком подходе в итоговой таблице никогда не возникнет лишних пустых колонок. Код получается максимально декларативным, чистым и легко масштабируемым. Если в будущем вам потребуется выводить не 31 день, а, например, данные за целый год по неделям, структура алгоритма останется неизменной — поменяется только логика заполнения исходного списка выводимых колонок.

← На главную