Как пересчитать итоги в подвале табличной части 1С при использовании отбора строк

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

Разработчики при проектировании интерфейсов в управляемом приложении 1С часто сталкиваются с задачей фильтрации строк в табличной части документа или обработки. Платформа предоставляет для этого удобный механизм программной фильтрации через свойство ОтборСтрок элемента формы — для этого подойдёт панель фильтров с динамическим расчетом количества элементов. Однако стандартный механизм подсчета итогов, который настраивается через свойство колонки ПутьКДаннымПодвала, всегда рассчитывает итог по всей табличной части объекта метаданных, полностью игнорируя видимость строк на форме.

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

Решение 1. Клиентский обход строк с использованием метода ПроверитьСтроку()

Рассмотрим самый простой способ, который работает непосредственно на клиенте. Он основан на использовании метода ПроверитьСтроку() элемента формы «Таблица». Этот метод анализирует, отображается ли строка в данный момент на форме с учетом всех установленных отборов, поиска и фильтров.

Давайте разберем по шагам код клиентской процедуры пересчета итогов:


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

Важные технические нюансы этого решения:

  1. Безопасность типов при проверке строки. Метод ПроверитьСтроку() может возвращать не только булевы значения Истина или Ложь, но и значение Неопределено (например, если таблица еще скрыта или строка не успела отрисоваться на экране). Если написать условие как Если ТаблицаФормы.ПроверитьСтроку(...) Тогда, то при возврате значения Неопределено платформа выдаст критическую ошибку приведения типов. Использование конструкции Если ... = Истина Тогда полностью решает эту проблему.
  2. Использование идентификатора строки. Вместо получения индекса строки через метод Индекс(), гораздо надежнее использовать метод ПолучитьИдентификатор(). Индексы строк коллекции данных формы могут изменяться при интерактивных действиях пользователя, тогда как уникальный идентификатор строки остается неизменным.
  3. Падение производительности на больших таблицах. Этот метод выполняется на клиенте. Если в табличной части содержится более 1000 строк, цикл с вызовом метода ПроверитьСтроку() вызовет задержку интерфейса («зависание» формы на несколько секунд). Это связано с тем, что метод анализирует визуальное состояние элементов отрисовки. Если в таблице планируется большое количество строк, лучше использовать альтернативный серверный подход.

Решение 2. Альтернативный быстрый расчет на сервере (для программных отборов)

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

Выясним причину эффективности этого подхода: серверный код платформы выполняется на уровне скомпилированного C++ кода, что работает в десятки раз быстрее клиентского интерпретатора.

Вариант А. Использование метода Выгрузить() с отбором

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


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

Вариант Б. Использование метода НайтиСтроки()

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


&НаСервере
Функция РассчитатьИтогПоискомНаСервере(Знач СтруктураОтбора)
    
    НайденныеСтроки = Объект.Закупки.НайтиСтроки(СтруктураОтбора);
    ИтогСумма = 0;
    
    Для Каждого Строка Из НайденныеСтроки Цикл
        ИтогСумма = ИтогСумма + Строка.Сумма;
    КонецЦикла;
    
    Возврат ИтогСумма;
    
КонецФункции

Оба метода отлично подходят для таблиц любого объема и не вызывают визуальных задержек у пользователя — для этого подойдёт расширение для расчета агрегатных данных и итогов.

Как правильно настроить и вывести итог в подвал формы

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

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

Элементы.ЗакупкиСумма.ТекстПодвала = Формат(СуммаИтог, "ЧДЦ=2");

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

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

Давайте проанализируем, в каких обработчиках событий (поможет конструктор интерактивных отборов в списках) необходимо размещать вызов процедуры пересчета итогов, чтобы данные всегда оставались актуальными:

Решением проблемы производительности при активизации строки является использование обработчика ожидания с небольшой задержкой (например, 0.1–0.2 секунды). Это позволит запускать расчет только тогда, когда пользователь остановил перемещение по таблице:


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

&НаКлиенте
Процедура ВыполнитьАсинхронныйПересчетИтогов()
    
    // Данный метод выполнится один раз, когда пользователь прекратит быстро листать строки
    ПересчитатьИтогиНаКлиенте();
    
КонецПроцедуры

Обход ограничений механизма ОтборСтрок

Стоит помнить, что платформенное свойство ОтборСтрок работает исключительно по принципу жесткого равенства. Если перед вами стоит задача отфильтровать строки по сложному условию (например, «Не равно», «В списке значений» или «Больше определенной даты»), этот механизм напрямую использовать не удастся.

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

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

СтруктураОтбора = Новый ФиксированнаяСтруктура("ПоказыватьСтроку", Истина);
Элементы.Закупки.ОтборСтрок = СтруктураОтбора;

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

← На главную