Как реализовать горизонтальное отображение табличных частей нескольких документов в одной форме

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

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

Архитектура решения: динамическое создание реквизитов

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

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


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

Создание интерфейса: горизонтальные группы и таблицы

Для того чтобы таблицы располагались слева направо, нам необходимо поместить их в группу формы с горизонтальной группировкой. Разберем процесс создания элементов управления. Каждая таблица будет привязана к пути к данным ИмяРеквизита.Товары (где Товары — имя табличной части документа).

Рассмотрим подробнее процедуру формирования элементов:


&НаСервере
Процедура СоздатьЭлементыТаблицы(ИмяРеквизита, Индекс, ДокументОбъект)

    // Создаем группу для визуального разделения документов
    ИмяГруппы = "ГруппаДокумента_" + Индекс;
    ГруппаДокумента = Элементы.Добавить(ИмяГруппы, Тип("ГруппаФормы"), Элементы.ОсновнаяГоризонтальнаяГруппа);
    ГруппаДокумента.Вид = ГруппаФормыВид.ОбычнаяГруппа;
    ГруппаДокумента.Заголовок = "Документ №" + ДокументОбъект.Номер;
    
    // Добавляем таблицу формы
    ИмяТаблицы = "Таблица_" + Индекс;
    Таблица = Элементы.Добавить(ИмяТаблицы, Тип("ТаблицаФормы"), ГруппаДокумента);
    Таблица.ПутьКДанным = ИмяРеквизита + ".Товары";
    
    // Настраиваем ограничения: запрещаем удаление и добавление строк
    Таблица.ИзменятьСоставСтрок = Ложь;
    Таблица.ИзменятьПорядокСтрок = Ложь;
    
    // Добавляем колонки (например, Номенклатура и Цена)
    ДобавитьКолонку(Таблица, ИмяТаблицы, "Номенклатура", "Товар", Истина);
    ДобавитьКолонку(Таблица, ИмяТаблицы, "Цена", "Цена", Ложь);

КонецПроцедуры

&НаСервере
Процедура ДобавитьКолонку(ТаблицаФормы, ИмяТаблицы, ИмяПоля, Заголовок, ТолькоПросмотр)
    
    НоваяКолонка = Элементы.Добавить(ИмяТаблицы + "_" + ИмяПоля, Тип("ПолеФормы"), ТаблицаФормы);
    НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода;
    НоваяКолонка.ПутьКДанным = ТаблицаФормы.ПутьКДанным + "." + ИмяПоля;
    НоваяКолонка.Заголовок = Заголовок;
    НоваяКолонка.ТолькоПросмотр = ТолькоПросмотр;
    
КонецПроцедуры

Оптимизация и обработка событий

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

  1. Групповое изменение реквизитов. Как мы уже отметили, метод ИзменитьРеквизиты должен вызываться один раз. Каждый вызов этого метода заставляет сервер пересобирать всю структуру формы, что при большом количестве документов приведет к значительным задержкам.
  2. Синхронизация прокрутки. Размещая несколько таблиц рядом, вы столкнетесь с тем, что у каждой из них будет своя вертикальная полоса прокрутки. Платформа 1С не поддерживает автоматическую синхронизацию скроллинга разных таблиц. Если в документах разное количество строк или они отсортированы по-разному, визуальное сравнение затруднится. Проанализируем решение: в таких случаях эффективнее использовать одну общую таблицу (Таблицу Значений), где строки представляют собой товары, а колонки дублируются для каждого документа (Документ1_Цена, Документ2_Цена).
  3. Обработка изменений. Если нам нужно выполнять действия при изменении цены, мы должны программно назначить обработчик события. Это делается с помощью метода УстановитьДействие.

Посмотрим на пример программного назначения события:


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

На клиенте необходимо описать соответствующую процедуру:


&НаКлиенте
Процедура Подключаемый_ПриИзмененииЦены(Элемент)
    // Элемент.Имя поможет определить, в какой именно таблице (документе) изменены данные
    Сообщить("Цена изменена в элементе: " + Элемент.Имя);
    ЭтаФорма.Модифицированность = Истина;
КонецПроцедуры

Сохранение данных

После редактирования цен пользователем, нам необходимо сохранить изменения обратно в базу данных. Поскольку мы использовали реквизиты типа ДокументОбъект, процесс упрощается. Нам нужно пройтись по всем созданным динамическим реквизитам, конвертировать их обратно в объекты и вызвать метод Записать.


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

Альтернатива: Табличный документ

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

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

Выясним причину выбора того или иного метода: если документов мало (до 5) и нужно быстрое редактирование — используем динамические таблицы формы. Если документов много и важна читаемость — лучше спроектировать сводную таблицу или использовать табличный документ.

← На главную