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

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

При разработке отчетов и обработок на управляемых формах часто возникает задача вывода структурированных данных пользователю. Удобным инструментом для этого является элемент формы с типом ТабличныйДокумент. Однако, в отличие от списков или таблиц значений, у табличного документа нет встроенного интерактивного механизма фильтрации («Автофильтра»), аналогичного MS Excel. Перерисовывать весь табличный документ с нуля при изменении условий отбора — неэффективно, особенно если макет содержит сложные группировки или большой объем данных.

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

---

Метод 1. Динамическое скрытие строк через свойство «Видимость»

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

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

Шаг 1. Получение данных и обход табличного документа

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

Рассмотрим пример кода, который обходит строки табличного документа и скрывает те, где значения во второй и третьей колонках равны:


&НаКлиенте
Процедура ПрименитьФильтрРазличныхЗначений()
    
    ТабДок = Объект.РезультатТабличныйДокумент;
    КоличествоСтрок = ТабДок.ВысотаТаблицы;
    
    // Начинаем со строки 2, предполагая, что строка 1 — это шапка таблицы
    Для НомерСтроки = 2 По КоличествоСтрок Цикл
        
        ЗначениеКолонки2 = ТабДок.Область(НомерСтроки, 2).Текст;
        ЗначениеКолонки3 = ТабДок.Область(НомерСтроки, 3).Текст;
        
        // Условие отбора: нам нужны только строки с различными значениями
        Если ЗначениеКолонки2 <> ЗначениеКолонки3 Тогда
            ТабДок.Область(НомерСтроки, , НомерСтроки, ).Видимость = Истина;
        Иначе
            ТабДок.Область(НомерСтроки, , НомерСтроки, ).Видимость = Ложь;
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

В данном примере метод Область(НомерСтроки, , НомерСтроки, ) выделяет всю строку целиком. Присвоение свойству Видимость значения Ложь скрывает строку из интерфейса пользователя.

Шаг 2. Оптимизация для больших таблиц

Если табличный документ содержит десятки тысяч строк, построчный обход и одиночное изменение видимости каждой строки может привести к «зависанию» интерфейса. Чтобы избежать этого, мы можем группировать смежные скрываемые строки в единые области и скрывать их одной командой. Давайте проанализируем оптимизированный вариант:


&НаКлиенте
Процедура ПрименитьФильтрОптимизированно()
    
    ТабДок = Объект.РезультатТабличныйДокумент;
    КоличествоСтрок = ТабДок.ВысотаТаблицы;
    
    НачалоИнтервалаСкрытия = 0;
    
    Для НомерСтроки = 2 По КоличествоСтрок Цикл
        
        ЗначениеКолонки2 = ТабДок.Область(НомерСтроки, 2).Текст;
        ЗначениеКолонки3 = ТабДок.Область(НомерСтроки, 3).Текст;
        
        Если ЗначениеКолонки2 = ЗначениеКолонки3 Тогда
            // Строка должна быть скрыта. Запоминаем начало интервала
            Если НачалоИнтервалаСкрытия = 0 Тогда
                НачалоИнтервалаСкрытия = НомерСтроки;
            КонецЕсли;
        Иначе
            // Строка должна остаться видимой. 
            // Если перед этим у нас накопился интервал для скрытия — скрываем его целиком
            Если НачалоИнтервалаСкрытия > 0 Тогда
                ТабДок.Область(НачалоИнтервалаСкрытия, , НомерСтроки - 1, ).Видимость = Ложь;
                НачалоИнтервалаСкрытия = 0;
            КонецЕсли;
            
            ТабДок.Область(НомерСтроки, , НомерСтроки, ).Видимость = Истина;
        КонецЕсли;
        
    КонецЦикла;
    
    // Скрываем последний накопленный интервал, если он остался в конце таблицы
    Если НачалоИнтервалаСкрытия > 0 Тогда
        ТабДок.Область(НачалоИнтервалаСкрытия, , КоличествоСтрок, ).Видимость = Ложь;
    КонецЕсли;
    
КонецПроцедуры

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

Шаг 3. Быстрый сброс фильтров

Для того чтобы вернуть таблицу в исходное состояние, нам не нужно снова перебирать все строки в цикле. Мы можем восстановить видимость абсолютно всех строк одной строчкой кода:


&НаКлиенте
Процедура СброситьВсеФильтры()
    ТабДок = Объект.РезультатТабличныйДокумент;
    // Делаем видимыми все строки, начиная со второй и до самого конца таблицы
    ТабДок.Область(2, , ТабДок.ВысотаТаблицы, ).Видимость = Истина;
EndПроцедуры

---

Метод 2. Использование Системы компоновки данных (СКД) с внешним набором

Если логика фильтрации усложняется (пользователю нужно предоставлять выбор различных условий сравнения, отборы по нескольким колонкам, логические условия "И"/"ИЛИ"), то ручное программирование интерфейса скрытия строк становится трудоемким. В таких сценариях лучше использовать СКД.

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

  1. Создаем схему компоновки данных, в которой определяем Набор данных - объект. Именем объекта указываем, например, ТаблицаДанных.
  2. На управляемой форме размещаем стандартный элемент Результат с типом ТабличныйДокумент и выносим пользовательские настройки СКД (компоновщик настроек) прямо на форму.
  3. При формировании отчета передаем исходную таблицу значений (ТЗ) в качестве внешнего набора данных.

Посмотрим на пример серверного кода для вывода данных с учетом наложенных пользователем отборов:


&НаСервере
Процедура СформироватьОтчетНаСервере()
    
    // Получаем исходную таблицу значений (например, из реквизита формы или базы данных)
    ТаблицаДляВывода = ПолучитьИсходнуюТаблицуЗначений();
    
    // Инициализируем схему и настройки СКД
    СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    Настройки = Отчет.КомпоновщикНастроек.ПолучитьНастройки();
    
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки);
    
    // Передаем ТЗ во внешний набор данных
    ВнешниеНаборыДанных = Новый Структура;
    ВнешниеНаборыДанных.Вставить("ТаблицаДанных", ТаблицаДляВывода);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных);
    
    // Очищаем табличный документ на форме и выводим результат
    ТабДок = РеквизитФормыВЗначение("Объект").РезультатТабличныйДокумент;
    ТабДок.Очистить();
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ТабДок);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

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

---

Технические нюансы и рекомендации

← На главную