Как программно заполнить таблицу или дерево значений на форме данными из справочника в 1С

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

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

Алгоритм ручного заполнения таблицы через перебор результата запроса

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

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

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

Посмотрим на пример кода, реализующий этот алгоритм:


&НаСервере
Процедура ЗаполнитьТаблицуНаСервере()
    
    // 1. Очищаем таблицу на форме (назовем её СписокДанных)
    Объект.СписокДанных.Очистить();
    
    // 2. Формируем запрос
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	Номенклатура.Наименование КАК Наименование,
        |	Номенклатура.Артикул КАК Артикул
        |ИЗ
        |	Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |	НЕ Номенклатура.ЭтоГруппа";
    
    РезультатЗапроса = Запрос.Выполнить();
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
    
    // 3. Цикл по результатам
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        // 4. Добавляем строку в таблицу формы
        НоваяСтрока = Объект.СписокДанных.Добавить();
        НоваяСтрока.Наименование = ВыборкаДетальныеЗаписи.Наименование;
        НоваяСтрока.Артикул      = ВыборкаДетальныеЗаписи.Артикул;
    КонецЦикла;
    
КонецПроцедуры

Проблема сопоставления колонок: почему данные не отображаются?

Выясним причину одной из самых частых ошибок. Часто бывает так: код выполняется без ошибок, цикл проходит, но таблица на форме остается пустой или значения не «прилетают» в нужные ячейки. Проанализируем ситуацию: в запросе вы выбираете поле Наименование, а в реквизите формы колонка называется Значение. Система 1С не знает, что вы хотите поместить наименование именно в эту колонку, если вы не укажете это явно.

Важные правила сопоставления:

Оптимальный способ: Использование метода ЗначениеВРеквизитФормы

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

Выполним следующие действия:


&НаСервере
Процедура ЗаполнитьБыстроНаСервере()
    
    Запрос = Новый Запрос("ВЫБРАТЬ Наименование, Код ИЗ Справочник.Номенклатура");
    
    // Выгружаем результат сразу в таблицу значений
    ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
    
    // Копируем данные в реквизит формы (например, в 'ТаблицаНаФорме')
    // Важно: колонки в ТаблицаРезультата и в ТаблицаНаФорме должны совпадать по именам!
    ЗначениеВРеквизитФормы(ТаблицаРезультата, "Объект.ТаблицаНаФорме");
    
КонецПроцедуры

Этот метод ЗначениеВРеквизитФормы работает значительно быстрее, так как платформа оптимизирует передачу данных. Однако помните, что он полностью замещает содержимое реквизита формы данными из таблицы.

Работа с иерархией: Дерево значений

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

Секрет заключается в использовании обхода по группировкам с иерархией. Посмотрим на пример запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Номенклатура.Ссылка КАК Ссылка,
    |	Номенклатура.Наименование КАК Наименование
    |ИЗ
    |	Справочник.Номенклатура КАК Номенклатура
    |ИТОГИ ПО
    |	Ссылка ИЕРАРХИЯ";

Результат = Запрос.Выполнить();
// Выгружаем с сохранением иерархии
Дерево = Результат.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
ЗначениеВРеквизитФормы(Дерево, "ДеревоНаФорме");

При таком подходе система сама поймет, какие записи являются родительскими, а какие подчиненными, и отрисует дерево с «плюсиками» для раскрытия групп.

Рекурсивный обход дерева значений

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

Рассмотрим по шагам, как организовать такой обход:

  1. Создаем основную процедуру, которая обращается к верхнему уровню дерева (коллекция Строки).
  2. Создаем рекурсивную процедуру, которая принимает на вход текущую коллекцию строк.
  3. Внутри цикла по строкам выполняем нужные действия и снова вызываем эту же процедуру для подчиненных строк (ТекущаяСтрока.Строки).

Пример программного кода для обхода:


&НаСервере
Процедура ОбработатьВсеДерево()
    // Начинаем обход с верхнего уровня
    ОбходСтрокРекурсивно(Объект.ДеревоНаФорме.ПолучитьЭлементы());
КонецПроцедуры

&НаСервере
Процедура ОбходСтрокРекурсивно(КоллекцияСтрок)
    
    Для Каждого СтрокаДерева Из КоллекцияСтрок Цикл
        
        // Здесь выполняем действия с текущей строкой
        Сообщить(СтрокаДерева.Наименование);
        
        // РЕКУРСИЯ: вызываем эту же процедуру для "детей" текущей строки
        ПодчиненныеСтроки = СтрокаДерева.ПолучитьЭлементы();
        Если ПодчиненныеСтроки.Количество() > 0 Тогда
            ОбходСтрокРекурсивно(ПодчиненныеСтроки);
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Альтернатива: Динамические списки

Проанализируем ситуацию: если ваша цель — просто показать данные справочника для выбора или просмотра, то, возможно, вам вообще не нужно писать код для заполнения таблицы. В 1С существует объект ДинамическийСписок.

Преимущества динамического списка:

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

Типизация и обновление интерфейса

В завершение подчеркнем важность типизации. При программном создании колонок (через ИзменитьРеквизиты) всегда точно указывайте типы. Если вы ожидаете в колонке ссылку на справочник СправочникСсылка.Контрагенты, не оставляйте тип неопределенным. Это обеспечит корректную работу стандартных кнопок выбора и предотвратит ошибки отображения.

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

← На главную