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

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

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

В этой статье мы подробно разберем, как решить эту задачу в «1С:Предприятии 8». Мы проанализируем несколько подходов: от динамического проектирования макета на этапе вывода до постобработки уже готового табличного документа и оптимизации данных в запросе.

Метод 1. Динамический вывод макета с использованием вертикальных и горизонтальных областей

Это самый гибкий, профессиональный и производительный подход. Вместо того чтобы выводить макет целиком, а затем удалять ненужное, мы будем конструировать печатную форму «на лету», присоединяя только те колонки, которые гарантированно содержат данные.

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

  1. Горизонтальные именованные области: например, Шапка, Строка, Подвал.
  2. Вертикальные именованные области: для каждого столбца, например, Номенклатура, КоличествоА, КоличествоБ, КоличествоС.

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

Шаг 1. Определение заполненности колонок в запросе

Чтобы не обходить выборку дважды в цикле, мы можем получить информацию о наличии данных прямо из итогов запроса. Для этого используем агрегатную функцию КОЛИЧЕСТВО() по общим итогам. Если общий итог по колонке равен 0, значит, во всех строках этой колонки содержатся значения NULL.

Рассмотрим пример такого запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Данные.Номенклатура КАК Номенклатура,
    |	Данные.КоличествоА КАК КоличествоА,
    |	Данные.КоличествоБ КАК КоличествоБ,
    |	Данные.КоличествоС КАК КоличествоС
    |ИЗ
    |	Справочник.Номенклатура КАК Данные
    |ИТОГИ
    |	КОЛИЧЕСТВО(КоличествоА),
    |	КОЛИЧЕСТВО(КоличествоБ),
    |	КОЛИЧЕСТВО(КоличествоС)
    |ПО
    |	ОБЩИЕ";

РезультатЗапроса = Запрос.Выполнить();

Шаг 2. Анализ итогов запроса перед выводом

Проанализируем общие итоги выборки, чтобы взвести флаги видимости колонок:


ВыводитьКолонкуА = Ложь;
ВыводитьКолонкуБ = Ложь;
ВыводитьКолонкуС = Ложь;

ВыборкаОбщие = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Если ВыборкаОбщие.Следующий() Тогда
    ВыводитьКолонкуА = (ВыборкаОбщие.КоличествоА > 0);
    ВыводитьКолонкуБ = (ВыборкаОбщие.КоличествоБ > 0);
    ВыводитьКолонкуС = (ВыборкаОбщие.КоличествоС > 0); КонецЕсли;

Шаг 3. Алгоритм вывода макета

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

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


ТабДок = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("Макет");

// 1. Выводим Шапку таблицы
ОбластьШапкаНоменклатура = Макет.ПолучитьОбласть("Шапка|Номенклатура");
ТабДок.Вывести(ОбластьШапкаНоменклатура);

Если ВыводитьКолонкуА Тогда
    ОбластьШапкаКолонкаА = Макет.ПолучитьОбласть("Шапка|КолонкаА");
    ТабДок.Присоединить(ОбластьШапкаКолонкаА);
КонецЕсли;

Если ВыводитьКолонкуБ Тогда
    ОбластьШапкаКолонкаБ = Макет.ПолучитьОбласть("Шапка|КолонкаБ");
    ТабДок.Присоединить(ОбластьШапкаКолонкаБ);
КонецЕсли;

Если ВыводитьКолонкуС Тогда
    ОбластьШапкаКолонкаС = Макет.ПолучитьОбласть("Шапка|КолонкаС");
    ТабДок.Присоединить(ОбластьШапкаКолонкаС);
КонецЕсли;

// 2. Выводим строки данных
ВыборкаДетали = РезультатЗапроса.Выбрать();
Пока ВыборкаДетали.Следующий() Цикл
    
    ОбластьСтрокаНоменклатура = Макет.ПолучитьОбласть("Строка|Номенклатура");
    ОбластьСтрокаНоменклатура.Параметры.Номенклатура = ВыборкаДетали.Номенклатура;
    ТабДок.Вывести(ОбластьСтрокаНоменклатура);
    
    Если ВыводитьКолонкуА Тогда
        ОбластьСтрокаКолонкаА = Макет.ПолучитьОбласть("Строка|КолонкаА");
        ОбластьСтрокаКолонкаА.Параметры.КоличествоА = ВыборкаДетали.КоличествоА;
        ТабДок.Присоединить(ОбластьСтрокаКолонкаА);
    КонецЕсли;
    
    Если ВыводитьКолонкуБ Тогда
        ОбластьСтрокаКолонкаБ = Макет.ПолучитьОбласть("Строка|КолонкаБ");
        ОбластьСтрокаКолонкаБ.Параметры.КоличествоБ = ВыборкаДетали.КоличествоБ;
        ТабДок.Присоединить(ОбластьСтрокаКолонкаБ);
    КонецЕсли;
    
    Если ВыводитьКолонкуС Тогда
        ОбластьСтрокаКолонкаС = Макет.ПолучитьОбласть("Строка|КолонкаС");
        ОбластьСтрокаКолонкаС.Параметры.КоличествоС = ВыборкаДетали.КоличествоС;
        ТабДок.Присоединить(ОбластьСтрокаКолонкаС);
    КонецЕсли;
    
КонецЦикла;

Метод 2. Постобработка сформированного Табличного Документа

Если структура вашего макета слишком сложная или вы не хотите переписывать процедуру построения табличного документа «по колонкам», можно применить тактику постобработки. В этом случае мы выводим документ целиком (со всеми пустыми колонками), а затем программно скрываем или удаляем ненужные столбцы.

Рассмотрим три способа постобработки:

Вариант А. Скрытие колонки через нулевую ширину

Это самый быстрый и безопасный способ. Он не ломает адресацию ячеек и формулы в результирующем документе. Мы просто находим область нужной колонки по её индексу и устанавливаем ширину в значение 0.


// Предположим, пустая колонка "КоличествоБ" находится под индексом 3
НомерКолонки = 3;
ОбластьКолонки = ТабДок.Область(, НомерКолонки, , НомерКолонки);
ОбластьКолонки.ШиринаКолонки = 0;

Вариант Б. Использование свойства «Видимость»

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


НомерКолонки = 3;
ОбластьКолонки = ТабДок.Область(, НомерКолонки, , НомерКолонки);
ОбластьКолонки.Видимость = Ложь;

Вариант В. Физическое удаление области

Если вам требуется физически удалить столбцы из структуры таблицы, чтобы последующие колонки сдвинулись влево, используем метод УдалитьОбласть() с указанием горизонтального типа смещения:


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

Критически важное правило работы в цикле!

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

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


// Обходим колонки с конца
Для НомерКолонки = ВсегоКолонок По 1 Шаг -1 Цикл
    Если ПроверитьКолонкаПустая(ТабДок, НомерКолонки) Тогда
        ОбластьКолонки = ТабДок.Область(, НомерКолонки, , НомерКолонки);
        ТабДок.УдалитьОбласть(ОбластьКолонки, ТипСмещенияТабличногоДокумента.ПоГоризонтали);
    КонецЕсли;
КонецЦикла;

Метод 3. Предварительная очистка данных в Таблице Значений

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

Выясним, как это реализовать на практике:


ТЗ = РезультатЗапроса.Выгрузить();

СписокКолонокДляУдаления = Новый Массив;

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

// Удаляем пустые колонки из структуры ТЗ
Для Каждого КолонкаДляУдаления Из СписокКолонокДляУдаления Цикл
    ТЗ.Колонки.Удалить(КолонкаДляУдаления);
КонецЦикла;

После такой предобработки в таблице значений ТЗ останутся только те колонки, в которых есть реальные данные. Теперь мы можем динамически построить печатную форму, используя обход коллекции ТЗ.Колонки, и полностью избавиться от жестко закодированных условий в коде вывода макета.

Резюме

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

← На главную