Как обойти табличный документ и правильно передать данные между управляемыми формами в 1С 8.3?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Подход 1. Программное получение данных отчета (рекомендуемый способ)

Если цель состоит в том, чтобы получить данные для дальнейших вычислений, открывать форму отчета и разбирать печатную форму не требуется. Гораздо надежнее и быстрее выполнить компоновку отчета на сервере напрямую в коллекцию ТаблицаЗначений. Это исключает зависимость от визуального оформления отчета, настроек колонок и видимости ячеек.

Рассмотрим по шагам программное формирование отчета на базе СКД (Системы компоновки данных) с выводом результата в таблицу значений:


&НаСервере
Функция ПолучитьДанныеОтчетаНаСервере()
    
    // Получаем объект отчета
    ОтчетОбъект = Отчеты.МТ_ОстаткиТоваровНаСкладах.Создать();
    СхемаКомпоновки = ОтчетОбъект.СхемаКомпоновкиДанных;
    
    // Инициализируем настройки
    Настройки = ОтчетОбъект.КомпоновщикНастроек.ПолучитьНастройки();
    
    // Формируем макет компоновки
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки, Настройки,,, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
    
    // Инициализируем процессор компоновки
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
    
    // Создаем таблицу для результата и выводим данные
    ТаблицаРезультат = Новый ТаблицаЗначений;
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
    ПроцессорВывода.УстановитьОбъект(ТаблицаРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    Возврат ТаблицаРезультат;
    
КонецФункции

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

Подход 2. Немодальная передача данных между управляемыми формами

Проанализируем ситуацию, когда форму открыть все же необходимо (например, чтобы пользователь интерактивно выбрал параметры или заполнил список) и вернуть результат в вызывающую форму. Использование метода ОткрытьФормуМодально в управляемом интерфейсе заблокировано конфигурацией (режим без модальности). Для возврата данных используются асинхронные механизмы.

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

Разберем реализацию передачи данных через ОписаниеОповещения и Временное хранилище:

  1. Код в вызывающей форме (Форма 1):

    При открытии второй формы мы передаем описание оповещения — процедуру, которая выполнится при закрытии дочернего окна.

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

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

    
    &НаКлиенте
    Процедура ВыполнитьИЗакрыть(Команда)
        
        АдресХранилища = ВыполнитьИПоместитьВХранилищеНаСервере();
        ЭтаФорма.Закрыть(АдресХранилища);
        
    КонецПроцедуры
    
    &НаСервере
    Функция ВыполнитьИПоместитьВХранилищеНаСервере()
        
        ТаблицаРезультат = Новый ТаблицаЗначений;
        // ... Заполнение таблицы значений ...
        
        // Помещаем данные во временное хранилище с уникальным идентификатором владельца
        Адрес = ПоместитьВоВременноеХранилище(ТаблицаРезультат, ВладелецФормы.УникальныйИдентификатор);
        Возврат Адрес;
        
    КонецФункции
    

Подход 3. Прямой обход табличного документа

Если табличный документ уже сформирован и вам требуется обойти его ячейки, выясним, как правильно работать с объектом ТабличныйДокумент. Для получения границ документа используются свойства ВысотаТаблицы (количество заполненных строк) и ШиринаТаблицы (количество колонок), а для доступа к ячейке — метод Область().

Посмотрим на пример обхода строк и извлечения как текстовых значений, так и ссылочных объектов расшифровки:


&НаСервере
Процедура ОбойтиТабличныйДокумент(ТабДок)
    
    КоличествоСтрок = ТабДок.ВысотаТаблицы;
    КоличествоКолонок = ТабДок.ШиринаТаблицы;
    
    // Предположим, что данные начинаются со 2-й строки (после шапки)
    Для НомерСтроки = 2 По КоличествоСтрок Цикл
        
        // Получаем область конкретной ячейки по координатам (R, C)
        ЯчейкаНоменклатура = ТабДок.Область(НомерСтроки, 1);
        ЯчейкаКоличество   = ТабДок.Область(НомерСтроки, 2);
        
        // Свойство .Текст возвращает строковое представление
        ТекстНоменклатуры = ЯчейкаНоменклатура.Текст;
        
        // Свойство .Расшифровка позволяет получить саму ссылку, если она была заполнена
        СсылкаНоменклатура = ЯчейкаНоменклатура.Расшифровка;
        
        // Преобразуем строковое значение количества в число
        ЗначениеКоличество = Число(ЯчейкаКоличество.Текст);
        
        Если ЗначениеЗаполнено(СсылкаНоменклатура) Тогда
            // Обработка данных строки
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

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

← На главную