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

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

При работе с большими табличными частями в управляемых формах 1С пользователям часто требуется отобрать строки по конкретному значению (например, по номенклатуре, ставке НДС или контрагенту) с помощью стандартной кнопки «Найти» (пиктограмма с лупой или сочетание клавиш Ctrl+F). Однако после применения такого отбора подвал таблицы продолжает отображать общую сумму по всем строкам документа, игнорируя наложенный фильтр. Разберем, почему платформа ведет себя именно так и какими способами можно реализовать динамический расчет итогов только по видимым строкам.

Выясним причину проблемы и архитектурные ограничения платформы

Чтобы найти правильное решение, проанализируем внутренние механизмы платформы 1С:Предприятие 8.3:

  1. Поведение стандартного подвала: Когда в свойствах колонки таблицы формы указан ПутьКДаннымПодвала (например, Объект.Товары.ИтогСумма), значение рассчитывается платформой автоматически через вызов метода Итог() применительно к коллекции ДанныеФормыКоллекция. Этот метод всегда суммирует значения абсолютно всех строк в памяти, вне зависимости от их видимости на экране.
  2. Отсутствие событий на интерактивный фильтр: Инструмент «Найти» в управляемом интерфейсе работает исключительно на уровне визуального слоя клиентского приложения. При его вызове, установке условий или сбросе платформа принципиально не генерирует никаких событий формы или таблицы (таких как ПриИзменении, ПослеУстановкиОтбора и аналогичных). Точка останова в модуле формы в момент поиска не срабатывает.
  3. Особенность свойства ОтборСтрок: Стандартный интерактивный поиск через лупу не заполняет свойство таблицы ОтборСтрок. Данное свойство предназначено исключительно для программной установки отбора по фиксированной структуре равенств и не отражает критерии поиска по подстроке.

Использование метода ПроверитьСтроку() для определения видимости

Для программной проверки того, отображается ли конкретная строка с учетом активного интерактивного поиска, в объекте ТаблицаФормы предусмотрен специальный метод ПроверитьСтроку(). Рассмотрим его синтаксис:

Элементы.ИмяТаблицы.ПроверитьСтроку(ИдентификаторСтроки)

Данный метод принимает идентификатор строки (получаемый через Строка.ПолучитьИдентификатор()), возвращает значение типа Булево (Истина, если строка удовлетворяет условиям текущего поиска, и Ложь в противном случае) и выполняется строго на клиенте без дополнительных обращений к серверу. Результат расчета выводится не через ПутьКДаннымПодвала, а напрямую в свойство колонки ТекстПодвала.

Разберем базовую процедуру пересчета суммы по отобранным строкам:


&НаКлиенте
Процедура ПересчитатьИтогПоВидимымСтрокам()
    
    ИтоговаяСумма = 0;
    
    Для Каждого Стр Из Объект.Товары Цикл
        Идентификатор = Стр.ПолучитьИдентификатор();
        Если Элементы.Товары.ПроверитьСтроку(Идентификатор) Тогда
            ИтоговаяСумма = ИтоговаяСумма + Стр.Сумма;
        КонецЕсли;
    КонецЦикла;
    
    Элементы.ТоварыСумма.ТекстПодвала = Формат(ИтоговаяСумма, "ЧДЦ=2");
    
КонецПроцедуры

Поскольку на само нажатие кнопки «Найти» подписаться невозможно, разберем практические сценарии внедрения этой процедуры.

Вариант 1. Замена стандартного поиска собственным полем отбора

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

  1. В командной панели таблицы отключаем стандартную кнопку поиска (через состав команд или свойство ПоложениеКоманднойПанели).
  2. Добавляем в форму строковый реквизит, например, СтрокаПоиска, и выносим его на форму в виде поля ввода рядом с таблицей.
  3. В событии ПриИзменении этого поля накладываем отбор на строки и вызываем пересчет итогов.

Посмотрим на пример реализации:


&НаКлиенте
Процедура СтрокаПоискаПриИзменении(Элемент)
    
    // Если отбор строится по точному соответствию реквизита:
    Если ЗначениеЗаполнено(СтрокаПоиска) Тогда
        НовыйОтбор = Новый ФиксированнаяСтруктура("Артикул", СтрокаПоиска);
        Элементы.Товары.ОтборСтрок = НовыйОтбор;
    Иначе
        Элементы.Товары.ОтборСтрок = Неопределено;
    КонецЕсли;
    
    // Пересчитываем сумму с учетом наложенного фильтра
    ПересчитатьИтогПоВидимымСтрокам();
    
КонецПроцедуры

Вариант 2. Комбинация событий ПриАктивизацииСтроки и редактирования данных

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

  1. В событии ПриИзменении колонок, влияющих на сумму (например, Количество, Цена, Сумма), вызываем ПересчитатьИтогПоВидимымСтрокам().
  2. В событии ПриАктивизацииСтроки таблицы формы также вызываем пересчет.

&НаКлиенте
Процедура ТоварыПриАктивизацииСтроки(Элемент)
    ПересчитатьИтогПоВидимымСтрокам();
КонецПроцедуры

&НаКлиенте
Процедура ТоварыСуммаПриИзменении(Элемент)
    ПересчитатьИтогПоВидимымСтрокам();
КонецПроцедуры

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

Вариант 3. Добавление команды ручного пересчета

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


&НаКлиенте
Процедура КомандаПосчитатьИтогПоФильтру(Команда)
    ПересчитатьИтогПоВидимымСтрокам();
КонецПроцедуры

Пользователь накладывает стандартный отбор через Ctrl+F, нажимает кнопку команды и получает точный расчет в подвале без избыточной нагрузки на клиентское приложение.

Вариант 4. Использование обработчика ожидания

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

Разберем правила безопасной настройки обработчика:

  1. Процедура должна выполняться строго &НаКлиенте без контекстных серверных вызовов (без директив &НаСервере).
  2. Интервал вызова должен составлять не менее 1–2 секунд, чтобы не перегружать интерфейс.
  3. Обязательно отключаем обработчик ожидания в событии формы ПриЗакрытии.

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    ПодключитьОбработчикОжидания("ФоновыйПересчетИтогов", 2, Ложь);
КонецПроцедуры

&НаКлиенте
Процедура ФоновыйПересчетИтогов()
    ПересчитатьИтогПоВидимымСтрокам();
КонецПроцедуры

&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
    ОтключитьОбработчикОжидания("ФоновыйПересчетИтогов");
КонецПроцедуры

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

← На главную