Таблица значений в 1С 8.3: создание, заполнение, сортировка и вывод на управляемую форму
Содержание
Чтобы отобразить таблицу значений в 1С на управляемой форме, создайте реквизит формы с типом ТаблицаЗначений, перетащите его в дерево элементов и на сервере перенесите данные методом ЗначениеВРеквизитФормы(ТЗ, "ИмяРеквизита"). Колонки реквизита при этом должны совпадать по именам с колонками вашей таблицы. Для быстрого просмотра без формы подойдёт табличный документ или окно вычисления выражения в отладчике.
Типичная ситуация: разработчик собрал в обработке остатки по складам в таблицу значений, хочет показать её пользователю, а на форме пусто или платформа ругается на тип. Причина почти всегда одна: в тонком клиенте объекта ТаблицаЗначений нет, и работать с ним можно только на сервере. Ниже по порядку: создание, заполнение, настройка колонок, сортировка, визуализация и разбор ошибок.
Создание таблицы значений и описание колонок
Таблица значений — это коллекция строк с заранее заданным набором колонок. Живёт она в памяти и в базу не записывается. Создаётся конструктором, колонки добавляются через коллекцию Колонки.
&НаСервере
Функция НоваяТаблицаОстатков()
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"), "Товар");
ТЗ.Колонки.Добавить("Склад", Новый ОписаниеТипов("СправочникСсылка.Склады"), "Склад");
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)), "Кол-во");
ТЗ.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)), "Сумма, руб.");
Возврат ТЗ;
КонецФункции
Параметры метода Колонки.Добавить() идут в таком порядке:
| № | Параметр | Что задаёт | Обязателен |
|---|---|---|---|
| 1 | Имя | Имя колонки, по нему идёт обращение в коде | да |
| 2 | Тип | Объект ОписаниеТипов | нет |
| 3 | Заголовок | Текст в шапке при выводе | нет |
| 4 | Ширина | Ширина колонки в символах | нет |
Имя колонки подчиняется тем же правилам, что и имя переменной: без пробелов, не с цифры. Человеческий текст «Сумма, руб.» пишите в заголовок, а не в имя.
Если тип не указать, колонка примет значения любого типа. Для расчётов в памяти это удобно, но позже такая колонка создаёт проблемы: в запросе, на форме и при свёртке. Задавайте тип каждой колонке, которую планируете выводить на форму или передавать в запрос.
Как заполнить таблицу значений: запрос и цикл
Из результата запроса
Самый частый и самый быстрый способ. Метод Выгрузить() сам создаёт колонки с именами полей запроса и с типами, взятыми из метаданных.
&НаСервере
Функция ОстаткиПоСкладам(Дата)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура КАК Номенклатура,
| Остатки.Склад КАК Склад,
| Остатки.КоличествоОстаток КАК Количество
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&Дата) КАК Остатки";
Запрос.УстановитьПараметр("Дата", Дата);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Имя регистра здесь условное: подставьте регистр своей конфигурации. Псевдонимы КАК в запросе становятся именами колонок, поэтому давайте их явно.
В цикле
Когда данные приходят не из базы (файл, расчёт, ответ веб-сервиса), строки добавляют вручную:
Стр = ТЗ.Добавить();
Стр.Номенклатура = Товар;
Стр.Количество = 5;
Стр.Сумма = 1250.50;
Если в источнике есть структура с теми же ключами, что и колонки, используйте ЗаполнитьЗначенияСвойств(Стр, Источник). Метод перенесёт совпадающие по имени значения и молча пропустит остальные.
Полезные методы массового заполнения
- 📥
ЗагрузитьКолонку(Массив, "Сумма")— заливает массив значений в колонку построчно, строк должно хватать. - 📤
ВыгрузитьКолонку("Номенклатура")— возвращает массив значений колонки, удобно для параметра запросаВ (&Список). - 📋
Скопировать()— полная копия;СкопироватьКолонки()— пустая таблица с той же структурой. - ➕
ЗаполнитьЗначения(0, "Сумма")— проставить одно значение во все строки колонки.
Типы, заголовки и ограничения колонок
Колонку после создания можно донастроить через её свойства: Имя, Заголовок, Ширина, ТипЗначения. Свойство ТипЗначения только читается, поэтому тип задают сразу при добавлении. Чтобы сменить тип, создают новую колонку, переносят значения и удаляют старую.
Квалификаторы описания типов работают как ограничения:
- 🔢
КвалификаторыЧисла(15, 2)— 15 знаков всего, 2 после запятой. Число 1250,456 превратится в 1250,46. - 🔤
КвалификаторыСтроки(50)— строка обрежется до 50 символов. - 📅
КвалификаторыДаты(ЧастиДаты.Дата)— время отбрасывается, остаётся только дата.
Округление и обрезка происходят при присваивании, без ошибки. Это частая причина «потерянных копеек»: колонка объявлена с квалификатором (15, 0), а в неё пишут суммы с копейками.
Составной тип задаётся строкой через запятую:
Тип = Новый ОписаниеТипов("СправочникСсылка.Контрагенты, СправочникСсылка.ФизическиеЛица");
ТЗ.Колонки.Добавить("Получатель", Тип);
Для частого поиска по одной колонке добавьте индекс: ТЗ.Индексы.Добавить("Номенклатура"). На таблице в десятки тысяч строк поиск НайтиСтроки() по индексированной колонке работает заметно быстрее. Для таблицы из ста строк индекс не нужен.
Сортировка, отбор и свёртка строк в таблице значений
Сортировка
ТЗ.Сортировать("Склад, Сумма Убыв");
По умолчанию порядок возрастающий, Убыв меняет направление для конкретной колонки. Ссылки сортируются по внутреннему представлению, а не по наименованию. Если нужен алфавит по товарам, добавьте в запрос поле Номенклатура.Наименование и сортируйте по нему, либо сортируйте сразу в запросе через УПОРЯДОЧИТЬ ПО.
Отбор
Отдельного «фильтра» у таблицы значений нет, есть три приёма:
| Приём | Что возвращает | Когда брать |
|---|---|---|
НайтиСтроки(Новый Структура("Склад", Склад)) | Массив строк исходной таблицы | Прочитать или изменить найденные строки |
Скопировать(Новый Структура("Склад", Склад)) | Новую таблицу только с подходящими строками | Нужна отдельная таблица для вывода |
Найти(Значение, "Номенклатура") | Первую найденную строку или Неопределено | Проверить, есть ли значение |
Отбор структурой работает только на равенство. Условия «больше», «содержит» и подобные проверяйте в цикле или переносите в запрос.
Свёртка и итоги
ТЗ.Свернуть("Номенклатура", "Количество, Сумма");
Всего = ТЗ.Итог("Сумма");
Свернуть() группирует строки по первой колонке (или списку) и суммирует вторые. Все колонки, не упомянутые ни в одном списке, исчезают. Суммировать можно только числовые колонки: строка или ссылка во втором параметре даст ошибку.
Удаление строк в цикле
При удалении строк обходите таблицу с конца, иначе индексы сдвигаются и часть строк пропускается:
Всего = ТЗ.Количество();
Для Сч = 1 По Всего Цикл
Стр = ТЗ[Всего - Сч];
Если Стр.Количество = 0 Тогда
ТЗ.Удалить(Стр);
КонецЕсли;
КонецЦикла;
Граница Всего запоминается до цикла, а индекс Всего - Сч пробегает от последней строки к нулевой.
Вывод таблицы значений на управляемую форму
Способ 1. Реквизит формы, созданный в конфигураторе
Подходит, когда набор колонок известен заранее.
- Откройте форму в конфигураторе, вкладка
Реквизиты, добавьте реквизит, напримерТаблицаОстатков, типТаблицаЗначений. - Раскройте реквизит и добавьте колонки с теми же именами и типами, что в вашей ТЗ.
- Перетащите реквизит мышью в дерево
Элементы— платформа создаст элемент «Таблица» с полями. - Напишите серверную процедуру заполнения и вызовите её из клиентской команды.
&НаСервере
Процедура ЗаполнитьНаСервере()
ТЗ = ОстаткиПоСкладам(ТекущаяДатаСеанса());
ЗначениеВРеквизитФормы(ТЗ, "ТаблицаОстатков");
КонецПроцедуры
&НаКлиенте
Процедура Заполнить(Команда)
ЗаполнитьНаСервере();
КонецПроцедуры
На клиенте реквизит виден как ДанныеФормыКоллекция: строки можно читать и менять, но методов Свернуть(), Скопировать() и Сортировать() с параметрами ТЗ там нет. Для обратного превращения на сервере есть РеквизитФормыВЗначение("ТаблицаОстатков").
Если колонки реквизита совпадают с колонками ТЗ не полностью, лишние колонки ТЗ просто не попадут на форму, а пустые колонки реквизита останутся пустыми. Ошибки не будет, поэтому проверяйте имена.
Отбор строк на форме задаётся свойством элемента, а не реквизита:
Элементы.ТаблицаОстатков.ОтборСтрок = Новый ФиксированнаяСтруктура("Склад", Склад);
Сбросить отбор — присвоить Неопределено.
Способ 2. Колонки создаются программно
Нужен, когда структура таблицы заранее не известна: универсальная обработка, выгрузка произвольного запроса. Реквизиты добавляются методом ИзменитьРеквизиты(), элементы — через Элементы.Добавить(). Всё выполняется на сервере.
&НаСервере
Процедура ПоказатьПроизвольнуюТЗ(ТЗ)
ИмяТаблицы = "ТаблицаДанных";
НовыеРеквизиты = Новый Массив;
НовыеРеквизиты.Добавить(Новый РеквизитФормы(ИмяТаблицы, Новый ОписаниеТипов("ТаблицаЗначений")));
Для Каждого Колонка Из ТЗ.Колонки Цикл
НовыеРеквизиты.Добавить(Новый РеквизитФормы(Колонка.Имя, Колонка.ТипЗначения, ИмяТаблицы, Колонка.Заголовок));
КонецЦикла;
ИзменитьРеквизиты(НовыеРеквизиты);
ЭлементТаблица = Элементы.Добавить(ИмяТаблицы, Тип("ТаблицаФормы"));
ЭлементТаблица.ПутьКДанным = ИмяТаблицы;
Для Каждого Колонка Из ТЗ.Колонки Цикл
Поле = Элементы.Добавить(ИмяТаблицы + Колонка.Имя, Тип("ПолеФормы"), ЭлементТаблица);
Поле.Вид = ВидПоляФормы.ПолеВвода;
Поле.ПутьКДанным = ИмяТаблицы + "." + Колонка.Имя;
КонецЦикла;
ЗначениеВРеквизитФормы(ТЗ, ИмяТаблицы);
КонецПроцедуры
Повторный вызов с тем же именем упадёт: реквизит уже есть. Перед повторным построением удалите старый реквизит, передав его имя во второй параметр ИзменитьРеквизиты() (массив удаляемых), и удалите элемент через Элементы.Удалить().
Способ 3. Табличный документ
Когда таблицу надо показать «только посмотреть» или распечатать, проще собрать табличный документ на сервере и открыть его на клиенте:
&НаСервере
Функция ТЗВТабличныйДокумент(ТЗ)
ТабДок = Новый ТабличныйДокумент;
НомКол = 0;
Для Каждого Колонка Из ТЗ.Колонки Цикл
НомКол = НомКол + 1;
ТабДок.Область(1, НомКол, 1, НомКол).Текст = ?(ЗначениеЗаполнено(Колонка.Заголовок), Колонка.Заголовок, Колонка.Имя);
КонецЦикла;
НомСтр = 1;
Для Каждого Стр Из ТЗ Цикл
НомСтр = НомСтр + 1;
НомКол = 0;
Для Каждого Колонка Из ТЗ.Колонки Цикл
НомКол = НомКол + 1;
ТабДок.Область(НомСтр, НомКол, НомСтр, НомКол).Текст = Строка(Стр[Колонка.Имя]);
КонецЦикла;
КонецЦикла;
Возврат ТабДок;
КонецФункции
На клиенте: ТЗВТабличныйДокумент(...).Показать("Остатки"). Сама ТЗ на клиент не передаётся, передаётся уже готовый табличный документ, а он в тонком клиенте доступен.
Какой способ выбрать
| Способ | Когда | Минус |
|---|---|---|
| Реквизит из конфигуратора | Колонки известны, нужна правка пользователем | Изменение структуры — правка формы |
| Программные реквизиты | Произвольный набор колонок | Больше кода, сложнее отлаживать |
| Табличный документ | Просмотр, печать, выгрузка в Excel | Данные нельзя редактировать как строки |
Для отчётов с группировками и отборами пользователем есть ещё один путь — система компоновки данных с набором «Объект», куда ТЗ передаётся через внешние наборы данных. Это отдельная большая тема; для простого вывода хватает трёх способов выше.
Отладка: как посмотреть содержимое таблицы
В тонком клиенте нет быстрого «открыть значение» для таблицы значений, поэтому смотрят её в отладчике:
- Поставьте точку останова (
F9) на строке после заполнения ТЗ. - Запустите отладку (
F5), дождитесь остановки. - Выделите имя переменной и откройте окно вычисления выражения (
Shift+F9). - Раскройте переменную: отладчик покажет колонки и строки, для таблицы доступен табличный просмотр.
В выражении можно писать код: ТЗ.Количество(), ТЗ.Итог("Сумма"), ТЗ.ВыгрузитьКолонку("Склад"). Так за секунду проверяется, на каком шаге «потерялись» строки.
Отладку с точками останова ведите на копии базы. Остановка в серверном коде держит открытую транзакцию, если вы внутри записи объекта, и другие пользователи могут упереться в блокировку.
Если отладчик недоступен, временно выведите количество строк сообщением: Сообщить("Строк: " + Формат(ТЗ.Количество(), "ЧН=0; ЧГ=0")). Формат здесь нужен, чтобы 1500 не превратилось в «1 500» и чтобы ноль не стал пустой строкой.
Типичные ошибки при работе с таблицей значений
Новый ТаблицаЗначений стоит в процедуре с директивой &НаКлиенте. Перенесите создание и обработку в процедуру &НаСервере или &НаСервереБезКонтекста.КАК Сумма поле называется КоличествоОстаток или иначе.ЗначениеВРеквизитФормы вызван для другого реквизита. Сверьте имена в отладчике.ОписаниеТипов или заполните ТЗ через Выгрузить() из другого запроса.КвалификаторыЧисла(15, 2).Частые вопросы
Можно ли передать таблицу значений на клиент?
Чем таблица значений отличается от табличной части?
Как выгрузить таблицу значений в Excel?
Записать() с типом ТипФайлаТабличногоДокумента.XLSX, либо пользователь сохранит его из открытого окна.Можно ли хранить таблицу значений в реквизите справочника?
ХранилищеЗначения: Новый ХранилищеЗначения(ТЗ) при записи и Получить() при чтении. Искать и отбирать по содержимому такого реквизита в запросе нельзя.