Как программно добавить колонку «Итого» в динамическую таблицу значений и рассчитать сумму по строке?

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

В практике разработки на платформе 1С:Предприятие 8.3 часто возникают задачи, когда структура таблицы на форме заранее неизвестна. Например, при формировании планов продаж или графиков производства количество колонок зависит от выбранного пользователем периода (месяцы, декады, дни). Одной из ключевых подзадач в таких интерфейсах является создание итоговой колонки, которая должна автоматически суммировать данные по всей строке. Разберем подробно, как реализовать этот функционал программно.

Шаг 1. Программное создание реквизита и элемента формы

Прежде чем выводить данные, необходимо создать сам «контейнер» для них. Поскольку наша таблица динамическая, мы не можем просто добавить колонку в конфигураторе. Нам нужно использовать метод ИзменитьРеквизиты для добавления нового реквизита формы и метод Элементы.Добавить для создания визуального поля.

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


// 1. Подготовка массива новых реквизитов
МассивРеквизитов = Новый Массив;
НазваниеКолонки = "Итог";
ТипЧисло = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));

// Добавляем описание нового реквизита в массив
// Параметры: Имя, Тип, ПутьКРодителю, Заголовок, СохраняемыеДанные
МассивРеквизитов.Добавить(Новый РеквизитФормы(НазваниеКолонки, ТипЧисло, "ТаблицаПроизводственныеПланы", "Итоговая сумма", Истина));

// 2. Выполнение тяжелой операции изменения состава реквизитов формы
ЭтаФорма.ИзменитьРеквизиты(МассивРеквизитов);

// 3. Добавление визуального элемента (поля ввода) на форму
НоваяКолонка = Элементы.Добавить(НазваниеКолонки, Тип("ПолеФормы"), Элементы.ТаблицаПроизводственныеПланы);
НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода;
НоваяКолонка.ПутьКДанным = "Объект.ТаблицаПроизводственныеПланы." + НазваниеКолонки;
НоваяКолонка.ТолькоПросмотр = Истина; // Обычно итоги не редактируются вручную

Важный нюанс: Метод ИзменитьРеквизиты является ресурсозатратным, так как вызывает полную переинициализацию контекста формы на сервере. Если вам нужно добавить несколько колонок (например, 12 месяцев и 1 итог), всегда собирайте их в один массив и вызывайте метод один раз в конце процедуры.

Шаг 2. Алгоритм расчета суммы по горизонтали

После создания колонки необходимо наполнить её данными. Рассмотрим ситуацию, когда у нас есть колонки, названные по формату «МесяцГод» (например, «Январь2023»), и нам нужно их просуммировать. Проанализируем универсальный способ обхода данных строки.

Вместо того чтобы жестко прописывать имена колонок, лучше использовать коллекцию Колонки самой таблицы значений или заранее подготовленный список имен числовых показателей.


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

Шаг 3. Интерактивное обновление при изменении данных

Чтобы итоговая колонка обновлялась сразу, как только пользователь ввел значение в одну из ячеек периода, необходимо назначить обработчик события ПриИзменении. Для динамических колонок это делается также программно.

Выясним, как связать программно созданный элемент с процедурой модуля:

  1. При создании динамической колонки периода используйте метод УстановитьДействие.
  2. Создайте клиентскую процедуру, которая будет вызывать пересчет.

// При создании колонок периодов:
НоваяКолонкаПериода.УстановитьДействие("ПриИзменении", "Подключаемый_ПриИзмененииДанных");

// В модуле формы:
&НаКлиенте
Процедура Подключаемый_ПриИзмененииДанных(Элемент)
    
    // Получаем текущую строку
    ТекущаяСтрока = Элементы.ТаблицаПроизводственныеПланы.ТекущиеДанные;
    Если ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Для оптимизации на клиенте можно не пересчитывать всю таблицу, 
    // а обновить только текущую строку
    Сумма = 0;
    // Предположим, имена колонок периодов хранятся в переменной-контейнере
    Для Каждого ИмяКолонки Из МассивИменПериодов Цикл
        Сумма = Сумма + ТекущаяСтрока[ИмяКолонки];
    КонецЦикла;
    
    ТекущаяСтрока.Итог = Сумма;
    
КонецПроцедуры

Шаг 4. Визуальное оформление и итоги по вертикали

Для удобства пользователя итоговую колонку часто выделяют цветом или шрифтом. Рассмотрим, как программно добавить Условное оформление для колонки «Итог».


ЭлементОформления = УсловноеОформление.Элементы.Добавить();
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("Шрифт", Новый Шрифт(,,Истина)); // Жирный
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", ЦветаСтиля.ЦветФонаИтогов);

ПолеОформления = ЭлементОформления.Поля.Элементы.Добавить();
ПолеОформления.Поле = Новый ПолеКомпоновкиДанных("ТаблицаПроизводственныеПланыИтог");

Также не забудьте про «Подвал» таблицы. Если вам нужно видеть общую сумму по всем строкам внизу колонки «Итог», установите следующие свойства:

Рекомендации по оптимизации

Проанализируем несколько советов, которые помогут избежать ошибок при работе с большими объемами данных в динамических ТЗ:

  1. Кэширование имен колонок: Чтобы каждый раз не перебирать коллекцию Колонки в поисках числовых полей, сохраните список имен колонок-слагаемых в переменную формы или скрытый реквизит при их создании.
  2. Минимизация серверных вызовов: Если расчет суммы не требует сложных бизнес-правил из модулей менеджеров, выполняйте его &НаКлиенте. Это сделает интерфейс мгновенным.
  3. Типизация: Всегда явно указывайте ОписаниеТипов("Число") при создании реквизитов. Если тип будет неопределенным, при попытке сложения программа выдаст ошибку преобразования типов.

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

← На главную