К статье
Практический материал

Разработка и Конфигурация · 13 мин

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

Как программно заполнить таблицу значений на форме в 1С: реквизиты формы, ДанныеФормыВЗначение, добавление строк, обход и типичные ошибки при работе с таблицами.

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

Ключевой момент: на управляемой форме нельзя работать с таблицей значений напрямую, как в модуле объекта. Форма хранит данные в специальном формате — ДанныеФормыКоллекция, и для массового заполнения нужно либо добавлять строки через методы коллекции, либо преобразовывать данные через ДанныеФормыВЗначение и ЗначениеВДанныеФормы. Ниже разобраны оба подхода с готовым кодом и типичными ошибками.

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

Как устроена таблица значений на управляемой форме

Когда вы добавляете на форму реквизит с типом «ТаблицаЗначений», платформа на самом деле создаёт не классическую таблицу значений, а объект ДанныеФормыКоллекция. У него есть методы Добавить(), Вставить(), Удалить(), НайтиСтроки(), но нет, например, метода ВыгрузитьКолонку() в привычном виде и нельзя присвоить ему другую таблицу целиком.

Это сделано намеренно: управляемая форма живёт в двух экземплярах — на клиенте и на сервере, — и платформа должна контролировать передачу данных между ними. Поэтому любые операции с таблицей на форме идут через специальный программный интерфейс, а попытка написать ТаблицаФормы = МояТаблицаЗначений; закончится ошибкой несовпадения типов.

Строки коллекции формы имеют тип ДанныеФормыЭлементКоллекции. К полям строки обращаются по имени колонки: Строка.Номенклатура, Строка.Количество. Имена должны точно совпадать с именами колонок реквизита, включая регистр символов в соответствии с тем, как колонка названа в конфигураторе.

Создание реквизита формы и колонок

Первый шаг — добавить реквизит формы. В конфигураторе откройте форму, перейдите на вкладку «Реквизиты» и создайте новый реквизит, например ТоварыПодбор, с типом «ТаблицаЗначений». Затем разверните реквизит и добавьте подчинённые колонки: Номенклатура (СправочникСсылка.Номенклатура), Количество (Число), Цена (Число) и так далее. После этого перетащите реквизит в дерево элементов формы, чтобы появилась видимая таблица.

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

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

Заполнение таблицы через добавление строк

Самый простой способ — последовательно добавлять строки методом Добавить(). Этот подход работает и на клиенте, и на сервере, не требует преобразований и хорошо подходит, когда строк немного (десятки, сотни) или они добавляются по одной — например, при подборе товара пользователем.

&НаСервере

Процедура ЗаполнитьТоварыНаСервере()

ТоварыПодбор.Очистить();

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ ПЕРВЫЕ 100

| Номенклатура.Ссылка КАК Номенклатура,

| Номенклатура.Артикул КАК Артикул

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ГДЕ

| НЕ Номенклатура.ПометкаУдаления";

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

НоваяСтрока = ТоварыПодбор.Добавить();

НоваяСтрока.Номенклатура = Выборка.Номенклатура;

НоваяСтрока.Артикул = Выборка.Артикул;

НоваяСтрока.Количество = 1;

КонецЦикла;

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

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

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

Массовое заполнение через ДанныеФормыВЗначение и ЗначениеВДанныеФормы

Когда у вас уже есть готовая таблица значений — результат Запрос.Выполнить().Выгрузить() или таблица, полученная извне, — удобнее перенести её целиком. Для этого служат глобальные методы ЗначениеВДанныеФормы() и обратный ДанныеФормыВЗначение().

&НаСервере

Процедура ЗагрузитьИзЗапросаНаСервере()

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Товары.Номенклатура КАК Номенклатура,

| СУММА(Товары.Количество) КАК Количество

|ИЗ

| Документ.РеализацияТоваровУслуг.Товары КАК Товары

|СГРУППИРОВАТЬ ПО

| Товары.Номенклатура";

ТаблицаРезультат = Запрос.Выполнить().Выгрузить();

ЗначениеВДанныеФормы(ТаблицаРезультат, ТоварыПодбор);

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

Здесь критично совпадение имён колонок: колонка Номенклатура в выгруженной таблице сопоставится с колонкой Номенклатура реквизита формы. Колонки, которых нет в реквизите формы, будут проигнорированы, а колонки реквизита, отсутствующие в источнике, останутся пустыми. Ошибки при этом не возникает — данные просто молча не перенесутся, поэтому после загрузки стоит проверить результат.

Обратное преобразование нужно, когда данные из формы требуется обработать серверными механизмами: свернуть, отсортировать по нескольким колонкам, передать в менеджер записи или в СКД:

ТаблицаДляОбработки = ДанныеФормыВЗначение(ТоварыПодбор, Тип("ТаблицаЗначений"));

ТаблицаДляОбработки.Свернуть("Номенклатура", "Количество");

Порядок действий
  1. 1
    Создайте реквизит формы типа «ТаблицаЗначений» и добавьте колонки с нужными типами
  2. 2
    Перетащите реквизит в элементы формы, чтобы появилась видимая таблица
  3. 3
    Напишите серверную процедуру заполнения: запрос + цикл с Добавить() или ЗначениеВДанныеФормы()
  4. 4
    Вызовите процедуру из клиентского обработчика (ПриСозданииНаСервере или команды)
  5. 5
    Откройте форму и проверьте, что строки видны и типы колонок отображаются корректно

Когда заполнять таблицу: события формы

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

Если данные зависят от действий пользователя — выбора организации, периода, нажатия кнопки «Заполнить» — создайте команду формы и в её клиентском обработчике вызывайте серверную процедуру. Разделение обязательно: запросы и работа с БД доступны только на сервере, а команда по умолчанию выполняется на клиенте.

&НаКлиенте

Процедура Заполнить(Команда)

ЗаполнитьТоварыНаСервере();

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

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

Работа с таблицей на обычной форме

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

// Обычная форма

ТоварыПодбор = Запрос.Выполнить().Выгрузить();

ЭлементыФормы.ТоварыПодбор.СоздатьКолонки();

Метод СоздатьКолонки() у элемента формы автоматически создаёт видимые колонки по структуре таблицы. В управляемых формах такого метода нет — колонки элемента там либо создаются в конфигураторе, либо программно через Элементы.Добавить() с привязкой к пути данных.

Типичные ошибки и как их диагностировать

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

Вторая группа ошибок — обращение к реквизиту формы из контекста, где он недоступен. В модуле объекта обработки реквизитов формы не существует: если заполнение написано в модуле объекта внешней обработки, а таблица — на её форме, данные нужно передавать через параметры или экспортные процедуры формы. Также реквизиты формы недоступны в &НаКлиенте-процедурах, если обращение идёт к серверным данным без соответствующего контекста — точнее, коллекция формы доступна и на клиенте, но запросы к БД оттуда невозможны.

Типичные ошибки
01
Присвоение обычной таблицы значений реквизиту формы напрямую — ошибка несовпадения типов, используйте ЗначениеВДанныеФормы()
02
Отсутствие Очистить() перед заполнением — строки дублируются при каждом повторном вызове
03
Несовпадение имён колонок источника и реквизита — данные молча не переносятся без сообщения об ошибке
04
Серверный вызов в цикле на каждую строку — таблица из тысячи строк заполняется десятки секунд
05
Обращение к реквизиту формы из модуля объекта — там реквизиты формы недоступны

Проверка результата и оптимизация

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

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

Контрольные точки

Как проверить результат

Количество строк после заполнения
Норма

Совпадает с количеством строк результата запроса

Тревожный признак

Ноль или больше ожидаемого — проверьте запрос и наличие Очистить()

Значения в ссылочных колонках
Норма

Отображаются представления элементов справочника

Тревожный признак

Пустые ячейки — не совпали имена колонок или типы

Повторный вызов заполнения
Норма

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

Тревожный признак

Строки удваиваются — нет очистки перед загрузкой

Частые вопросы

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

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

Почему возникает ошибка «Поле объекта не обнаружено» при обращении к колонке?

Имя колонки в коде не совпадает с именем колонки реквизита формы, либо колонка вообще не добавлена. Откройте реквизит в конфигураторе и сверьте имена посимвольно. Также ошибка возникает, если обращение идёт к строке другой таблицы — проверьте, из какой коллекции получена строка.

Можно ли заполнить таблицу на форме без серверного вызова?

Да, если данные уже есть на клиенте: например, строки добавляются по одной при подборе или копируются из другой таблицы этой же формы. Метод Добавить() работает на клиенте. Но любые данные из базы — запросы, ссылки, остатки — требуют серверного контекста.

Как добавить колонку в таблицу на форме программно?

Через массив реквизитов: создайте Новый РеквизитФормы("ИмяКолонки", ОписаниеТипов, "ИмяТаблицы"), добавьте в массив, вызовите ИзменитьРеквизиты(МассивДобавляемых), затем создайте элемент формы Элементы.Добавить() с ПутьКДанным = "ИмяТаблицы.ИмяКолонки". Все действия выполняются только на сервере.

Чем отличается Очистить() от повторного ЗначениеВДанныеФормы()?

ЗначениеВДанныеФормы() полностью замещает содержимое коллекции — предварительная очистка не нужна. Очистить() требуется только перед заполнением через Добавить() в цикле, иначе новые строки добавятся к старым. При замещении через преобразование учтите: текущая строка и позиция курсора в таблице на форме сбрасываются.

Как отсортировать таблицу на управляемой форме?

У ДанныеФормыКоллекции нет метода Сортировать(). Вариантов два: преобразовать в таблицу значений через ДанныеФормыВЗначение(), отсортировать и загрузить обратно, либо задать сортировку в самом запросе, которым таблица заполняется. Второй способ предпочтительнее — сортировка на уровне СУБД быстрее и не требует лишних преобразований.

Итог

Что важно запомнить

Реквизит формы типа «ТаблицаЗначений» — это ДанныеФормыКоллекция, а не обычная таблица. Небольшие объёмы заполняйте через Добавить() в цикле с предварительной Очистить(), готовые таблицы переносите через ЗначениеВДанныеФормы(). Следите за совпадением имён колонок и не делайте серверных вызовов в цикле.