К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как программно добавить колонку в дерево значений 1С

Как программно добавить колонку в дерево значений 1С: Колонки.Добавить(), типизация, заполнение данными, реквизит формы. Примеры кода и типичные ошибки.

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

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

Ниже разобраны синтаксис метода, типизация колонок, перенос колонок из таблицы значений и запроса, добавление колонки в реквизит формы и типичные ошибки, из-за которых код падает или колонка не отображается на форме.

Синтаксис метода Колонки.Добавить()

Базовый вызов выглядит так: Дерево.Колонки.Добавить(Имя, ОписаниеТипа, Заголовок, Ширина). Все параметры, кроме первого, необязательны, но на практике тип лучше указывать всегда — иначе колонка получит произвольный тип, что усложнит сортировку, итоги и вывод на форму.

Дерево = Новый ДеревоЗначений;

Дерево.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"), "Номенклатура");

Дерево.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)), "Кол-во");

Дерево.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)), "Сумма");

Параметр Имя — строка без пробелов и спецсимволов, по ней колонка будет доступна в коде: СтрокаДерева.Номенклатура. Параметр Заголовок — текст, который увидит пользователь в шапке табличного поля; если его не задать, выведется имя колонки. Ширина задаётся в символах и влияет только на отображение.

Метод возвращает объект КолонкаДереваЗначений, у которого можно дополнительно настроить свойства, например ТипЗначения уже после создания. Но проще передать корректное описание типов сразу при добавлении.

Как задать тип колонки через ОписаниеТипов

Типизация колонки определяет, какие значения можно в неё записывать и как платформа будет их сравнивать и отображать. Простейший вариант — один тип: Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(150)). Квалификаторы ограничивают длину строки, точность числа или состав даты.

Для составного типа типы перечисляются через запятую: Новый ОписаниеТипов("СправочникСсылка.Номенклатура,СправочникСсылка.Контрагенты"). Это полезно для универсальных колонок вроде «Объект» или «Владелец», куда могут попадать ссылки разных видов.

Типичная ошибка — оставить колонку без типа и потом пытаться свернуть дерево или построить по ней итоги. Смешанные значения в нетипизированной колонке приводят к ошибкам сравнения при сортировке и к неожиданным результатам агрегатных функций.

Добавление колонок из таблицы значений или запроса

Часто дерево строится на основе результата запроса, и колонки нужно перенести автоматически, не описывая каждую вручную. Удобный приём — перебрать коллекцию колонок источника и добавить их в дерево с сохранением типов.

РезультатЗапроса = Запрос.Выполнить().Выгрузить();

Дерево = Новый ДеревоЗначений;

Для Каждого Колонка Из РезультатЗапроса.Колонки Цикл

Дерево.Колонки.Добавить(Колонка.Имя, Колонка.ТипЗначения, Колонка.Заголовок);

КонецЦикла;

Если запрос возвращает иерархию (например, с итогами по группам), вместо Выгрузить() используйте Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией) — тогда результат сразу будет деревом значений с готовыми колонками, и добавлять их вручную не потребуется.

При переносе колонок из чужой таблицы проверяйте, что имена не конфликтуют с уже существующими. Если дерево частично заполнено заранее, добавляйте только недостающие колонки через проверку Найти().

Если нужно скопировать структуру дерева целиком без данных, используйте Дерево.Скопировать() с отбором, который ничего не вернёт, или создайте новое дерево и скопируйте колонки циклом. Метода «скопировать только колонки» в платформе нет.
ПЗ
Практическое замечание

Программное добавление колонки в реквизит формы типа «ДеревоЗначений»

Отдельный сценарий — колонка нужна в дереве, которое является реквизитом управляемой формы. Напрямую вызвать РеквизитФормы.Колонки.Добавить() нельзя: реквизиты формы изменяются только через метод ИзменитьРеквизиты() в серверном контексте.

МассивДобавляемых = Новый Массив;

НовыйРеквизит = Новый РеквизитФормы("НоваяКолонка",

Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)),

"ДеревоДанных", "Новая колонка", Ложь);

МассивДобавляемых.Добавить(НовыйРеквизит);

ИзменитьРеквизиты(МассивДобавляемых);

Третий параметр конструктора РеквизитФормы — путь к родительскому реквизиту, то есть имя дерева значений на форме. После ИзменитьРеквизиты() колонка появится в данных, но элемент формы (колонку таблицы) нужно создать отдельно через Элементы.Добавить() с типом ПолеФормы, иначе пользователь её не увидит.

Метод ИзменитьРеквизиты() доступен только на сервере и только до вывода формы пользователю либо при программной обработке. Изменение состава реквизитов — относительно «тяжёлая» операция, поэтому динамические колонки стоит добавлять пакетно, одним вызовом.

Порядок действий для реквизита формы
  1. 1
    Определите имя дерева-реквизита формы, куда добавляется колонка
  2. 2
    Сформируйте массив объектов РеквизитФормы с именем, типом, путём и заголовком
  3. 3
    Вызовите ИзменитьРеквизиты(МассивДобавляемых) в серверной процедуре
  4. 4
    Создайте элемент формы ПолеФормы, привяжите его к новому пути данных
  5. 5
    Проверьте отображение: колонка видна в таблице и принимает значения

Заполнение новой колонки данными

После добавления колонка существует, но все ячейки пусты. Заполнение выполняется обходом строк дерева. Для плоского перебора всех уровней используется рекурсивная процедура или метод Строки.НайтиСтроки(), если нужны конкретные узлы.

Процедура ЗаполнитьКолонку(Строки)

Для Каждого Строка Из Строки Цикл

Строка.НоваяКолонка = Строка.Количество * Строка.Цена;

ЗаполнитьКолонку(Строка.Строки);

КонецЦикла;

КонецПроцедуры;

Если колонка добавлена с типом, значения, не подходящие под описание типов, будут приведены или вызовут ошибку при строгой проверке. Например, запись строки в числовую колонку даст неявное преобразование только для корректных строковых представлений чисел.

Для больших деревьев избегайте в цикле обращений к СУБД — запросы внутри рекурсивного обхода резко снижают производительность. Выгрузите нужные данные одним запросом заранее и соотносите их со строками по ключу.

Проверка результата и контрольные точки

После добавления колонки проверьте несколько вещей: колонка присутствует в коллекции, тип соответствует ожиданию, данные записываются и отображаются. Быстрая проверка в коде — через Дерево.Колонки.Найти("ИмяКолонки"): метод вернёт объект колонки или Неопределено.

Для реквизита формы дополнительно убедитесь, что создан элемент таблицы и его ПутьКДанным указывает на новую колонку. Отсутствие элемента — самая частая причина «колонка добавилась, но её не видно».

Контрольные точки

Как проверить результат

Наличие колонки
Норма

Колонки.Найти() возвращает объект с нужным именем и типом

Тревожный признак

Метод возвращает Неопределено — колонка не добавлена или имя с опечаткой

Отображение на форме
Норма

Колонка видна в таблице, значения выводятся

Тревожный признак

Колонки нет — не создан элемент формы или неверный ПутьКДанным

Запись значений
Норма

Значения сохраняются и читаются обратно без преобразований

Тревожный признак

Значения обрезаются или сбрасываются — неверные квалификаторы типа

Типичные ошибки и их последствия

Большинство проблем при программном добавлении колонок связано с несколькими повторяющимися причинами. Их знание экономит время отладки.

Типичные ошибки
01
Добавление колонки с существующим именем — исключение и остановка кода; проверяйте через Найти()
02
Попытка вызвать Колонки.Добавить() у реквизита формы — ошибка; нужен ИзменитьРеквизиты()
03
Колонка добавлена в данные, но элемент формы не создан — пользователь её не видит
04
Колонка без типа — ошибки сортировки, итогов и сравнения при смешанных значениях
05
Имя колонки с пробелом или кириллическим спецсимволом — недоступность через точку в коде

Ещё одна ошибка — добавление колонок после того, как дерево уже передано в элемент формы, без обновления отображения. Обычно для реквизитов формы платформа справляется сама, но при сложных динамических сценариях может потребоваться пересоздание связи элемента с данными.

FAQ

Можно ли добавить колонку в середину списка, а не в конец?

Да, у коллекции колонок есть метод Вставить(Индекс, ...), который добавляет колонку в указанную позицию. Для реквизита формы порядок реквизитов задаётся массивом в ИзменитьРеквизиты, а порядок отображения — расположением элементов формы.

Как удалить программно добавленную колонку?

Используйте Дерево.Колонки.Удалить(Колонка) или Удалить(Индекс). Для реквизита формы удаление выполняется тем же ИзменитьРеквизиты(), но массив удаляемых имён передаётся вторым параметром.

Почему значения в новой колонке обрезаются?

Причина почти всегда в квалификаторах типа: например, КвалификаторыСтроки(10) обрежет более длинные строки, а КвалификаторыЧисла(10, 0) отбросит дробную часть. Пересоздайте колонку с подходящими квалификаторами — изменить тип существующей колонки можно через свойство ТипЗначения, но данные при этом могут быть преобразованы.

Можно ли добавить колонку с типом «ТаблицаЗначений» или «ДеревоЗначений»?

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

Чем добавление колонки в дерево отличается от таблицы значений?

Синтаксис идентичен: Колонки.Добавить() работает одинаково для обеих коллекций. Различие в данных: у дерева каждая строка имеет коллекцию подчинённых строк и свойства Родитель и Уровень(), поэтому обход и заполнение обычно рекурсивные.

Нужно ли добавлять колонку заново при каждом открытии формы?

Да, если колонка создаётся программно: состав реквизитов, описанный кодом, не сохраняется между сеансами работы формы. Разместите добавление в обработчике ПриСозданииНаСервере, чтобы структура восстанавливалась при каждом открытии.

Итог

Что важно запомнить

Колонка добавляется методом Дерево.Колонки.Добавить(Имя, ОписаниеТипов, Заголовок, Ширина). Всегда задавайте тип и проверяйте дубли имён через Найти(). Для реквизита управляемой формы используйте ИзменитьРеквизиты() на сервере и отдельно создавайте элемент формы, иначе колонка останется невидимой.