Переход с обычного на управляемое приложение обязывает программиста изменить уже ставшие привычными приёмы написания программного кода.
В этой статье предложены шаблоны программного кода, которые позволяют выполнять различные операции с Таблицой Значений или Деревом Значений в управляемой форме.
В 1С:классификации Таблица Значений и Дерево Значений (ТЗ и ДЗ) представляют собой не сохраняемый в базе объект. В связи с этим, описание коллекций значений для программирования выполняется оперативно в момент обращения к ним.
Для сокращения трудозатрат программиста, в статье предложена универсальная процедура вывода ТаблицыЗначений или ДереваЗначений на экран. Эта процедура программно заполняет колонки реквизита управляемой формы, что весьма удобно при отладке.
На примерах показаны различия работы с КоллекциямиЗначений в толстом и тонком клиентах управляемой формы.
Из примеров следуют общие правила:
А) для толстого клиента ограничений нет. Примеры 1 и 4.
Б) для тонкого клиента – обработку коллекции необходимо выполнять на сервере, там же следует обеспечить вывод результата на экран.
Предложенная универсальная процедура СоздатьКолонкиУпр() программно добавляет колонки в реквизиты формы и преобразовывает коллекциюЗначений в ДанныеФормы.
Универсальную процедуру СоздатьКолонкиУпр() рекомендуется размещать в общем модуле конфигурации. Если это невозможно, то процедура успешно работает в модуле внешнего отчета.
В обычном приложение аналогом является процедура СоздатьКолонки(), которая удаляет старые колонки и загружает новые колонки из источника данных в табличное поле.
Примечание.
Существуют аналоги рассматриваемой теме: Программный вывод таблицы значений на управляемую форму 8.2 , Создание произвольной таблицы значений на форме в управляемом приложении программным способом , Управляемая форма 1С 8.2 (8.3) – работа с деревом значений и таблицей значений. Часть I (Основы) , Пример преобразования дерева значений в таблицу значений и обратно в 1Cv8 , Конструктор программиста – набор шаблонов программного кода для конструирования результата СКД и поддержки баз как типовых и т.д. Ссылки на другие сайты не приводятся согласно правилам публикации на Infostart.
Разница между обычным и управляемым приложениями уже была изложена в аналогах.
Эта статья систематизирует методы работы с коллекциями значений и предлагает удобные для копирования варианты программного кода. Цель статьи – сократить трудозатраты программиста при выборе между толстым и тонким клиентами для использования таблицы (ТЗ) или дерева значений (ДЗ) в качестве источника данных для СистемыКомпоновкиДанных (СКД).
Блок-схема подготовки источника внешних данных для СКД на основании не сохраняемых в базе объектов приведена на прилагаемом рисунке.
Третья группа примеров на Видео демонстрирует реализацию всех веток блок – схемы.
Текст озвучки видео.
Сейчас будут показаны варианты программирования работы с таблицей и деревом значений в тонком и толстом клиентах управляемого приложения.
Откроем 1С:Предприятие в Тонком и Толстом клиентах.
Во всех примерах состав колонок Таблицы Значений или Дерева Значений произвольный, то есть заранее не известен. Программное заполнение реквизитов управляемой формы будет выполнено функцией СоздатьКолонкиУпр().
1) В толстом клиенте никаких ограничений нет. Пример №1 выводит на экран новую таблицу. Пример №4 редактирует существующую таблицу. Все операции можно выполнять на клиенте.
Толстый клиент закрываем.
Остальные примеры рассмотрим в тонком клиенте.
2) В тонком клиенте (пример №2) дерево создается на сервере. Пример №5 редактирует существующее дерево на сервере.
- Пример №6 преобразовывает ДеревоЗначений в таблицу. Это действие востребовано при передаче внешних данных в СКД.
3) Если программист вынужден передать в обработку КоллекциюЗначений через клиента, то это можно выполнить с помощью временного хранилища. Смотрим пример №3.
- Пример №7 показывает как таблицу преобразовать в дерево, используя макет ОсновнаяСхемаКомпоновкиДанных.
4) Заполним ТаблицуЗначений заново и в примере №8 преобразуем её в табличный документ. Теперь можно напечатать результат.
5) Далее отключим конфигуратор и демонстрируем, что ручной ввод с экрана новых строк не нарушает алгоритмов преобразования. (Примечание. Работа с добавлением колонок была показано ранее.)
- Создаём таблицу значений (Пример.3)
- и добавляем строку вручную.
- Преобразовываем таблицу в дерево (Пример.7)
- и добавляем строки в последний уровень и первый,
- Преобразовываем скорректированное дерево в табличный документ по макету ОсновнаяСхемаКомпоновкиДанных. (Пример.9).
- Меняем значение первой колонки
- Повторяем преобразование в ТабДок. (Пример.9) и наглядно видим, что ТабличныйДокумент ожидаемый.
- Преобразовываем скорректированное дерево в таблицу. (Пример.6)
- Скорректированную таблицу преобразовываем в табличный документ по макету ОсновнаяСхемаКомпоновкиДанных.(Пример.8)
- На этом заканчиваем демонстрацию приемов программирования КоллекцийЗначений в управляемом приложении.
6) Третья группа примеров посвящена применению Системы Компоновки Данных (СКД). Здесь будет продемонстрировано практическое использование ранее изложенных приемов для ввода данных в СКД.
- Примеры третьей группы полезны программисту в случаях, когда возникает необходимость применить методы обработки данных не доступные в СКД.
- Пример 10.1. Получаем табличный документ типовой работой СКД со справочником на основании макетаДЗ.Обращаем внимание, что макетДЗ не имеет настроек на ввод данных из внешнего набора, т.е макетДЗ можно построить конструктором.
- Пример 10.2. Получаем тоже самое в форме ДереваЗначений. Добавляем строку и меняем ей родителя на «Блузу».
- Пример 10.3. Возвращает изменённое ДеревоЗначений в формат ТабличногоДокумента по структуре, заданной в макетеДЗ. Такое преобразование востребовано, например, для печати результата типовыми методами.
- Видим, что в сложных для программиста случаях, данные табличного документа можно скорректировать либо вручную, либо программно, используя промежуточное дерево значений.
- Предварительно преобразуем ДЗ в ТЗ. (Пример.6)
- Пример 10.4. Повторяет то же самое для ТаблицыЗначений.
- Техническое решение примеров 10.3 и 10.4 обеспечивает функция ВернутьТабДокСервер(), которая:
- В пустой макет «СКДТонкийКлиент» программно устанавливает НаборДанныхОбъект, который заполняем внешними данными из отредактированной ТЗ.
- Настройки копируем из макетаДЗ.
- Результатом будет требуемый ТабличныйДокумент, учитывающий внесенные изменения в таблицу значений ТЗ.
7) Заключение. Демонстрация показала:
- Процедура СоздатьКолонкиУпр() выполняет такие же функции как процедура. СоздатьКолонки() обычного приложения.
- Если исходная коллекция и результат её преобразования размещены в одной управляемой форме, то необходимо очищать колонки источника во избежание дублирования наименований в приёмнике. (Процедура ОчиститьКоллекциюЗначенийНаСервере()).
- В тонком клиенте модули управления коллекцией значений обязательно следует размещать на сервере.
- Для преобразования коллекции значений в табличной документ с независимым макетомСКД можно применить функцию Скд_ВнешниеДанные().
- Независимый макетСКД можно создать на основании другого макета, например, макетДЗ. Для решения этой задачи можно применить функцию ВернутьТабДокСервер().
- Примечание. Программный код представлен способом, повышающим удобство копирования в разработку. Размеры базовых блоков программного кода, назначенных к копированию в разработку, не превышают четырёх строк.
Желаю успехов всем и каждому.
////////////////////////////////////////////////////////
Описание Процедуры СоздатьКолонкиУпр()
Синтаксис:
СоздатьКолонкиУпр(<ФормаЭта>, <ИмяРеквизита>, <КоллекцияЗначений>)
Параметры:
<ФормаЭта> (обязательный)
Тип:УправляемаяФорма. Форма, в реквизите которой требуется программно определить состав колонок.
<ИмяРеквизита> (обязательный)
Тип:Строка. Имя реквизита как указано в управляемой форме. Этому реквизиту следует определить состав колонок. Тип реквизита должен быть либо ТаблицаЗначений, либо ДеревоЗначений.
<КоллекцияЗначений> (обязательный)
Тип:ТаблицаЗначений, ДеревоЗначений, АдресВременногоХранилища. Источник данных, который следует вывести на экран. Тип источника данных должен быть либо ТаблицаЗначений, либо ДеревоЗначений. Причем, для этого реквизита состав колонок указанный в управляемой форме должен быть пустым.
Описание:
Для любого прикладного объекта типа таблицаЗначений или деревоЗначений, программно создаётся состав колонок реквизита управляемой формы. Затем прикладной объект преобразовывается в данные формы и выводится на экран.
Процедура применяется в случаях, когда состав колонок коллекцииЗначений заранее не определён.
Доступность:
Сервер, ТолстыйКлиент
Примечание:
////////////////////////////////////////////////////////
Описание Функции ВернутьТабДокСервер()
Синтаксис:
ВернутьТабДокСервер (<ТЗисточник >, < АдресМакетаСКД >, < НастройкиСКД_1>)
Параметры:
< ТЗисточник > (обязательный)
Тип:ТаблицаЗначений. Источник данных для формирования результата СКД.
< АдресМакетаСКД > (обязательный)
Тип:Строка. Адрес временного хранилища, в которое помещен макет схемы компоновки данных (Тип:СхемаКомпоновкиДанных).
< НастройкиСКД _1> (обязательный)
Тип:НастройкиКомпоновкиДанных. Текущие настройки макета СКД.
Описание:
Возвращает ТабличныйДокумент с данными из ТаблицыЗначений (ТЗисточник) преобразованными по структуре МакетаСКД
Доступность:
Сервер, ТолстыйКлиент
Примечание:
////////////////////////////////////////////////////////
Описание Функции скд_ВнешниеДанные ()
Синтаксис:
Скд_ВнешниеДанные (<ТЗ_внешниеДанные>, <ТипРезультата="ТабДок">, <АдресМакетаСКД="">, <НастройкиСКД=Неопределено>)
Параметры:
< ТЗ_внешниеДанные > (обязательный)
Тип:ТаблицаЗначений. ДанныеФормыКоллекция. Источник данных для формирования результата СКД.
< ТипРезультата > (не обязательный)
Тип:Строка. Допустимые значения: «ТабДок», «ТабличныйДокумент», «ДЗ», «ДеревоЗначений», «ТЗ», «ТаблицаЗначений».
< АдресМакетаСКД > (не обязательный)
(Тип:Строка).
< НастройкиСКД > (не обязательный)
Тип:НастройкиКомпоновкиДанных. Текущие настройки макета СКД.
Описание:
Возвращает результат СКД заданного типа с данными из ТаблицыЗначений преобразованными по структуре МакетаСКД
Доступность:
Сервер, ТолстыйКлиент
Примечание:
////////////////////////////////////////////////////////
&НаСервере
Процедура СоздатьКолонкиУпр(ФормаЭта,ИмяРеквизита, ДеревоТаблицаЗначенийАдрес) Экспорт
#Если ТолстыйКлиент Тогда
цЭто="ЭтоТолстыйКлиент";//Отладка
#ИначеЕсли ТонкийКлиент Тогда
цЭто="ЭтоТонкийКлиент";//Отладка
#ИначеЕсли Клиент Тогда
цЭто="ЭтоКлиент";//Отладка|ОбычноеПриложение
#ИначеЕсли Сервер Тогда
цЭто="ЭтоСервер";//Отладка
#Иначе
цЭто="ЭтоНеКлиентНеСервер";//Отладка
#КонецЕсли
Вариант=3;
Если Вариант=2 Тогда
////Вариант=2;
ИначеЕсли Вариант=3 тогда
Если ЭтоАдресВременногоХранилища(ДеревоТаблицаЗначенийАдрес) Тогда
цДеревоТаблицаЗначений = ПолучитьИзВременногоХранилища(ДеревоТаблицаЗначенийАдрес);
Иначе
цДеревоТаблицаЗначений = ДеревоТаблицаЗначенийАдрес ;
КонецЕсли;
//ФормаЭта = РеквизитФормыВЗначение(,Тип("УправляемаяФорма"));
фрмЭлементы = ФормаЭта.Элементы;
цРодитель = ФормаЭта.Элементы[имяРеквизита];
цТипЭлемента = Тип("ПолеФормы");
мсУдаляемыеКолонкиРеквизита= Новый Массив;
цРодПодч = цРодитель.ПодчиненныеЭлементы ;
Для каждого кол Из цРодПодч Цикл
кол_имя = кол.Имя;
СтараяКолонкаРеквизита = кол.ПутьКДанным;
мсУдаляемыеКолонкиРеквизита.Добавить(СтараяКолонкаРеквизита);
КонецЦикла;
мсДобавляемыеКолонкиРеквизита = Новый Массив;
для Каждого кол Из цДеревоТаблицаЗначений.Колонки Цикл
кол_имя = кол.Имя;
//ОписаниеТиповДляРеквизита = Новый ОписаниеТипов(ТипыРеквизита);
ОписаниеТиповДляРеквизита = кол.ТипЗначения;
Если ОписаниеТиповДляРеквизита.СодержитТип(Тип("ХранилищеЗначения")) Тогда
Продолжить;
КонецЕсли;
НоваяКолонка = Новый РеквизитФормы(кол_имя, // имя
ОписаниеТиповДляРеквизита, // тип
имяРеквизита, // путь
кол.Заголовок, // заголовок
Ложь); // сохраняемые данные
мсДобавляемыеКолонкиРеквизита.Добавить(НоваяКолонка);
КонецЦикла;
//
#Если НаСервере Тогда
ФормаЭта.ИзменитьРеквизиты(мсДобавляемыеКолонкиРеквизита,мсУдаляемыеКолонкиРеквизита);
#Иначе
ц="ЭтоБлин";
#КонецЕсли
Для каждого новКолонка Из мсДобавляемыеКолонкиРеквизита Цикл
этаКолонкаЕсть = ФормаЭта.Элементы.Найти(новКолонка.Имя);
Если этаКолонкаЕсть<>Неопределено Тогда
//Продолжить;
ФормаЭта.Элементы.Удалить(этаКолонкаЕсть);
КонецЕсли;
Попытка
кол_имя =новКолонка.Имя;
новЭлем = ФормаЭта.Элементы.Добавить(кол_имя, цТипЭлемента, цРодитель);
новЭлем.Вид = ВидПоляФормы.ПолеВвода;
новЭлем.ПутьКДанным = имяРеквизита+"."+кол_имя;
Исключение
//Если ФлагЭтоЯ Тогда
цОш = ОписаниеОшибки();
сооб = Новый СообщениеПользователю;
сооб.Текст = кол_имя+" : "+цОш;
сооб.Поле = кол_имя;
сооб.Сообщить();
//Продолжить;
//КонецЕсли;
КонецПопытки;
КонецЦикла;
#Если не ТонкийКлиент Тогда
ЗначениеВДанныеФормы(цДеревоТаблицаЗначений,ФормаЭта[ИмяРеквизита]);
#КонецЕсли
КонецЕсли;
КонецПроцедуры
R03;
Функция ВернутьТабДокСервер(цРезультатСКД1, цАдресМакетаСКД1, цНастройкиИсточник1) Экспорт
Перем ТабДок2;
цСхемаКомпоновкиДанныхИсточник1 = ПолучитьИзВременногоХранилища(цАдресМакетаСКД1);
цНаборыДанныхИсточник1 = цСхемаКомпоновкиДанныхИсточник1.НаборыДанных ;
цСхемаКомпоновкиДанныхИсточникТабДок2 = ПолучитьОбщийМакет("СКДтонкийКлиент");
//цСхемаКомпоновкиДанныхИсточникТабДок2 = ПолучитьМакет("СКДтонкийКлиент"); //внешнйОтчет
цНаборыДанныхИсточникТабДок2 = цСхемаКомпоновкиДанныхИсточникТабДок2.НаборыДанных ;
цНаборыДанныхИсточникТабДок2.Очистить();
цНаборДанныхТабДок2 = цНаборыДанныхИсточникТабДок2.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
цТемпИмяТЗ_2 = "тзИмяТемп";
цНаборДанныхТабДок2.имя = цТемпИмяТЗ_2;
цИмяОбъекта_2 = "тзОбъектТемп";
//цИмяОбъекта_2 = "тзИсточник";
цНаборДанныхТабДок2.имяОбъекта = цИмяОбъекта_2;
цНаборДанныхТабДок2.ИсточникДанных = "ИсточникДанных1";
Для каждого текНаборИсточник1 Из цНаборыДанныхИсточник1 Цикл
Для каждого поле_1 Из текНаборИсточник1.Поля Цикл
Попытка
Если ТипЗнч(поле_1)= тип("ПолеНабораДанныхСхемыКомпоновкиДанных") Тогда
поле_2 = цНаборДанныхТабДок2.поля.Добавить(тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
ЗаполнитьЗначенияСвойств(поле_2,поле_1, ,"ТипЗначения");
цтип = новый ОписаниеТипов( поле_1.ТипЗначения) ;
поле_2.ТипЗначения = цтип;
ИначеЕсли ТипЗнч(поле_1)= тип("ПапкаПолейНабораДанныхСхемыКомпоновкиДанных") Тогда
поле_2 = цНаборДанныхТабДок2.поля.Добавить(тип("ПапкаПолейНабораДанныхСхемыКомпоновкиДанных"));
ЗаполнитьЗначенияСвойств(поле_2,поле_1, ,);
УбратьИзПутьКДаннымИмяПапки(цРезультатСКД1, поле_1.ПутьКДанным );//ППМ
Иначе
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Отказ, поле_1="+поле_1;
//Сообщение.Поле = "";
//Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
КонецЕсли;
Исключение
цОш= ОписаниеОшибки();
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = цОш+", поле_1="+поле_1;
//Сообщение.Поле = "";
//Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
КонецПопытки;
КонецЦикла
КонецЦикла;
Для каждого текПолеИтога1 Из цСхемаКомпоновкиДанныхИсточник1.ПоляИтога Цикл
Попытка
полеИтога_2 = цСхемаКомпоновкиДанныхИсточникТабДок2.ПоляИтога.Добавить();
ЗаполнитьЗначенияСвойств(полеИтога_2, текПолеИтога1 );
Исключение
цОш= ОписаниеОшибки();
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = цОш+", полеИтога_1="+текПолеИтога1;
//Сообщение.Поле = "";
//Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
КонецПопытки;
КонецЦикла;
ТабДок2 = скд_ВнешниеДанные(цРезультатСКД1,"ТабДок" , цСхемаКомпоновкиДанныхИсточникТабДок2, цНастройкиИсточник1);
Возврат ТабДок2;
КонецФункции
R03;
/////////////////////////////////////////////////////////
R03;
Функция скд_ВнешниеДанные(цТЗ_внешниеДанные, цТипРезультата="ТабДок", цАдресМакетаСКД="", цНастройкиСКД=Неопределено)Экспорт //Преобразовать коллекциюЗначений в табличный документ
Перем ВнешниеДанныеСКД;
Если ВРег(цТипРезультата)="ТАБДОК"
ИЛИ ВРег(цТипРезультата)="ТАБЛИЧНЫЙДОКУМЕНТ"
Тогда
цОбъектСКД=Новый ТабличныйДокумент;
типГенератораСКД = Тип("ГенераторМакетаКомпоновкиДанных");
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(цОбъектСКД);
Иначе
Если ВРег(цТипРезультата)="ДЗ"
ИЛИ ВРег(цТипРезультата)="ДЕРЕВОЗНАЧЕНИЙ"
Тогда
цОбъектСКД=Новый ДеревоЗначений;
ИначеЕсли ВРег(цТипРезультата)="ТЗ"
ИЛИ ВРег(цТипРезультата)="ТАБЛИЦАЗНАЧЕНИЙ"
Тогда
цОбъектСКД=Новый ТаблицаЗначений;
Иначе
цОбъектСКД=Новый ДеревоЗначений;
КонецЕсли;
типГенератораСКД = Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений");
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(цОбъектСКД);
КонецЕсли;
Если ТипЗнч(цТЗ_внешниеДанные)=Тип("ТаблицаЗначений") Тогда
ТЗ = цТЗ_внешниеДанные;
ВнешниеДанныеСКД = Новый Структура("тзОбъектТемп", ТЗ);
//ВнешниеДанныеСКД = Новый Структура("ТЗисточник", ТЗ);
ИначеЕсли ТипЗнч(цТЗ_внешниеДанные)=Тип("ДанныеФормыКоллекция") Тогда
ТЗ = ДанныеФормыВЗначение(цТЗ_внешниеДанные,Тип("ТаблицаЗначений"));
ВнешниеДанныеСКД = Новый Структура("тзОбъектТемп", ТЗ);
//ВнешниеДанныеСКД = Новый Структура("ТЗисточник", ТЗ);
Иначе
// это ТабличныйДокумент
КонецЕсли;
Если ЭтоАдресВременногоХранилища(цАдресМакетаСКД) Тогда
СхемаКомпоновкиДанных = ПолучитьИзВременногоХранилища(цАдресМакетаСКД) ;
ИначеЕсли ТипЗнч(цАдресМакетаСКД)= Тип("СхемаКомпоновкиДанных") Тогда
СхемаКомпоновкиДанных = цАдресМакетаСКД ;
Иначе
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "нет макета СКД";
//Сообщение.Поле = "";
//Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
Возврат цОбъектСКД;
КонецЕсли;
Если цНастройкиСКД=Неопределено Тогда
Настройки = СхемаКомпоновкиДанных.НастройкиПоУмолчанию;
Иначе
Настройки = цНастройкиСКД;
КонецЕсли;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, , ,типГенератораСКД, ,);
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеДанныеСКД );
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
Возврат цОбъектСКД;
КонецФункции
R03;
Состав zip.
1. База данных c примерами для копирования - dt и cf.
2. Внешняя обработка.