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