В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача отображения итогов по таблице, которая находится непосредственно на форме (например, связанная с ТаблицейЗначений или ТабличнойЧастью). Особую сложность вызывает ситуация, когда пользователь применяет стандартную команду "Найти" (вызываемую через Ctrl+F или контекстное меню). Стандартные механизмы платформы визуально скрывают строки, не подходящие под критерии поиска, но программно количество строк в самой коллекции данных (объекте) не меняется. В этой статье мы подробно разберем, как вычислить количество фактически видимых пользователю строк и где лучше всего разместить этот код.
Рассмотрим стандартную ситуацию: на управляемой форме размещена таблица. Данные в нее попадают из реквизита формы с типом ТаблицаЗначений. Когда пользователь нажимает кнопку "Найти" и вводит строку поиска, платформа фильтрует отображение. Однако, если мы просто обратимся к свойству Объект.ИмяТЧ.Количество(), мы получим общее число строк, которое было до начала поиска. События "ПослеПоиска" в платформе не существует, что ставит разработчика в тупик. Проанализируем, какие инструменты у нас есть в арсенале для решения этой задачи.
Ключом к решению является метод элемента формы "Таблица" — ПроверитьСтроку(). Этот метод предназначен специально для того, чтобы определить, удовлетворяет ли конкретная строка всем установленным фильтрам, включая:
ОтборСтрок, установленный через расширение таблицы.Метод ПроверитьСтроку() доступен только на клиенте и принимает в качестве параметра идентификатор строки. Если строка видима пользователю, метод возвращает Истина.
Разберем по шагам, как реализовать механизм подсчета. Нам потребуется создать процедуру, которая будет обходить коллекцию данных и проверять каждую строку на "видимость".
Для начала создадим на форме реквизит КоличествоВидимыхСтрок (тип "Число"). Выведем его на форму в виде надписи или в подвал соответствующей колонки таблицы. Теперь напишем клиентскую процедуру для пересчета:
&НаКлиенте
Процедура ПересчитатьКоличествоВидимыхСтрок()
ПеременнаяСчетчик = 0;
ЭлементТаблица = Элементы.ИмяВашейТаблицы; // Обращаемся к элементу формы
КоллекцияДанных = Объект.ИмяТЧ; // Обращаемся к данным (например, Табличная часть)
Для каждого СтрокаДанных Из КоллекцияДанных Цикл
// Получаем уникальный идентификатор строки для метода проверки
ИдентификаторСтроки = СтрокаДанных.ПолучитьИдентификатор();
// Проверяем, отображается ли строка в данный момент
Если ЭлементТаблица.ПроверитьСтроку(ИдентификаторСтроки) Тогда
ПеременнаяСчетчик = ПеременнаяСчетчик + 1;
КонецЕсли;
КонецЦикла;
// Обновляем реквизит на форме
КоличествоВидимыхСтрок = ПеременнаяСчетчик;
КонецПроцедуры
Выясним причину, по которой это решение не всегда работает автоматически. Главный вопрос: когда вызывать эту процедуру? Поскольку явного события завершения поиска нет, рассмотрим основные варианты:
Рассмотрим пример реализации через ПриОбновленииОтображения с защитой от лишних вычислений:
&НаКлиенте
Процедура ПриОбновленииОтображения()
// Используем ПодключитьОбработчикОжидания, чтобы расчет
// не "вешал" интерфейс при каждом движении мыши
ПодключитьОбработчикОжидания("ВыполнитьОтложенныйПересчет", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьОтложенныйПересчет()
ПересчитатьКоличествоВидимыхСтрок();
КонецПроцедуры
Если вам нужно не просто посчитать количество строк, а вычислить сумму, среднее или другие сложные агрегатные функции по отфильтрованным данным, обычного цикла на клиенте может быть недостаточно из-за низкой производительности. В этом случае проанализируем ситуацию с использованием Системы Компоновки Данных (СКД).
Если ваша таблица — это ДинамическийСписок, вы можете на сервере получить исполняемую схему и настройки, чтобы выполнить запрос с учетом всех пользовательских отборов. Посмотрим на пример кода, который позволяет получить результат компоновки данных:
&НаСервере
Функция ПолучитьКоличествоЧерезСКД()
Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
Настройки = Элементы.Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
РезультатТЗ = ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Возврат РезультатТЗ.Количество();
КонецФункции
Обратите внимание: этот метод подходит преимущественно для ДинамическихСписков. Для обычных таблиц значений, заполняемых программно, метод ПроверитьСтроку() на клиенте остается приоритетным и самым простым в реализации.
Важно различать ОтборСтрок и интерактивный поиск. Если вы программно устанавливаете Элементы.Таблица.ОтборСтрок, это свойство ограничивает набор данных на уровне отображения элемента. Метод ПроверитьСтроку() корректно обработает и этот случай. Однако помните, что интерактивный поиск "Найти" работает поверх ваших программных отборов. Таким образом, использование цикла с проверкой каждой строки является максимально надежным способом получить именно то число, которое пользователь видит на своем экране в данный момент.
Проанализируем производительность. Если в вашей таблице более 5-10 тысяч строк, клиентский цикл с вызовом ПроверитьСтроку() может привести к заметным задержкам (фризам) интерфейса. В таких случаях мы рекомендуем:
Подводя итог, можно сказать, что несмотря на отсутствие прямого события "ПоискЗавершен", комбинация метода ПроверитьСтроку() и обработчика ПриОбновленииОтображения позволяет полностью решить задачу контроля количества записей в управляемых формах 1С.