Как отобразить таблицу внутри ячейки таблицы на форме в 1С?

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

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

Ограничения платформы 1С:Предприятие

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

Элемент формы Таблица принципиально не может содержать другой элемент Таблица внутри своей ячейки. Ячейки таблицы формы предназначены только для отображения скалярных типов данных (строка, число, дата, булево, ссылки на объекты базы данных) либо элементов управления типа ПолеВвода, ПолеФлажка и ПолеНадписи. Сложные коллекции значений внутри ячеек интерфейсом формы игнорируются.

Выясним, какие альтернативные способы позволяют решить прикладную задачу пользователя удобно и без нарушения стандартов разработки платформы 1С.

Способ 1. Использование двух связанных таблиц (Master-Detail)

Это классический, наиболее производительный и привычный для пользователей вариант организации интерфейса. Рассмотрим его реализацию по шагам.

  1. Создадим на форме два реквизита с типом ТаблицаЗначений: например, ТаблицаКонтрагентов (основная) и ТаблицаДоговоров (подчиненная).
  2. В табличной части контрагентов предусмотрим уникальный идентификатор строки (или используем ссылку на контрагента). В табличной части договоров добавим колонку для связи (ключ родительской строки или ссылка на контрагента), а также реквизиты Договор и Пометка (тип Булево).
  3. Разместим на управляемой форме обе таблицы рядом или друг под другом.
  4. Для таблицы контрагентов назначим обработчик события ПриАктивизацииСтроки. При смене текущей строки в первой таблице программно устанавливаем отбор во второй таблице.

Посмотрим на пример установки отбора во второй таблице при смене активной строки в первой:


&НаКлиенте
Процедура ТаблицаКонтрагентовПриАктивизацииСтроки(Элемент)
    СтрокаТаблицы = Элемент.ТекущиеДанные;
    Если СтрокаТаблицы = Неопределено Тогда
        Элементы.ТаблицаДоговоров.ОтборСтрок = Неопределено;
        Возврат;
    КонецЕсли;
    
    // Устанавливаем отбор подчиненной таблицы по контрагенту
    Элементы.ТаблицаДоговоров.ОтборСтрок = Новый ФиксированнаяСтруктура("Контрагент", СтрокаТаблицы.Контрагент);
КонецПроцедуры

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

Способ 2. Использование Дерева значений

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

  1. Создаем реквизит управляемой формы с типом ДеревоЗначений.
  2. Добавляем в реквизит колонки: Наименование, Договор, Пометка.
  3. Перетаскиваем дерево значений в элементы формы. Платформа создаст элемент Таблица, поддерживающий раскрывающиеся узлы.
  4. При заполнении дерева на верхний уровень добавляем контрагентов, а в подчиненную коллекцию строк родительского узла — связанные договоры с флажками.

Посмотрим на пример программного заполнения дерева значений на сервере:


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

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

Способ 3. Выбор нескольких значений через диалог в одной ячейке

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

  1. Для поля ячейки в свойствах включаем КнопкаВыбора = Истина и РедактированиеТекста = Ложь.
  2. В событии ячейки НачалоВыбора перехватываем действие пользователя и открываем диалог отметки элементов списка.
  3. Для выбора используем асинхронный метод ПоказатьОтметкуЭлементов().
  4. Выбранные элементы преобразуем в строку через разделитель и выводим в ячейку, а сам массив или список значений сохраняем в скрытой колонке или служебном соответствии.

Посмотрим на пример реализации обработчика начала выбора:


&НаКлиенте
Процедура ТаблицаСписокДоговоровНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    
    ТекущаяСтрока = Элементы.Таблица.ТекущиеДанные;
    Если ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    СписокВыбора = ПолучитьСписокДоговоровКонтрагента(ТекущаяСтрока.Контрагент);
    
    Оповещение = Новый ОписаниеОповещения("ПослеВыбораДоговоров", ЭтотОбъект, ТекущаяСтрока);
    СписокВыбора.ПоказатьОтметкуЭлементов(Оповещение, "Выберите договоры");
КонецПроцедуры

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

Способ 4. Многострочный текст для режима просмотра

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

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

Итоги

Попытка напрямую встроить элемент Таблица в ячейку противоречит архитектуре платформы 1С. Наиболее эргономичным решением остается разделение интерфейса на две связанные таблицы (Master-Detail) или использование ДереваЗначений, если требуется сохранить монолитный вид древовидного реестра.

← На главную