При разработке в среде 1С:Предприятие 8.3 на управляемых формах часто возникает задача получить данные отчета или другой формы и обработать их в вызывающем модуле. Начинающие разработчики нередко пытаются открыть форму отчета модально, сформировать печатную форму и затем построчно считывать ячейки полученного табличного документа. Разберем, почему такой подход считается неоптимальным, как правильно получать данные напрямую и как при необходимости обойти готовый табличный документ или передать коллекции данных между формами.
Если цель состоит в том, чтобы получить данные для дальнейших вычислений, открывать форму отчета и разбирать печатную форму не требуется. Гораздо надежнее и быстрее выполнить компоновку отчета на сервере напрямую в коллекцию ТаблицаЗначений. Это исключает зависимость от визуального оформления отчета, настроек колонок и видимости ячеек.
Рассмотрим по шагам программное формирование отчета на базе СКД (Системы компоновки данных) с выводом результата в таблицу значений:
&НаСервере
Функция ПолучитьДанныеОтчетаНаСервере()
// Получаем объект отчета
ОтчетОбъект = Отчеты.МТ_ОстаткиТоваровНаСкладах.Создать();
СхемаКомпоновки = ОтчетОбъект.СхемаКомпоновкиДанных;
// Инициализируем настройки
Настройки = ОтчетОбъект.КомпоновщикНастроек.ПолучитьНастройки();
// Формируем макет компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки, Настройки,,, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
// Инициализируем процессор компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
// Создаем таблицу для результата и выводим данные
ТаблицаРезультат = Новый ТаблицаЗначений;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(ТаблицаРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Возврат ТаблицаРезультат;
КонецФункции
В результате мы получаем готовую типизированную таблицу со всеми полями отчета без необходимости эмулировать нажатия кнопок пользователем и открывать окна.
Проанализируем ситуацию, когда форму открыть все же необходимо (например, чтобы пользователь интерактивно выбрал параметры или заполнил список) и вернуть результат в вызывающую форму. Использование метода ОткрытьФормуМодально в управляемом интерфейсе заблокировано конфигурацией (режим без модальности). Для возврата данных используются асинхронные механизмы.
Важное ограничение: объект типа ТаблицаЗначений существует только на сервере и не может быть передан на клиент напрямую. Для передачи данных с сервера дочерней формы на сервер вызывающей формы используют либо массив структур (доступен на клиенте), либо временное хранилище.
Разберем реализацию передачи данных через ОписаниеОповещения и Временное хранилище:
При открытии второй формы мы передаем описание оповещения — процедуру, которая выполнится при закрытии дочернего окна.
&НаКлиенте
Процедура СформироватьОтчет(Команда)
ОповещениеОЗакрытии = Новый ОписаниеОповещения("ПослеЗакрытияФормыОтчета", ЭтотОбъект);
ПараметрыОткрытия = Новый Структура;
ОткрытьФорму("Отчет.МТ_ОстаткиТоваровНаСкладах.Форма.Форма", ПараметрыОткрытия, ЭтотОбъект,,,, ОповещениеОЗакрытии);
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗакрытияФормыОтчета(РезультатЗакрытия, ДополнительныеПараметры) Экспорт
Если РезультатЗакрытия = Неопределено Тогда
Возврат; // Пользователь просто закрыл форму крестиком
КонецЕсли;
// РезультатЗакрытия содержит адрес во временном хранилище
ОбработатьРезультатНаСервере(РезультатЗакрытия);
КонецПроцедуры
&НаСервере
Процедура ОбработатьРезультатНаСервере(АдресВХранилище)
ТаблицаДанных = ПолучитьИзВременногоХранилища(АдресВХранилище);
УдалитьИзВременногоХранилища(АдресВХранилище);
// Выполняем обход полученной таблицы значений
Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
// Обработка полей: СтрокаТЗ.Номенклатура, СтрокаТЗ.Количество
КонецЦикла;
КонецПроцедуры
При выполнении операции помещаем сформированную таблицу значений во временное хранилище с привязкой к идентификатору формы-владельца (чтобы данные не очистились при закрытии текущей формы) и закрываем форму с передачей адреса.
&НаКлиенте
Процедура ВыполнитьИЗакрыть(Команда)
АдресХранилища = ВыполнитьИПоместитьВХранилищеНаСервере();
ЭтаФорма.Закрыть(АдресХранилища);
КонецПроцедуры
&НаСервере
Функция ВыполнитьИПоместитьВХранилищеНаСервере()
ТаблицаРезультат = Новый ТаблицаЗначений;
// ... Заполнение таблицы значений ...
// Помещаем данные во временное хранилище с уникальным идентификатором владельца
Адрес = ПоместитьВоВременноеХранилище(ТаблицаРезультат, ВладелецФормы.УникальныйИдентификатор);
Возврат Адрес;
КонецФункции
Если табличный документ уже сформирован и вам требуется обойти его ячейки, выясним, как правильно работать с объектом ТабличныйДокумент. Для получения границ документа используются свойства ВысотаТаблицы (количество заполненных строк) и ШиринаТаблицы (количество колонок), а для доступа к ячейке — метод Область().
Посмотрим на пример обхода строк и извлечения как текстовых значений, так и ссылочных объектов расшифровки:
&НаСервере
Процедура ОбойтиТабличныйДокумент(ТабДок)
КоличествоСтрок = ТабДок.ВысотаТаблицы;
КоличествоКолонок = ТабДок.ШиринаТаблицы;
// Предположим, что данные начинаются со 2-й строки (после шапки)
Для НомерСтроки = 2 По КоличествоСтрок Цикл
// Получаем область конкретной ячейки по координатам (R, C)
ЯчейкаНоменклатура = ТабДок.Область(НомерСтроки, 1);
ЯчейкаКоличество = ТабДок.Область(НомерСтроки, 2);
// Свойство .Текст возвращает строковое представление
ТекстНоменклатуры = ЯчейкаНоменклатура.Текст;
// Свойство .Расшифровка позволяет получить саму ссылку, если она была заполнена
СсылкаНоменклатура = ЯчейкаНоменклатура.Расшифровка;
// Преобразуем строковое значение количества в число
ЗначениеКоличество = Число(ЯчейкаКоличество.Текст);
Если ЗначениеЗаполнено(СсылкаНоменклатура) Тогда
// Обработка данных строки
КонецЕсли;
КонецЦикла;
КонецПроцедуры
При проектировании алгоритмов всегда отдавайте предпочтение прямому формированию данных в ТаблицаЗначений через серверные механизмы. Обход печатной формы табличного документа используйте только в крайних случаях, когда исходный источник данных или алгоритм формирования отчета недоступны для программного вызова.