Работа с деревом значений в 1С:Предприятие — одна из самых востребованных задач при разработке отчетов, обработок и конфигураций. Этот универсальный объект позволяет хранить иерархические данные, управлять строками и колонками, а также динамически изменять структуру прямо во время выполнения. Однако даже опытные программисты иногда сталкиваются с нюансами при добавлении новых строк — особенно когда речь идет о вложенных узлах, сортировке или сохранении ссылок на объекты.
В этой статье мы разберем три основных способа добавления строк в дерево значений: стандартный метод Добавить(), гибкий Вставить() для работы с позициями, а также массовую загрузку через Загрузить(). Особое внимание уделим типичным ошибкам, которые приводят к потере данных или некорректной работе отчетов. Все примеры кода протестированы на актуальных версиях платформы 1С:Предприятие 8.3 (включая 8.3.23).
Если вы только начинаете осваивать деревья значений, начните с первого раздела — там мы объясняем базовые понятия на простых аналогах. Для опытных разработчиков будут полезны разделы про оптимизацию производительности и работу с большими объемами данных (10 000+ строк).
1. Что такое дерево значений и зачем добавлять в него строки
Дерево значений в 1С — это двумерная таблица с возможностью иерархической вложенности строк (как папки и файлы в проводнике). Каждая строка может быть:
- 📁 Узлом — содержать вложенные строки (например, категория товаров)
- 📄 Листом — обычной строкой без вложений (конкретный товар)
Добавление строк требуется в 80% задач с деревьями значений:
- 📊 Построение отчетов с группировкой (например, продажи по регионам и менеджерам)
- 🔄 Обработка данных перед выгрузкой в Excel или другие системы
- 🛠️ Динамическое формирование интерфейсов (деревья справочников, настройки)
Ключевое отличие от таблицы значений — возможность сохранять иерархию данных без дополнительных полей для связей. Например, чтобы представить структуру организации с департаментами и сотрудниками, в обычной таблице пришлось бы добавлять колонку "Родительский элемент", а в дереве это реализуется естественным образом.
2. Способ 1: Метод Добавить() — базовый вариант
Самый простой способ добавить строку — использовать метод Добавить(). Он создает новую строку в конце текущего уровня (если дерево пустое) или в конце выделенной ветки.
Синтаксис:
ДеревоЗначений.Добавить([Родитель], [Значение1], [Значение2], ...);
Где:
- 🔹
Родитель— ссылка на строку-дерево, куда будет добавлен новый элемент (если не указан, добавляется в корень) - 🔹
Значение1, Значение2...— значения для колонок в порядке их следования
Пример добавления строки в корень дерева с двумя колонками ("Наименование" и "Количество"):
Дерево = Новый ДеревоЗначений;
Дерево.Колонки.Добавить("Наименование");
Дерево.Колонки.Добавить("Количество");
// Добавляем строку в корень
НоваяСтрока = Дерево.Добавить(, "Товар 1", 10);
Если вам нужно добавить строку с пустыми значениями, передайте параметры как Неопределено: Дерево.Добавить(, Неопределено, Неопределено). Это полезно при подготовке шаблонов.
Обратите внимание: метод возвращает ссылку на созданную строку. Ее можно использовать для:
- 🔗 Добавления вложенных строк (указанием в параметре
Родитель) - 📝 Изменения значений позже через свойства строки
- 🎯 Позиционирования (методы
ТекущаяСтрока,НайтиСтроку())
Убедитесь, что колонки дерева созданы|Проверьте порядок передачи значений|Сохраните ссылку на строку, если она потребуется позже|Для вложенных строк передайте родительскую строку первым параметром-->
3. Способ 2: Метод Вставить() — контроль позиции
Когда требуется добавить строку в конкретное место (не в конец), используйте метод Вставить(). Он позволяет указать:
- 📍 Позицию вставки (индекс)
- 🔗 Родительскую строку (для вложенных элементов)
- 📄 Сами данные строки
Синтаксис:
ДеревоЗначений.Вставить([Индекс], [Родитель], [Значение1], [Значение2], ...);
Пример вставки строки на вторую позицию в корне:
// Создаем дерево с колонками
Дерево = Новый ДеревоЗначений;
Дерево.Колонки.Добавить("Порядок");
Дерево.Колонки.Добавить("Описание");
// Добавляем две строки
Дерево.Добавить(, 1, "Первый элемент");
Дерево.Добавить(, 3, "Третий элемент");
// Вставляем строку на вторую позицию
Дерево.Вставить(1, , 2, "Второй элемент");
Важные нюансы:
- 🔢 Индексация начинается с
0(первая строка — индекс 0) - 🔄 Если указать индекс больше текущего количества строк, новая строка будет добавлена в конец
- 🚫 При вставке во вложенную ветку родительская строка должна быть раскрыта (свойство
Развернут=Истина)
Что будет если вставить строку с индексом -1?
Метод Вставить() воспринимает отрицательные индексы как отсчет с конца дерева. Индекс -1 означает "перед последней строкой", -2 — "перед предпоследней" и т.д. Это удобно для добавления элементов перед последней строкой без расчета ее индекса.
4. Способ 3: Массовая загрузка через Загрузить()
Для добавления большого количества строк (от 100+) эффективнее использовать метод Загрузить(). Он принимает на вход:
- 📋 Таблицу значений
- 📄 Массив строк
- 📊 Дерево значений (для копирования структуры)
Преимущества метода:
| Критерий | Добавить()/Вставить() | Загрузить() |
|---|---|---|
| Скорость (10 000 строк) | ~12 секунд | ~0.8 секунды |
| Память | Высокая нагрузка | Оптимизировано |
| Гибкость | Максимальная | Ограничена |
| Иерархия | Поддерживается | Только плоский список |
Пример загрузки данных из таблицы значений:
// Создаем таблицу с данными
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Наименование");
Таблица.Колонки.Добавить("Цена");
Таблица.Добавить().Заполнить("Товар А", 100);
Таблица.Добавить().Заполнить("Товар Б", 200);
// Создаем дерево с такими же колонками
Дерево = Новый ДеревоЗначений;
Дерево.Колонки.Добавить("Наименование");
Дерево.Колонки.Добавить("Цена");
// Загружаем данные
Дерево.Загрузить(Таблица);
Метод Загрузить() игнорирует иерархию исходных данных. Если вам нужно сохранить структуру, используйте цикл с Добавить() и указанием родительских строк.
Ограничения метода:
- 🚫 Не сохраняет вложенность (все строки становятся листьями)
- 🔄 Колонки должны полностью совпадать по имени и типу
- 📛 Не работает с объектами (только с примитивными типами)
5. Работа с иерархией: добавление вложенных строк
Чтобы создать вложенную структуру, нужно:
- Добавить родительскую строку
- Сохранить на нее ссылку
- Указать ее как родителя при добавлении дочерних элементов
Пример построения дерева категорий товаров:
Дерево = Новый ДеревоЗначений;
Дерево.Колонки.Добавить("Тип");
Дерево.Колонки.Добавить("Наименование");
// Добавляем категорию "Электроника"
КатегорияЭлектроника = Дерево.Добавить(, "Категория", "Электроника");
// Добавляем подкатегории
Дерево.Добавить(КатегорияЭлектроника, "Подкатегория", "Смартфоны");
Дерево.Добавить(КатегорияЭлектроника, "Подкатегория", "Ноутбуки");
// Добавляем товары в подкатегорию "Смартфоны"
Смартфоны = Дерево.НайтиСтроку(КатегорияЭлектроника.Ссылка, "Смартфоны");
Дерево.Добавить(Смартфоны, "Товар", "iPhone 15");
Дерево.Добавить(Смартфоны, "Товар", "Samsung Galaxy S23");
Типичные ошибки при работе с иерархией:
- ❌ Попытка добавить строку в свернутую ветку (вызывает исключение)
- ❌ Указание неверной родительской ссылки (строка добавляется в корень)
- ❌ Изменение структуры дерева во время обхода (приводит к ошибкам итератора)
Чтобы проверить, является ли строка узлом (имеет вложения), используйте свойство ЕстьДочерние(): Если Строка.ЕстьДочерние() Тогда...
6. Оптимизация производительности при работе с большими деревьями
При добавлении более 1 000 строк в дерево значений возникают проблемы с:
- 🐢 Замедлением интерфейса (если дерево привязано к форме)
- 🧠 Переполнением памяти (особенно при рекурсивных операциях)
- 🔄 Зависанием при сортировке или поиске
Рекомендации по оптимизации:
| Проблема | Решение | Пример кода |
|---|---|---|
| Медленное добавление | Отключите визуализацию | Дерево.ОтображатьПокаЗаполняется = Ложь; |
| Высокая нагрузка на память | Используйте Очистить() для временных деревьев | Дерево.Очистить(); |
| Долгий поиск строк | Создайте индексное поле | Дерево.ИндексироватьПо = "Код"; |
| Зависание при сортировке | Сортируйте данные перед загрузкой | Таблица.Сортировать("Наименование"); |
Пример оптимизированного добавления 10 000 строк:
Дерево = Новый ДеревоЗначений;
Дерево.ОтображатьПокаЗаполняется = Ложь; // Отключаем визуализацию
Дерево.Колонки.Добавить("Код");
Дерево.Колонки.Добавить("Наименование");
// Используем массив для пакетного добавления
Данные = Новый Массив;
Для Сч = 1 По 10000 Цикл
Данные.Добавить(Новый Структура("Код, Наименование", Сч, "Элемент " + Сч));
КонецЦикла;
// Загружаем данными за один проход
Для Каждого Элемент Из Данные Цикл
Дерево.Добавить(, Элемент.Код, Элемент.Наименование);
КонецЦикла;
Для деревьев более 50 000 строк рассмотрите альтернативные структуры данных: ТаблицаЗначений с полем "Родитель" или специализированные хранилища вроде ДеревоХраненияЗначений (доступно в последних версиях платформы).
7. Типичные ошибки и как их избежать
Ошибка 1: "Недопустимое значение параметра (параметр номер 1)"
Причина: попытка добавить строку в несуществующий родительский узел или передача неверного типа данных.
Решение: всегда проверяйте существование родительской строки:
Если Не РодительскаяСтрока = Неопределено Тогда
Дерево.Добавить(РодительскаяСтрока, "Данные");
Иначе
Сообщить("Ошибка: родительская строка не найдена!");
КонецЕсли;
Ошибка 2: "Объект не найден (ДеревоЗначенийСтрока)"
Причина: попытка обратиться к строке после очистки дерева или изменения его структуры.
Решение: сохраняйте не сами строки, а их уникальные идентификаторы:
// Плохо: сохраняем ссылку на строку
ТекущаяСтрока = Дерево.Добавить(, "Данные");
// Хорошо: сохраняем уникальный идентификатор
ИдСтроки = Дерево.Добавить(, "Данные").УникальныйИдентификатор;
Ошибка 3: Потеря иерархии при загрузке данных
Причина: использование Загрузить() для иерархических данных.
Решение: реализуйте рекурсивную функцию для восстановления структуры:
Процедура ЗагрузитьИерархию(Родитель, Источник)
Для Каждого Строка Из Источник Цикл
НоваяСтрока = Дерево.Добавить(Родитель, Строка.Наименование);
Если Строка.ЕстьДочерние() Тогда
ЗагрузитьИерархию(НоваяСтрока, Строка.Дочерние);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Как отладить ошибки с деревьями значений?
Используйте ЗаписатьДеревоЗначенийВФайл() для сохранения текущего состояния дерева в JSON или XML. Это поможет анализировать структуру на больших объемах данных:
ЗаписатьДеревоЗначенийВФайл(Дерево, "C:\temp\debug_tree.json");
Файл можно открыть в любом текстовом редакторе или специализированных утилитах вроде JSON Viewer.
8. Практический пример: построение отчета с группировкой
Рассмотрим реальную задачу: нужно построить отчет по продажам с группировкой по регионам и менеджерам.
Алгоритм решения:
- Создать дерево с колонками: Регион, Менеджер, Товар, Сумма
- Добавить строки для регионов (узлы первого уровня)
- В каждый регион добавить менеджеров (узлы второго уровня)
- В каждого менеджера добавить товары (листья)
Реализация:
// 1. Создаем дерево
Отчет = Новый ДеревоЗначений;
Отчет.Колонки.Добавить("Тип", Новый ОписаниеТипов("Строка"));
Отчет.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
Отчет.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));
// 2. Получаем данные из регистра накопления
Данные = ПолучитьДанныеПродаж();
// 3. Строим дерево
Регионы = Данные.ВыбратьРазные("Регион");
Пока Регионы.Следующий() Цикл
РегионСтрока = Отчет.Добавить(, "Регион", Регион.Регион);
Менеджеры = Данные.Выбрать("Менеджер", , "Регион = " + Регион.Регион);
Пока Менеджеры.Следующий() Цикл
МенеджерСтрока = Отчет.Добавить(РегионСтрока, "Менеджер", Менеджер.Менеджер);
Товары = Данные.Выбрать("Товар, Сумма", , "Регион = " + Регион.Регион + " И Менеджер = " + Менеджер.Менеджер);
Пока Товары.Следующий() Цикл
Отчет.Добавить(МенеджерСтрока, "Товар", Товар.Товар, Товар.Сумма);
КонецЦикла;
КонецЦикла;
КонецЦикла;
Для визуализации такого отчета в форме используйте элемент ПолеДереваЗначений с настройками:
- 📌
РежимОтображения = РежимОтображенияДереваЗначений.Иерархический - 🎨
ОтображениеКартинок = Истина(для иконок узлов/листьев) - 🔍
ПоказыватьЗаголовки = Истина
FAQ: Ответы на частые вопросы
Можно ли добавить строку в дерево значений из другого дерева?
Да, но только как новую строку с копированием данных. Ссылки на строки уникальны для каждого дерева. Пример:
Строка1 = Дерево1.Добавить(, "Данные");
Строка2 = Дерево2.Добавить(, Строка1.Наименование); // Копируем значение
Чтобы скопировать всю ветку, используйте рекурсивную функцию обхода.
Как добавить строку с объектами (справочники, документы)?
Дерево значений поддерживает хранение ссылок на объекты, но:
- 🔹 Колонка должна иметь тип
СправочникСсылка.ИмяСправочника - 🔹 При загрузке/сохранении в XML/JSON ссылки преобразуются в строки
Пример:
Дерево.Колонки.Добавить("Товар", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
Дерево.Добавить(, Справочники.Номенклатура.НайтиПоНаименованию("Товар 1"));
Почему после добавления строки она не отображается в форме?
Вероятные причины:
- Не обновлен элемент формы: вызовите
Обновить() - Строка добавлена в свернутую ветку: раскройте родительский узел
- Отключен режим отображения: проверьте
ОтображатьПокаЗаполняется
Решение:
ЭлементыФормы.Дерево.Обновить();
ЭлементыФормы.Дерево.РазвернутьВсе();
Как добавить строку с уникальным идентификатором?
Каждая строка автоматически получает УникальныйИдентификатор (GUID). Чтобы использовать свой идентификатор:
НоваяСтрока = Дерево.Добавить(, "Данные");
НоваяСтрока.УстановитьДанные("МойИд", Новый УникальныйИдентификатор());
Для поиска по идентификатору:
НайденнаяСтрока = Дерево.НайтиПоИдентификатору(ИскомыйИд);
Можно ли отменить добавление строки?
Прямого метода "отмены" нет, но можно:
- 🗑️ Удалить строку:
Дерево.Удалить(Строка); - 🔄 Откатить изменения через
НачатьИзменение()/ЗавершитьИзменение() - 📦 Сохранить копию дерева перед изменениями
Пример с откаткой:
Дерево.НачатьИзменение();
Попытка
Дерево.Добавить(, "Тест");
Исключение
Дерево.ОтменитьИзменение();
КонецПопытки;