Как ускорить сворачивание и развертывание дерева значений в обычных формах 1С

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При работе с большими деревьями значений в обычных формах 1С (например, в УТ 10.3) разработчики часто сталкиваются с критическим падением производительности при программном сворачивании или развертывании всех узлов. Основная проблема заключается в том, что при каждом вызове метода Свернуть() или Развернуть() платформа инициирует обновление графического интерфейса. Это приводит к многократному вызову тяжелых обработчиков событий, таких как ПриВыводеСтроки и ПриПолученииДанных. Если в этих процедурах выполняются расчеты или запросы, процесс может затянуться на минуты.

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

Метод 1. Использование флага блокировки обработчиков

Проанализируем самую частую причину тормозов. Когда мы в цикле обходим строки дерева и сворачиваем их, 1С пытается перерисовать форму после каждой операции. Если у нас 1000 строк, обработчик ПриВыводеСтроки может быть вызван тысячи раз. Самый простой и эффективный способ — временно «отключить» логику внутри этих событий.

Для этого в модуле формы создадим переменную-флаг. Рассмотрим пример реализации:


Перем ЭтоМассовоеДействие;

Процедура КоманднаяПанельСвернутьВсе(Кнопка)
    ЭтоМассовоеДействие = Истина; // Включаем блокировку
    
    // Выполняем действия с деревом
    Для Каждого СтрокаВерхнегоУровня Из ДеревоТоваров.Строки Цикл
        ЭлементыФормы.ДеревоТоваров.Свернуть(СтрокаВерхнегоУровня, Истина);
    КонецЦикла;
    
    ЭтоМассовоеДействие = Ложь; // Выключаем блокировку
    
    // Принудительно обновляем форму один раз в конце
    ЭлементыФормы.ДеревоТоваров.ОбновитьСтроки();
КонецПроцедуры

Теперь нам необходимо изменить обработчики событий дерева. Выясним, как это повлияет на скорость:


Процедура ДеревоТоваровПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    Если ЭтоМассовоеДействие = Истина Тогда
        Возврат; // Ничего не считаем и не оформляем, пока идет цикл
    КонецЕсли;
    
    // Ваша обычная логика оформления (цвета, шрифты, вычисления)
    ОформлениеСтроки.Ячейки.Остаток.УстановитьТекст(ДанныеСтроки.Остаток);
КонецПроцедуры

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

Метод 2. Встроенный параметр рекурсии в методах Свернуть и Развернуть

Часто программисты пишут собственные рекурсивные функции для обхода всех уровней дерева. Однако платформа 1С на уровне встроенного языка уже имеет оптимизированный механизм. Разберем синтаксис методов Свернуть() и Развернуть():

ЭлементыФормы.ИмяЭлемента.Свернуть(Строка, Рекурсивно)

Если во второй параметр передать Истина, платформа выполнит операцию для всех дочерних узлов на уровне собственного кода (C++), что работает значительно быстрее, чем цикл на языке 1С. Посмотрим на оптимизированный код развертывания:


Для Каждого Строка Из ДеревоТоваров.Строки Цикл
    ЭлементыФормы.ДеревоТоваров.Развернуть(Строка, Истина);
КонецЦикла;

Метод 3. Быстрая смена режима отображения (самый эффективный метод)

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

Выполним следующие шаги в коде:

  1. Отключим видимость элемента управления, чтобы избежать мерцания.
  2. Переключим свойство Отображение в значение Список.
  3. Программно свернем или развернем нужные строки.
  4. Вернем режим отображения Дерево.
  5. Включим видимость обратно.

ЭлементДерево = ЭлементыФормы.ДеревоТоваров;
ЭлементДерево.Видимость = Ложь;

// Устанавливаем режим списка, это отключает отрисовку веток дерева
ЭлементДерево.Отображение = ОтображениеТаблицы.Список;

Для Каждого ТекущаяСтрока Из ДеревоТоваров.Строки Цикл
    ЭлементДерево.Свернуть(ТекущаяСтрока, Истина);
КонецЦикла;

// Возвращаем исходный вид
ЭлементДерево.Отображение = ОтображениеТаблицы.Дерево;
ЭлементДерево.Видимость = Истина;

Этот метод показывает лучшие результаты на деревьях, содержащих более 5-10 тысяч строк. Платформа перерисовывает дерево целиком только один раз в момент включения видимости.

Метод 4. Использование системных горячих клавиш (SendKeys)

В обычных формах 1С предусмотрены стандартные сочетания клавиш для управления деревьями, которые работают на уровне системных событий Windows. Проанализируем их:

Мы можем имитировать нажатие этих клавиш программно через объект WScript.Shell. Это заставляет платформу использовать свой внутренний высокопроизводительный механизм сворачивания.


Процедура РазвернутьВсеДеревоЧерезКлавиши()
    ЭлементыФормы.ДеревоТоваров.УстановитьФокус();
    Shell = Новый COMОбъект("WScript.Shell");
    // Имитируем нажатие Ctrl+Shift+Num+
    // Плюс в SendKeys экранируется фигурными скобками
    Shell.SendKeys("^+{ADD}"); 
КонецПроцедуры

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

Рекомендации по оптимизации обработчиков событий

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

Подводя итог, можно сказать: для небольших деревьев достаточно использовать флаг блокировки в ПриВыводеСтроки, а для сложных и объемных структур лучшим решением будет временная смена режима Отображение на Список в сочетании с рекурсивными методами платформы.

← На главную