Дерево значений, которое негде посмотреть
Метод "ВыбратьСтроку" остался в золотом веке толстого клиента, но необходимость окинуть одним взглядом всё дерево порой возникает. Предлагаю простое решение в виде одной функции — вывода в текстовое представление.
- Описание
- Подробнее
Описание
Да, мы все понимаем, что модальные окна это плохо, а дерево значений не живёт на клиенте и не может быть отображено, но очень хочется следить за внешним видом и наполнением наших переменных хотя бы с целью отладки. Собственно, как раз для отладки «ВыбратьСтроку» у таблицы и дерева был незаменимым методом. Но, если таблицу значений можно более-менее адекватно увидеть в отладчике, то для иерархии дерева это совсем не вариант. Отладчик показывает содержимое крайне неудобно с точки зрения «единого просмотра».
Поэтому сделаем текстовое представление. Его можно выводить в окне сообщений и оттуда копировать, его можно сохранять в файл, его можно более-менее удобно посмотреть в отладчике. Разумеется, шрифт в том месте, где смотрите, должен быть моноширинным.
Никаких особых хитростей нет, кроме разве что одного места — определения максимального количества уровней в дереве. Признаю, что сделал это не самым оптимальным образом, через сериализацию (да ещё и всего дерева, когда хватило бы одной колонки) — можно и иначе, желающие да обрящут. Вот //sale.itcity.ru/profile/28527/ наверняка придумал бы иной способ, верю.
Дизайн при желании можно отрегулировать самостоятельно, т.к. на вкус и цвет фломастеры бывают разные.
Используется вывод в текстовый документ с помощью текстового же макета:
// Выводит данные ДереваЗначений в ТекстовыйДокумент, пригодный к рассмотрению в отладчике, окне сообщений и показу.
//
// Параметры:
// рВетка — дерево значений, подлежащее выводу. Может иметь почти любую глубину иерархии, количество и тип колонок. Если хватит
// объявленных позиционных строк-заполнителей, всё поместится. Если иерархия слишком глубока, строки просто надо нарастить;
// рТекст — на входе должен быть равен Неопределено; на выходе по окончании работы содержит результатный текстовый документ;
// рПараметры — структура дополнительных настроек, допустимые ключи:
// Колонки — структура колонок, которые подлежат выводу. Если пуста или имеет тип, отличный от структуры, выводятся все колонки;
// если в ключах структуры указаны имена колонок, будут выведены только они. В значениях структуры можно передать строковое
// представление формата, согласно которому должны будут форматироваться выводимые значения. По умолчанию формата нет;
// ПоказыватьУровни — булево, управляет выводом №№ уровней (метод Уровень()), по умолчанию выключено;
// ШагОтступа — число, определяющее шаг в символах, используемый для показа псевдографики иерархии веток в дереве.
//
&НаСервереБезКонтекста
Процедура ВывестиДеревоЗначенийВТекст(Знач рВетка,рТекст,Знач рПараметры=Неопределено)
Попытка
Если рТекст=Неопределено Тогда // первая итерация, шапочный вызов исходной части
//—————————————————————————————————————————
// Разбираем входные данные
Если ТипЗнч(рВетка)<>Тип(«ДеревоЗначений») Тогда Возврат КонецЕсли;
Если ТипЗнч(рПараметры)<>Тип(«Структура») Тогда рПараметры=Новый Структура КонецЕсли;
стрКолонок=?(рПараметры.Свойство(«Колонки»),рПараметры.Колонки,Неопределено);
Если ТипЗнч(стрКолонок)<>Тип(«Структура») Тогда стрКолонок=Новый Структура КонецЕсли;
рПоказыватьУровни=?(рПараметры.Свойство(«ПоказыватьУровни»),рПараметры.ПоказыватьУровни,Ложь); // затратное дело, кстати
рШагОтступа=?(рПараметры.Свойство(«ШагОтступа»),рПараметры.ШагОтступа,2); // для отображения отступа в колонке иерархии
//—————————————————————————————————————————
// Определяем максимальное количество уровней
// Также можно получить максимальный уровень, «плоско» перебрав все строки (например, получив их через НайтиСтроки)
// и в цикле для каждой вызывая Уровень() и определяя максимум.
// Вариант через СКД и служебное поле «Уровень» ни на одной известной мне платформе не работоспособен (нехватка памяти).
//
//
//рДеревоДляТеста=КакНибудьСкопироватьДерево(рВетка);
//рДеревоДляТеста.Колонки.Вставить(0,»_Level»,Новый ОписаниеТипов(«Булево»)); // самый экономный вариант, с сохранением иерархии
//мНенужных=Новый Массив;
//Для й=1 По рДеревоДляТеста.Колонки.Количество()-1 Цикл
// мНенужных.Добавить(рДеревоДляТеста.Колонки[й]);
//КонецЦикла;
//Для каждого кол Из мНенужных Цикл
// рДеревоДляТеста.Колонки.Удалить(кол);
//КонецЦикла;
//
рДеревоДляТеста=рВетка; // пока сериализуем прямо всё дерево (неоптимально, но…)
рЗапись=Новый ЗаписьXML;
рЗапись.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(рЗапись,рДеревоДляТеста);
стро=рЗапись.Закрыть();
//
стро=СтрЗаменить(стро,«xmlns=»,«xmlns:myns1C=»); // иначе не будет работать XPath
//
рЧтение=Новый ЧтениеXML;
рЧтение.УстановитьСтроку(стро);
постр=Новый ПостроительDOM;
рДокументДОМ=постр.Прочитать(рЧтение);
рВыражение=«/ValueTree/row»; максКолвоУровней=1;
рРазыменователь=Новый РазыменовательПространствИменDOM(рДокументДОМ);
Пока Истина Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
рРезультат=рДокументДОМ.ВычислитьВыражениеXPath(рВыражение,рДокументДОМ,рРазыменователь,ТипРезультатаDOMXPath.Любой);
Если рРезультат.ПолучитьСледующий()=Неопределено Тогда Прервать КонецЕсли;
рВыражение=рВыражение+«/row»;
максКолвоУровней=максКолвоУровней+1;
КонецЦикла;
максКолвоУровней=максКолвоУровней—1; // можно и так: СтрЧислоВхождений(рВыражение,»/row»)-1;
//—————————————————————————————————————————
// готовим исходный макет вывода
строПробелы=» «;
строРазделители=«===============================================================================================»;
строОтступы=«___________________________________________________________________________________________»; // тут нужны чуть для другого
//
секШапка1=«|[_HCS»+Лев(строПробелы,максКолвоУровней*рШагОтступа)+«]|»; // HierarchyColumnShow
секГорРазделитель1=«|»+Лев(строОтступы,максКолвоУровней*рШагОтступа+6)+«|»; // здесь именно Отступы!
рШиринаКолонкиИерархии=СтрДлина(секШапка1)-2;
строПолейШапки=«#Поле _HCS
| #Выравнивание Центр»;
строПолейЗаписи=«»;
//
Если рПоказыватьУровни Тогда
секШапка1=секШапка1+«[_Level]|»;
секГорРазделитель1=секГорРазделитель1+Лев(строРазделители,8)+«|»;
строПолейШапки=строПолейШапки+«
|#Поле _Level
| #Выравнивание Центр»;
строПолейЗаписи=«#Поле _Level
| #Выравнивание Центр
| #Забивать Истина»;
КонецЕсли;
//
мИменКолонок=Новый Массив;
Для каждого кол Из рВетка.Колонки Цикл
Если стрКолонок.Количество()<>0 и не стрКолонок.Свойство(кол.Имя) Тогда Продолжить КонецЕсли; // чётко указаны конкретные колонки
рДлинаИмениКолонки=СтрДлина(кол.Имя);
рНужнаяШирина=Макс(?(кол.Ширина<3,10,кол.Ширина),рДлинаИмениКолонки);
// к сожалению, ключевое слово «#Поля» неприменимо — платформа падает — поэтому делаем всё сами
секШапка1=секШапка1+«[«+кол.Имя+Лев(строПробелы,рНужнаяШирина—рДлинаИмениКолонки)+«]|»;
секГорРазделитель1=секГорРазделитель1+Лев(строРазделители,рНужнаяШирина+1)+«=|»;
строПолейШапки=строПолейШапки+«
|#Поле «+кол.Имя+«
| #Выравнивание Центр»;
рОписТипов=кол.ТипЗначения;
Если рОписТипов.Типы().Количество()=1 и рОписТипов.СодержитТип(Тип(«Булево»)) Тогда
рВыравнивание=«Центр»;
ИначеЕсли рОписТипов.СодержитТип(Тип(«Число»)) Тогда
рВыравнивание=«Право»;
ИначеЕсли рОписТипов.СодержитТип(Тип(«Строка»)) и рОписТипов.КвалификаторыСтроки.Длина=0 Тогда
рВыравнивание=«ПоШирине»;
Иначе
рВыравнивание=«Лево»;
КонецЕсли;
строПолейЗаписи=строПолейЗаписи+?(ПустаяСтрока(строПолейЗаписи),«»,Символы.ПС)+«#Поле «+кол.Имя+«
| #Выравнивание «+рВыравнивание;
Попытка
Если ЗначениеЗаполнено(стрКолонок[кол.Имя]) Тогда // указан формат, уточняющий показ колонки
строПолейЗаписи=строПолейЗаписи+«
| #Формат «»»+СокрЛП(стрКолонок[кол.Имя])+«»»»;
КонецЕсли;
Исключение
КонецПопытки;
мИменКолонок.Добавить(кол.Имя);
КонецЦикла;
секШапка2=СтрЗаменить(СтрЗаменить(секШапка1,«[«,«<«),«]»,«>»);
секЗапись1=секШапка1; секЗапись2=секШапка2; // пусть они по дизайну пока не отличаются
секГорРазделитель2=СтрЗаменить(СтрЗаменить(секГорРазделитель1,«=»,«-«),«|»,«+»);
// обработаем нормальное обрамление шапки колонки иерархии
секГорРазделитель1=СтрЗаменить(секГорРазделитель1,«_»,«=»);
секГорРазделитель2=СтрЗаменить(секГорРазделитель2,«_»,» «);
//
тМакет=Новый ТекстовыйДокумент;
тМакет.ДобавитьСтроку(«#Область Шапка»);
тМакет.ДобавитьСтроку(строПолейШапки);
тМакет.ДобавитьСтроку(секГорРазделитель1);
тМакет.ДобавитьСтроку(секШапка1);
тМакет.ДобавитьСтроку(секШапка2);
тМакет.ДобавитьСтроку(секГорРазделитель1);
тМакет.ДобавитьСтроку(«#КонецОбласти»);
тМакет.ДобавитьСтроку(«»);
тМакет.ДобавитьСтроку(«#Область Запись»);
тМакет.ДобавитьСтроку(строПолейЗаписи);
тМакет.ДобавитьСтроку(секЗапись1);
тМакет.ДобавитьСтроку(секЗапись2);
тМакет.ДобавитьСтроку(секГорРазделитель2);
тМакет.ДобавитьСтроку(«#КонецОбласти»);
рПараметры.Вставить(«ИсходныйМакет»,тМакет); // пусть будет
//—————————————————————————————————————————
// Запускаем вывод в итоговый документ
рТекст=Новый ТекстовыйДокумент;
сек=тМакет.ПолучитьОбласть(«Шапка»);
сек.Параметры._HCS=«Иерархия»;
Для каждого имякол Из мИменКолонок Цикл
кол=рВетка.Колонки[имякол];
сек.Параметры[кол.Имя]=?(ПустаяСтрока(кол.Заголовок),кол.Имя,кол.Заголовок);
КонецЦикла;
рТекст.Вывести(сек);
//
пар=Новый Структура;
пар.Вставить(«МассивИмёнКолонок»,мИменКолонок);
пар.Вставить(«ТекущаяСекция»,тМакет.ПолучитьОбласть(«Запись»));
пар.Вставить(«ШиринаКолонкиИерархии»,рШиринаКолонкиИерархии);
пар.Вставить(«ПоказыватьУровни»,рПоказыватьУровни);
пар.Вставить(«Отступ»,0);
пар.Вставить(«ШагОтступа»,рШагОтступа);
ВывестиДеревоЗначенийВТекст(рВетка,рТекст,пар);
Иначе
// очередная итерация, вывод в текстовый документ
мИменКолонок=рПараметры.МассивИмёнКолонок;
рСекция=рПараметры.ТекущаяСекция;
рОтступ=рПараметры.Отступ;
рШиринаКолонкиИерархии=рПараметры.ШиринаКолонкиИерархии;
рПоказыватьУровни=рПараметры.ПоказыватьУровни;
//
строОтступы=«_________________________________________________________________________________________________________»;
строПробелы=» «;
//
пар=Новый Структура;
пар.Вставить(«МассивИмёнКолонок»,мИменКолонок);
пар.Вставить(«ТекущаяСекция»,рПараметры.ТекущаяСекция);
пар.Вставить(«ШиринаКолонкиИерархии»,рШиринаКолонкиИерархии);
пар.Вставить(«ПоказыватьУровни»,рПоказыватьУровни);
пар.Вставить(«ШагОтступа»,рПараметры.ШагОтступа);
пар.Вставить(«Отступ»,рОтступ+рПараметры.ШагОтступа);
//
Для каждого рПодветка Из рВетка.Строки Цикл
рСекция.Параметры._HCS=Лев(строПробелы,рОтступ)+«\»+Лев(строОтступы,рШиринаКолонкиИерархии—рОтступ—1);
Если рПоказыватьУровни Тогда
рСекция.Параметры._Level=рПодветка.Уровень();
КонецЕсли;
Для каждого имякол Из мИменКолонок Цикл
рСекция.Параметры[имякол]=рПодветка[имякол];
КонецЦикла;
рТекст.Вывести(рСекция);
ВывестиДеревоЗначенийВТекст(рПодветка,рТекст,пар)
КонецЦикла;
//
КонецЕсли;
Исключение
Сообщить(«ВывестиДеревоЗначенийВТекст, ошибка: «+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
КонецПопытки;
КонецПроцедуры
Надеюсь, пригодится и упростит жизнь)