Дерево значений 1с при изменении

Дерево значений 1с. Описание и примеры использования

ДеревоЗначений — это программный объект встроенного языка, позволяющий строить произвольные иерархические наборы данных в памяти компьютера, отображать их в табличном и\или древовидном виде, а также программно и интерактивно манипулировать ими (добавлять, редактировать, удалять и сортировать строки).

Как и таблица значений, дерево состоит из строк и колонок. Строки располагаются вниз по вертикали, а колонки — вправо по горизонтали. Однако, в отличие от таблицы значений, строки дерева значений могут иметь подчиненные строки любой глубины вложенности.

Строки и колонки имеют индексы, по которым к ним можно обращаться напрямую (начинаются с 0). Кроме этого, к колонкам можно обращаться по идентификатору.

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

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

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

Создание дерева значений

Как и большинство объектов встроенного языка, новая дерево значений может быть создано с помощью оператора Новый :

Свойства и методы дерева значений

Имя Тип Описание
Свойства
Колонки КоллекцияКолонокДереваЗначений содержит коллекцию колонок дерева значений
Строки КоллекцияСтрокДереваЗначений содержит коллекцию корневых строк дерева значений
Методы
ВыбратьСтроку() СтрокаДереваЗначений открывает диалог для интерактивного выбора строки дерева значений
Скопировать() ДеревоЗначений создает новый объект копированием текущего (копируются все колонки и строки)

Колонки дерева значений

Прежде чем начать работу с деревом значений, необходимо создать структуру колонок. Каждая колонка характеризуется следующими свойствами:

Имя Тип Описание
Имя Строка символьный идентификатор колонки, по которому к ней можно обращаться из кода. Может содержать только алфавитные символы, цифры и знаки подчеркивания. Причем, начинаться имя колонки может только с буквы или символа подчеркивания
Заголовок Строка строковое представление колонки на форме. Может содержать произвольные символы
ТипЗначения ОписаниеТипов тип значения содержимого ячеек в этой колонке. Свойство ограничивает пространство доступных значений, которые можно указать в данной колонке
Ширина Число ширина колонки на форме (выражается в количестве символов)
Читайте также:  Hatsan 125 приклад дерево

Доступ к колонкам производится через свойство Колонки объекта ДеревоЗначений . Для добавления новой колонки используется метод Колонки.Добавить():

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

Для того, чтобы определить наличие колонки с нужным именем используется метод Колонки.Найти():

найдКолонка = дз.Колонки.Найти("Наименование"); Если найдКолонка = Неопределено Тогда Сообщить("Колонка не найдена!"); Иначе Сообщить("Индекс колонки color: red;">+ дз.Колонки.Индекс(найдКолонка)); КонецЕсли; 

Перебор колонок выполняется следующим образом:

Для каждого Колонка Из дз.Колонки Цикл Сообщить(Колонка.Имя + ": " + Колонка.ТипЗначения); КонецЦикла; //Результат: // Наименование: Строка // Количество: Число // Свойство: 

Для удаления колонки используется метод Колонки.Удалить():

найдКолонка = дз.Колонки.Найти("Свойство"); Если НЕ найдКолонка = Неопределено Тогда дз.Колонки.Удалить(найдКолонка); КонецЕсли; 

Методы коллекции колонок дерева значений

Вставить() Вставляет новую колонку в указанную позицию коллекции
Добавить() Добавляет новую колонку в конец коллекции
Индекс() Возвращает индекс колонки в коллекции колонок
Получить() Возвращает колонку по ее индексу
Количество() Возвращает количество колонок в коллекции
Найти() Ищет колонку в коллекции по имени
Очистить() Удаляет все колонки из коллекции
Сдвинуть() Сдвигает колонку влево или вправо
Удалить() Удаляет колонку из коллекции

Строки дерева значений

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

В отличие от таблицы значений, доступ к строкам дерева значений производится через свойство Строки объекта ДеревоЗначений или объекта СтрокаДереваЗначений . Каждая строка является узлом иерархии, поэтому обладает следующими свойствами и методами:

Имя Тип Описание
Свойства
Родитель СтрокаДереваЗначений ссылается на строку верхнего уровня. Для корневой строки имеет значение Неопределено
Строки КоллекцияСтрокДереваЗначений содержит коллекцию подчиненных строк
Методы
Владелец() ДеревоЗначений возвращает ссылку на дерево значений, которому принадлежит строка
Уровень() Число возвращает уровень вложенности строки в иерархии дерева. Для строки, не имеющей родителя, уровень будет равен 0 (верхний уровень или корневой уровень). Подчиненная ей строка будет иметь уровень 1 и т.д.

Добавление и удаление строк

Для добавления новой строки используется метод Строки.Добавить(). Метод возвращает объект СтрокаДереваЗначений , с которым доступны дальнейшие манипуляции:

СтрокаДЗ = дз.Строки.Добавить(); 

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

СтрокаДЗ.Наименование = "Стул деревянный"; СтрокаДЗ.Количество = 1; СтрокаДЗ.Свойство = ТекущаяДата(); 

Для удаления строки используется метод Строки.Удалить(). Строку можно удалить передав методу либо саму строку, либо ее индекс:

//удаление строки дз.Строки.Удалить(СтрокаДЗ); //удаление по индексу ИндексСтроки = дз.Строки.Индекс(СтрокаДЗ); дз.Строки.Удалить(ИндексСтроки); //безопасное удаление НайдСтрока = дз.Строки.Найти("Стул деревянный", "Наименование"); Если НЕ НайдСтрока = Неопределено Тогда дз.Строки.Удалить(НайдСтрока); КонецЕсли; 

Перебор строк дерева значений

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

Для Каждого СтрокаДЗ Из дз.Строки Цикл ИндСтроки = дз.Строки.Индекс(СтрокаДЗ); Сообщить("Строка[" + ИндСтроки + "]: " + СтрокаДЗ.Наименование); КонецЦикла; //в редких случаях Для ИндСтроки = 0 По дз.Строки.Количество() - 1 Цикл СтрокаДЗ = дз.Строки.Получить(ИндСтроки); Сообщить("Строка[" + ИндСтроки + "]: " + СтрокаДЗ.Наименование); КонецЦикла; 

Поиск строк

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

//удаление первой найденной строки НайдСтрока = дз.Строки.Найти("Стул деревянный", "Наименование"); Если НЕ НайдСтрока = Неопределено Тогда дз.Строки.Удалить(НайдСтрока); КонецЕсли; //удаление всех найденных строк ПараметрыПоиска = Новый Структура("Наименование", "Стул деревянный"); мНайдСтроки = дз.Строки.НайтиСтроки(ПараметрыПоиска); Для каждого НайдСтрока Из мНайдСтроки Цикл дз.Строки.Удалить(НайдСтрока); КонецЦикла; 

Поиск возможен даже среди вложенных строк. Внимательно изучите документацию к методам Строки.Найти() и Строки.НайтиСтроки().

Читайте также:  Долларовое дерево как подобрать горшок

Все методы коллекции строк дерева значений:

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

Иерархию свойств и типов значений, связанных с деревом значений, схематически можно представить в виде дерева:

Источник

Дерево значений — пересчет итогов иерархии при изменении строки

На форме отчета есть дерево значений, в которое выгрузил выборку запроса.

Как реализовать пересчет итогов?
Пока написал такой обработчик:

Процедура ДеревоРезультатаПередОкончаниемРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования, Отказ)
Если НЕ ОтменаРедактирования Тогда
ЭлементыФормы.ДеревоРезультата.ТекущиеДанные[«Изменение»] = Истина;
КонецЕсли;
КонецПроцедуры

А вот что дальше с ним делать — не пойму.

Хорошо. Построил заново.
Юзер ввёл новое значение и итоги должны пересчитаться интерактивно, после ввода нового значения.

(4) подсказываю:
1. либо пересчитывать вверх ручками вверх по иерархии
2. либо скидывать плоское тз в темпы, строить по нему итогами твое дз и выгружать обратно — если в дз не состав какой то сложной турбины )
3. можно извратить п.2 — выгружать в твое тп не все дз, а только ту ветку, итог которой нужно получить по иерархии. Но это гемор еще тот.

Читайте также:  Шаблоны осеннего дерева распечатать

(5) Ок.
Первый пункт кажется путёвым. Возникает вопрос — как отследить, что это уже другая иерархия, соответственно, нужно будет итоги пересчитать и в верхних группировках.

Чуйствую, что без рекурсии не обойтись

Процедура ДеревоПланПродажПриОкончанииРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования)
ТекСтрока = ЭлементыФормы.ДеревоПланПродаж.ТекущиеДанные;
Если ЗначениеНеЗаполнено(ТекСтрока.ТорговаяТочка) Тогда
Возврат;
КонецЕсли;

ВторойУровень = ТекСтрока.Родитель;
Для каждого Колонка Из ДеревоПланПродаж.Колонки Цикл
Если Колонка.ТипЗначения = ТипЧисло И Прав(Колонка.Имя,1)=»П» Тогда
ВторойУровень[Колонка.Имя]=ВторойУровень.Строки.Итог(Колонка);
КонецЕсли;
КонецЦикла;

Процедура ПересчитИтогиИерархически(Элемент, Строка)
ТекСтрока = ЭлементыФормы.ДеревоПланПродаж.ТекущиеДанные;
Если ЗначениеНеЗаполнено(ТекСтрока.ТорговаяТочка) Тогда
Возврат;
КонецЕсли;

ВторойУровень = ТекСтрока.Родитель;
Для каждого Колонка Из ДеревоПланПродаж.Колонки Цикл
Если Колонка.ТипЗначения = ТипЧисло И Прав(Колонка.Имя,1)=»П» Тогда
ВторойУровень[Колонка.Имя]=ВторойУровень.Строки.Итог(Колонка);
КонецЕсли;
КонецЦикла;
ПересчитИтогиИерархически(Элемент, НоваяСтрока)
КонецПроцедуры

Процедура ДеревоПланПродажПриОкончанииРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования)
ТекСтрока = ЭлементыФормы.ДеревоПланПродаж.ТекущиеДанные;
Если ЗначениеНеЗаполнено(ТекСтрока.ТорговаяТочка) Тогда
Возврат;
КонецЕсли;

ПересчитИтогиИерархически(Элемент, НоваяСтрока)
КонецПроцедуры

Всё получилось. Для тех, кто будет искать этот вопрос. Решение подсказал Павел Данилкович:

Процедура СчитатьСуммыДЗ(пСтрокиДЗ, пСуммы) Экспорт
Для Каждого лСтр Из пСтрокиДЗ Цикл
//если уровень группировок — высчитываем итог
Если лСтр.Строки.Количество() = 0 Тогда
Продолжить;
КонецЕсли;

СчитатьСуммыДЗ(лСтр.Строки, пСуммы);
Для Каждого лЗн Из пСуммы Цикл
лСтр[лЗн.Ключ] = лСтр.Строки.Итог(лЗн.Ключ);
КонецЦикла;
КонецЦикла;
КонецПроцедуры // СчитатьСуммыДЗ()

просто рекурсивно проходим все узлы, причем обходим именно узлы, а не элементы.

это условие контролирует кусочек:

//если уровень группировок — высчитываем итог
Если лСтр.Строки.Количество() = 0 Тогда
Продолжить;
КонецЕсли;

Тоесть, если выбирается элемент — у него нет строк, вот его и пропускаем. Просто передать в процедуру само дерево и соответствие колонок по которым нужно суммировать, например План и ПланируемыйРасход:

Процедура ТЗВыборкаПередОкончаниемРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования, Отказ)
соотвКолонок = Новый Соответствие;
соотвКолонок.Вставить(«План»);
соотвКолонок.Вставить(«ПланируемыйРасход»);
СчитатьСуммыДЗ(ДеревоПлан.Строки, соотвКолонок);
КонецПроцедуры

Источник

Оцените статью