В процессе разработки отчетов или обработок на обычных формах часто возникает необходимость предоставить пользователю возможность быстро увидеть сумму значений в выделенных ячейках табличного документа, подобно тому, как это реализовано в Microsoft Excel. Несмотря на кажущуюся простоту, при реализации этой функции в 1С:Предприятие 8 (особенно на обычных формах) программисты сталкиваются с типичными ошибками обращения к объектам и производительности. Рассмотрим подробно, как правильно организовать этот процесс, разобравшись в программном коде и способах оптимизации.
В приведенном обсуждении автор столкнулся с ошибкой ПолеТабличногоДокумента не определено. Проанализируем причину. В 1С:Предприятие 8 при работе с обычными формами все элементы управления (кнопки, поля ввода, табличные документы) располагаются в коллекции ЭлементыФормы. Когда мы пишем код внутри модуля формы, мы не можем просто обратиться к полю по его имени, если оно не является реквизитом обработки или документа. Чтобы передать табличный документ в функцию общего модуля, необходимо явно указать путь к нему через коллекцию элементов.
Если ваш табличный документ на форме называется, например, Результат, то передавать его в функцию нужно следующим образом:
Процедура СуммаПриВыделении()
// Правильное обращение к элементу табличного документа на обычной форме
ТабДок = ЭлементыФормы.Результат;
// Вызов функции из общего модуля (например, ПЛ_Омега)
Сумма = ПЛ_Омега.СуммаПриВыделенииЯчеек(ТабДок);
// Вывод результата в надпись на форме или в состояние
ЭлементыФормы.НадписьСумма.Заголовок = "Сумма: " + Формат(Сумма, "ЧДЦ=2");
КонецПроцедуры
Теперь рассмотрим саму функцию, которая будет производить вычисления. Проанализируем ситуацию: пользователь может выделить одну область, несколько разрозненных ячеек или даже целые строки и колонки. Коллекция ВыделенныеОбласти содержит объекты типа ОбластьЯчеекТабличногоДокумента. Пройдемся по ним в цикле.
Важный нюанс оптимизации: В исходном коде автора использовалось обращение к ячейке через строковый адрес (например, "R1C1"). Это медленная операция. Намного эффективнее использовать метод Область(НомерСтроки, НомерКолонки), который принимает числовые координаты напрямую.
Рассмотрим доработанный и оптимизированный вариант функции для общего модуля:
Функция СуммаПриВыделенииЯчеек(ПолеТабличногоДокумента) Экспорт
Перем Сумма;
Сумма = 0;
// Перебираем все выделенные области (их может быть несколько при зажатом Ctrl)
Для Каждого Область Из ПолеТабличногоДокумента.ВыделенныеОбласти Цикл
// Проверяем, что это именно область ячеек
Если ТипЗнч(Область) = Тип("ОбластьЯчеекТабличногоДокумента") Тогда
// Проходим циклом по строкам и колонкам внутри каждой области
Для ИндексСтрока = Область.Верх По Область.Низ Цикл
Для ИндексКолонка = Область.Лево По Область.Право Цикл
// Получаем ячейку по числовым индексам
Ячейка = ПолеТабличногоДокумента.Область(ИндексСтрока, ИндексКолонка);
// Попытка преобразовать текст в число
Попытка
// Очищаем строку от пробелов и неразрывных пробелов
ТекстЯчейки = СтрЗаменить(Ячейка.Текст, " ", "");
ТекстЯчейки = СтрЗаменить(ТекстЯчейки, Символы.НПП, ""); // Обработка неразрывного пробела
Если Не ПустаяСтрока(ТекстЯчейки) Тогда
Сумма = Сумма + Число(ТекстЯчейки);
КонецЕсли;
Исключение
// Если в ячейке текст (заголовок), просто пропускаем ее
Продолжить;
КонецПопытки;
КонецЦикла;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Возврат Сумма;
КонецФункции
Проанализируем, почему обычный СтрЗаменить(Текст, " ", "") часто не срабатывает. В системе 1С при выводе чисел часто используется символ с кодом 160 — неразрывный пробел (Символы.НПП), который визуально неотличим от обычного пробела, но функцией Число() не игнорируется и вызывает исключение. Поэтому крайне важно удалять оба типа пробелов перед преобразованием.
Также стоит обратить внимание на свойство ячейки СодержитЗначение. Если ваш табличный документ строится программно и в ячейки записываются именно числа, а не просто текст, можно извлекать данные напрямую через Ячейка.Значение. Это избавит от необходимости парсить строку и значительно ускорит работу.
Чтобы сумма обновлялась сразу, как только пользователь изменил выделение, нам нужно использовать событие табличного документа. Выясним, какое событие для этого подходит. В обычных формах это событие ПриАктивизацииОбласти.
Разберем по шагам настройку события:
ПриАктивизацииОбласти и нажмите на лупу, чтобы создать обработчик.Пример кода в модуле формы:
Процедура РезультатПриАктивизацииОбласти(Элемент)
// В обработчик события автоматически передается "Элемент"
// Это и есть наш табличный документ
Сумма = ПЛ_Омега.СуммаПриВыделенииЯчеек(Элемент);
// Выводим информацию в строку состояния внизу окна
Состояние("Сумма выделенных ячеек: " + Формат(Сумма, "ЧЦ=15; ЧДЦ=2"));
КонецПроцедуры
Выясним причину возможных зависаний. Если пользователь выделит всю колонку целиком (нажав на заголовок колонки), то цикл попытается обработать более миллиона строк. Это приведет к длительному зависанию программы.
Рекомендация: Введите ограничение на количество обрабатываемых ячеек. Перед запуском вложенных циклов проверьте размер области:
КоличествоЯчеек = (Область.Низ - Область.Верх + 1) * (Область.Право - Область.Лево + 1);
Если КоличествоЯчеек > 10000 Тогда
Возврат 0; // Или выдать предупреждение пользователю
КонецЕсли;
Таким образом, мы проанализировали не только синтаксическую ошибку обращения к ЭлементыФормы, но и разобрали способы сделать код надежным, быстрым и удобным для конечного пользователя.