Как рассчитать сумму выделенных ячеек в табличном документе на обычных формах

Программист 1С v8.3 (Обычные формы)
← На главную

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

Разбор основной проблемы: обращение к элементам формы

В приведенном обсуждении автор столкнулся с ошибкой ПолеТабличногоДокумента не определено. Проанализируем причину. В 1С:Предприятие 8 при работе с обычными формами все элементы управления (кнопки, поля ввода, табличные документы) располагаются в коллекции ЭлементыФормы. Когда мы пишем код внутри модуля формы, мы не можем просто обратиться к полю по его имени, если оно не является реквизитом обработки или документа. Чтобы передать табличный документ в функцию общего модуля, необходимо явно указать путь к нему через коллекцию элементов.

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


Процедура СуммаПриВыделении()  
    // Правильное обращение к элементу табличного документа на обычной форме
    ТабДок = ЭлементыФормы.Результат;
    
    // Вызов функции из общего модуля (например, ПЛ_Омега)
    Сумма = ПЛ_Омега.СуммаПриВыделенииЯчеек(ТабДок);
    
    // Вывод результата в надпись на форме или в состояние
    ЭлементыФормы.НадписьСумма.Заголовок = "Сумма: " + Формат(Сумма, "ЧДЦ=2");
КонецПроцедуры

Реализация функции подсчета в общем модуле

Теперь рассмотрим саму функцию, которая будет производить вычисления. Проанализируем ситуацию: пользователь может выделить одну область, несколько разрозненных ячеек или даже целые строки и колонки. Коллекция ВыделенныеОбласти содержит объекты типа ОбластьЯчеекТабличногоДокумента. Пройдемся по ним в цикле.

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

Рассмотрим доработанный и оптимизированный вариант функции для общего модуля:


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

Обработка специфических символов и форматирования

Проанализируем, почему обычный СтрЗаменить(Текст, " ", "") часто не срабатывает. В системе 1С при выводе чисел часто используется символ с кодом 160 — неразрывный пробел (Символы.НПП), который визуально неотличим от обычного пробела, но функцией Число() не игнорируется и вызывает исключение. Поэтому крайне важно удалять оба типа пробелов перед преобразованием.

Также стоит обратить внимание на свойство ячейки СодержитЗначение. Если ваш табличный документ строится программно и в ячейки записываются именно числа, а не просто текст, можно извлекать данные напрямую через Ячейка.Значение. Это избавит от необходимости парсить строку и значительно ускорит работу.

Как сделать расчет динамическим?

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

Разберем по шагам настройку события:

  1. Откройте форму с табличным документом в конфигураторе.
  2. Выберите элемент управления (табличное поле) и откройте его свойства.
  3. Найдите событие ПриАктивизацииОбласти и нажмите на лупу, чтобы создать обработчик.
  4. В созданном обработчике вызовите вашу процедуру расчета.

Пример кода в модуле формы:


Процедура РезультатПриАктивизацииОбласти(Элемент)
    // В обработчик события автоматически передается "Элемент" 
    // Это и есть наш табличный документ
    Сумма = ПЛ_Омега.СуммаПриВыделенииЯчеек(Элемент);
    
    // Выводим информацию в строку состояния внизу окна
    Состояние("Сумма выделенных ячеек: " + Формат(Сумма, "ЧЦ=15; ЧДЦ=2"));
КонецПроцедуры

Меры предосторожности при больших объемах данных

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

Рекомендация: Введите ограничение на количество обрабатываемых ячеек. Перед запуском вложенных циклов проверьте размер области:


КоличествоЯчеек = (Область.Низ - Область.Верх + 1) * (Область.Право - Область.Лево + 1);
Если КоличествоЯчеек > 10000 Тогда
    Возврат 0; // Или выдать предупреждение пользователю
КонецЕсли;

Таким образом, мы проанализировали не только синтаксическую ошибку обращения к ЭлементыФормы, но и разобрали способы сделать код надежным, быстрым и удобным для конечного пользователя.

← На главную