При разработке интерфейсов форм в 1С часто возникает задача отобразить суммарные показатели по колонкам табличной части или таблицы значений. Если колонка имеет числовой тип данных, платформа позволяет легко включить флаг автоматического подсчета итогов. Однако в ситуациях, когда колонка содержит ссылочный тип данных (например, СправочникСсылка.Магазины, СправочникСсылка.Сотрудники) или строки, стандартный механизм ОтображатьИтогиВПодвале становится недоступным для автоматического суммирования. Разберем по шагам, почему возникает данное ограничение и как программно реализовать подсчет и вывод итогов в подвал таблицы.
Проанализируем механику работы стандартных таблиц. Автоматический расчет платформы рассчитан исключительно на математическое суммирование числовых значений. Когда в ячейках хранятся ссылки на элементы справочников, документов или строковые представления, платформа не может по умолчанию определить, какую агрегатную функцию ожидает разработчик (количество непустых, количество уникальных или конкатенацию).
Несмотря на то, что флаг автоматического итога для колонки отключен, сама строка подвала у табличного поля может отображаться при установленном свойстве таблицы Подвал = Истина. Это дает нам возможность программно рассчитать нужное значение и передать его в ячейку подвала.
Рассмотрим классический вариант реализации для обычных форм. Задача заключается в том, чтобы обойти строки таблицы, проверить заполненность значения в каждой колонке с помощью функции ЗначениеЗаполнено() или сравнения с пустой ссылкой и присвоить полученный результат свойству колонки ТекстПодвала.
Посмотрим на пример процедуры подсчета количества выходов по дням месяца:
Процедура РассчитатьИтогиТабеля()
// Включаем отображение подвала у элемента формы
ЭлементыФормы.Табель.Подвал = Истина;
// Инициализируем структуру или переменные счетчиков
СчетчикиДней = Новый Массив(32);
Для Индекс = 1 По 31 Цикл
СчетчикиДней[Индекс] = 0;
КонецЦикла;
// Обходим строки табличной части
Для Каждого Стр Из Табель Цикл
Для День = 1 По 31 Цикл
ИмяКолонки = "День" + День;
Если ЗначениеЗаполнено(Стр[ИмяКолонки]) Тогда
СчетчикиДней[День] = СчетчикиДней[День] + 1;
КонецЕсли;
КонецЦикла;
КонецЦикла;
// Выводим полученные значения в подвал соответствующих колонок
Для День = 1 По 31 Цикл
ИмяКолонки = "День" + День;
ЭлементыФормы.Табель.Колонки[ИмяКолонки].ТекстПодвала = Формат(СчетчикиДней[День], "ЧН=0");
ЭлементыФормы.Табель.Колонки[ИмяКолонки].ГоризонтальноеПоложениеВПодвале = ПоложениеТекста.Право;
КонецЦикла;
КонецПроцедуры
Выясним причину возможных проблем с производительностью. Частой ошибкой является размещение тяжелых циклов пересчета в обработчике события формы ОбновлениеОтображения(). Данное событие вызывается платформой очень часто: при любом перемещении курсора, смене фокуса и перерисовке элементов. Это приводит к ощутимым зависаниям интерфейса.
Правильным подходом является вызов процедуры расчета строго в тех событиях, где данные действительно изменяются:
ПриОткрытии) — для первичного заполнения подвала при загрузке данных.ПриИзменении поля ввода колонки) — пересчитывает итог сразу после выбора значения пользователем.ПослеУдаления, ПриОкончанииРедактированияСтроки) — обновляет итоги при удалении или добавлении сотрудников.Если в табличной части находится большое количество строк (сотни или тысячи записей), последовательный перебор всех ячеек может замедлить отклик формы. В таких случаях эффективнее использовать расчет через объект Запрос по выгруженной таблице.
Рассмотрим пример формирования запроса к временной таблице:
Процедура РассчитатьИтогиЗапросом()
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
// Передаем текущие данные таблицы в запрос
Запрос.Текст =
"ВЫБРАТЬ *
|ПОМЕСТИТЬ ВТ_Табель
|ИЗ &ТаблицаТабеля КАК ТаблицаТабеля;
|
|ВЫБРАТЬ
| СУММА(ВЫБОР КОГДА ВТ.День1 <> ЗНАЧЕНИЕ(Справочник.Магазины.ПустаяСсылка) ТОГДА 1 ИНАЧЕ 0 КОНЕЦ) КАК День1,
| СУММА(ВЫБОР КОГДА ВТ.День2 <> ЗНАЧЕНИЕ(Справочник.Магазины.ПустаяСсылка) ТОГДА 1 ИНАЧЕ 0 КОНЕЦ) КАК День2
|ИЗ
| ВТ_Табель КАК ВТ";
Запрос.УстановитьПараметр("ТаблицаТабеля", Табель.Выгрузить());
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
ЭлементыФормы.Табель.Колонки.День1.ТекстПодвала = Строка(Выборка.День1);
ЭлементыФормы.Табель.Колонки.День2.ТекстПодвала = Строка(Выборка.День2);
КонецЕсли;
КонецПроцедуры
В управляемом интерфейсе прямое свойство ТекстПодвала у элемента колонки таблицы формы отсутствует. Для вывода произвольных итогов используется другой механизм:
ИтогДень1, ИтогДень2).ПутьКДаннымПодвала, куда указывается соответствующий реквизит формы.Подвал = Истина.Таким образом, комбинируя явное включение видимости подвала, проверку заполненности ссылок через ЗначениеЗаполнено() и привязку расчета к корректным событиям формы, можно организовать удобный и быстрый вывод итогов для любых нечисловых данных.