При разработке отчетов и обработок на управляемых формах часто возникает задача вывода структурированных данных пользователю. Удобным инструментом для этого является элемент формы с типом ТабличныйДокумент. Однако, в отличие от списков или таблиц значений, у табличного документа нет встроенного интерактивного механизма фильтрации («Автофильтра»), аналогичного MS Excel. Перерисовывать весь табличный документ с нуля при изменении условий отбора — неэффективно, особенно если макет содержит сложные группировки или большой объем данных.
В этой статье мы подробно разберем, как реализовать быстрый динамический фильтр в табличном документе с помощью управления видимостью строк, а также рассмотрим альтернативный вариант решения этой задачи через Систему компоновки данных (СКД).
---
Этот способ является наиболее производительным при работе на тонком клиенте. Вместо повторного обращения к базе данных и полной перезаполнения макета, мы управляем отображением уже выведенных строк. Строки, которые не соответствуют критериям отбора, мы просто скрываем.
Разберем по шагам, как реализовать этот алгоритм, если нам нужно скрыть строки, у которых значения в соседних колонках (например, во второй и третьей) совпадают (или, наоборот, различаются).
Шаг 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Процедуры
---
Если логика фильтрации усложняется (пользователю нужно предоставлять выбор различных условий сравнения, отборы по нескольким колонкам, логические условия "И"/"ИЛИ"), то ручное программирование интерфейса скрытия строк становится трудоемким. В таких сценариях лучше использовать СКД.
Выясним, как спроектировать такое решение:
ТаблицаДанных.Результат с типом ТабличныйДокумент и выносим пользовательские настройки СКД (компоновщик настроек) прямо на форму.Посмотрим на пример серверного кода для вывода данных с учетом наложенных пользователем отборов:
&НаСервере
Процедура СформироватьОтчетНаСервере()
// Получаем исходную таблицу значений (например, из реквизита формы или базы данных)
ТаблицаДляВывода = ПолучитьИсходнуюТаблицуЗначений();
// Инициализируем схему и настройки СКД
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = Отчет.КомпоновщикНастроек.ПолучитьНастройки();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки);
// Передаем ТЗ во внешний набор данных
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ТаблицаДанных", ТаблицаДляВывода);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных);
// Очищаем табличный документ на форме и выводим результат
ТабДок = РеквизитФормыВЗначение("Объект").РезультатТабличныйДокумент;
ТабДок.Очистить();
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДок);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
При таком подходе при изменении отборов пользователю не нужно заново запрашивать базу данных. СКД мгновенно накладывает фильтры на уже готовую таблицу значений в оперативной памяти и быстро выводит обновленный результат в табличный документ.
---
Видимость = Ложь) физические индексы строк в табличном документе не изменяются. Скрытая строка №10 остается строкой №10. Это позволяет разработчику без проблем повторно применять к таблице другие фильтры без смещения адресации..xlsx (через стандартное меню или методом Записать()) скрытые строки сохраняют свой статус "скрытых" и в самом Excel. Пользователь сможет при необходимости отобразить их уже внутри редактора таблиц.ВременномХранилище. При необходимости полного сброса вы сможете за доли секунды восстановить исходный вид документа без повторного прохода по ячейкам.