Добавление колонок в ТаблицуЗначений: методы и код
Содержание
Колонка в ТаблицаЗначений добавляется одной строкой: ТЗ.Колонки.Добавить("Имя"). Метод живёт не у самой таблицы, а у коллекции её колонок — свойства Колонки. Поэтому если искать у объекта метод с именем ДобавитьКолонку, его там нет: правильный вызов — ТЗ.Колонки.Добавить(...).
У метода четыре параметра: имя, тип значения, заголовок и ширина. Обязателен только первый. Ниже — все варианты: простой тип, составной тип через ОписаниеТипов, добавление колонок в цикле, копирование структуры из другой таблицы, вставка в нужную позицию и ошибки, на которые чаще всего натыкаются.
Код одинаково работает в обычном и управляемом приложении, на сервере и на клиенте — ТаблицаЗначений создаётся где угодно, кроме тонкого клиента
без вызова на сервере.
Базовый вызов Колонки.Добавить
Создаём таблицу и добавляем колонки:
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номенклатура");
ТЗ.Колонки.Добавить("Количество");
ТЗ.Колонки.Добавить("Сумма");
Полная сигнатура метода:
ТЗ.Колонки.Добавить(<Имя>, <ТипЗначения>, <Заголовок>, <Ширина>)
Имя— идентификатор колонки, по нему обращаются в коде. Обязательный параметр.ТипЗначения— объектОписаниеТипов. Если не задать, колонка примет значение любого типа.Заголовок— строка, которая показывается в шапке колонки на форме и в табличном документе.Ширина— число, ширина колонки в символах при выводе.
Метод возвращает добавленную колонку, поэтому её свойства можно донастроить сразу:
Колонка = ТЗ.Колонки.Добавить("Цена");
Колонка.Заголовок = "Цена за единицу";
Колонка.Ширина = 12;
Имя и заголовок — разные вещи. В имени нельзя использовать пробелы и спецсимволы, оно подчиняется правилам идентификатора. Всё «человеческое» — пробелы, знаки, единицы измерения — выносите в заголовок.
Указание типа колонки через ОписаниеТипов
Чаще всего тип колонки нужно ограничить — тогда платформа контролирует вводимые значения и правильно показывает их на форме. Тип задаётся объектом ОписаниеТипов:
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"));
ТЗ.Колонки.Добавить("Комментарий", Новый ОписаниеТипов("Строка"));
Для ссылочных типов имя пишется полностью:
ТЗ.Колонки.Добавить("Товар", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТЗ.Колонки.Добавить("Заказ", Новый ОписаниеТипов("ДокументСсылка.ЗаказКлиента"));
Квалификаторы: разрядность, длина, части даты
Голого имени типа часто мало. Для числа задают разрядность и число знаков после запятой, для строки — длину, для даты — её состав. Это делают квалификаторы:
// Число 15 знаков, 2 из них дробные
КвалЧисла = Новый КвалификаторыЧисла(15, 2);
ТЗ.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", КвалЧисла));
// Строка не длиннее 100 символов
КвалСтроки = Новый КвалификаторыСтроки(100);
ТЗ.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка", , КвалСтроки));
// Дата без времени
КвалДаты = Новый КвалификаторыДаты(ЧастиДаты.Дата);
ТЗ.Колонки.Добавить("ДатаОтгрузки", Новый ОписаниеТипов("Дата", , , КвалДаты));
Порядок параметров в строковом конструкторе ОписаниеТипов такой: сначала типы строкой, потом квалификатор числа, квалификатор строки и квалификатор даты. Пустые позиции пропускают запятой — поэтому у строки две запятые перед квалификатором, у даты — три.
Если задать колонке тип Число без квалификатора, разрядность дробной части будет нулевой, и дробные значения округлятся до целого при записи. Для сумм и количеств всегда указывайте КвалификаторыЧисла.
Составные и неограниченные типы
Когда в колонке могут лежать значения разных типов, собираем составной тип. Строковый конструктор принимает несколько типов через запятую:
ТЗ.Колонки.Добавить("Значение", Новый ОписаниеТипов("Число, Строка, Дата"));
Либо через массив типов — так удобнее, когда типы вычисляются программно:
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Число"));
МассивТипов.Добавить(Тип("Булево"));
СоставнойТип = Новый ОписаниеТипов(МассивТипов);
ТЗ.Колонки.Добавить("Флаг", СоставнойТип);
Составной тип нужен не только для «число или строка». Частый случай — колонка, в которой может лежать ссылка на документ любого вида: заказ, реализация, счёт. Тогда в тип добавляют несколько ссылочных типов:
ТЗ.Колонки.Добавить("Основание",
Новый ОписаниеТипов("ДокументСсылка.ЗаказКлиента, ДокументСсылка.РеализацияТоваровУслуг"));
Если тип не указывать вовсе, колонка будет принимать значение любого типа — это и есть «неограниченный» вариант. Он удобен для временных и промежуточных таблиц, но на форме такая колонка редактируется хуже: платформа не знает, какой элемент управления подставить. Для данных, которые показываются пользователю, тип лучше задавать явно.
Имя и заголовок: обращение к колонке
К колонке в коде обращаются по имени — тремя способами, все равнозначны:
ТЗ.Колонки.Сумма.Заголовок = "Сумма, руб.";
ТЗ.Колонки["Сумма"].Заголовок = "Сумма, руб.";
ТЗ.Колонки.Найти("Сумма").Заголовок = "Сумма, руб.";
У колонки есть свойства Имя, Заголовок, Ширина, ТипЗначения, ПолныйЗаголовок, Формат и ФорматРедактирования. Переименовать колонку после создания нельзя — свойство Имя только для чтения. Если имя нужно поменять, добавляют новую колонку и переносят в неё значения, старую удаляют.
Имена колонок нечувствительны к регистру. Колонки Сумма и сумма считаются одной и той же — попытка добавить вторую вызовет ошибку. Это частая причина падения кода, который формирует имена колонок автоматически.
Добавление колонок программно в цикле
Классический сценарий — таблица с колонками по периодам, когда число периодов заранее неизвестно. Имена формируются на лету:
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
Для Месяц = 1 По 12 Цикл
ИмяКолонки = "Месяц_" + Месяц;
Заголовок = Формат(Дата(2024, Месяц, 1), "ДФ=MMMM");
ТЗ.Колонки.Добавить(ИмяКолонки, Новый ОписаниеТипов("Число"), Заголовок);
КонецЦикла;
Имя здесь — служебное (Месяц_1, Месяц_2), а читаемое название месяца уходит в заголовок. Число приклеивается к строке оператором +, потому что Месяц — это целое без дробной части, лишних символов не добавит.
Заполнение уже существующих строк
Когда колонку добавляют к таблице, в которой уже есть строки, эти строки получают значение по умолчанию для указанного типа: ноль для числа, пустую строку для строки, пустую дату для даты. Если колонка без типа — значения будут Неопределено.
Нужное содержимое заполняют отдельным проходом:
ТЗ.Колонки.Добавить("Остаток", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
Для Каждого Строка Из ТЗ Цикл
Строка.Остаток = Строка.Приход - Строка.Расход;
КонецЦикла;
Быстрое заполнение колонки из массива
Когда значения колонки уже лежат в массиве, перебирать строки необязательно — есть метод ЗагрузитьКолонку. Он берёт массив и раскладывает его по строкам таблицы в порядке следования. Число элементов массива должно совпадать с числом строк:
ТЗ.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
ТЗ.ЗагрузитьКолонку(МассивЦен, "Цена");
Обратная операция — ВыгрузитьКолонку: возвращает массив значений одной колонки. Удобно, когда из таблицы нужно вытащить, например, все ссылки для запроса:
МассивТоваров = ТЗ.ВыгрузитьКолонку("Товар");
Так добавление колонки и её наполнение занимают две строки вместо цикла. На больших таблицах это ещё и быстрее: один вызов платформы вместо тысяч присваиваний в цикле встроенного языка.
Само добавление колонки — операция дешёвая независимо от размера таблицы: меняется только описание структуры. Время съедает заполнение строк. Если колонок добавляется много и все — в цикле, выносите формирование ОписаниеТипов за пределы цикла, чтобы не пересоздавать его на каждой итерации.
Копирование структуры и перенос колонок между таблицами
Чтобы получить пустую таблицу с теми же колонками, не перечисляя их заново, есть два метода.
СкопироватьКолонки возвращает новую таблицу — только структура, без строк:
ПустаяТЗ = ТЗ.СкопироватьКолонки(); // все колонки
ЧастичнаяТЗ = ТЗ.СкопироватьКолонки("Товар, Сумма"); // только эти две
Скопировать переносит и колонки, и строки; второй параметр ограничивает набор колонок:
КопияСДанными = ТЗ.Скопировать(); // всё целиком
ДвеКолонки = ТЗ.Скопировать( , "Товар, Количество"); // строки есть, колонок две
Объединить колонки двух таблиц
Когда нужно добавить в одну таблицу колонки из другой — например, дополнить таблицу остатков колонками из таблицы цен, — перебирают коллекцию колонок источника и добавляют недостающие:
Для Каждого Колонка Из ТЗЦены.Колонки Цикл
Если ТЗОстатки.Колонки.Найти(Колонка.Имя) = Неопределено Тогда
ТЗОстатки.Колонки.Добавить(
Колонка.Имя,
Колонка.ТипЗначения,
Колонка.Заголовок,
Колонка.Ширина);
КонецЕсли;
КонецЦикла;
Проверка через Найти обязательна: без неё при совпадении имён код упадёт на дубликате. Этот же приём собирает сводную таблицу из нескольких источников.
Вставка в позицию, порядок и удаление колонок
Добавить всегда ставит колонку в конец. Чтобы вставить её в начало или в середину, используют Вставить с индексом (нумерация с нуля):
ТЗ.Колонки.Вставить(0, "Период", Новый ОписаниеТипов("Дата")); // первой колонкой
Передвинуть уже существующую колонку:
ТЗ.Колонки.Сдвинуть("Сумма", -1); // на одну позицию влево
Удалить колонку можно по имени, по индексу или по самой колонке:
ТЗ.Колонки.Удалить("Цена");
ТЗ.Колонки.Удалить(0);
ТЗ.Колонки.Удалить(ТЗ.Колонки.Найти("Цена"));
Узнать число колонок — ТЗ.Колонки.Количество(), индекс колонки — ТЗ.Колонки.Индекс(Колонка). Порядок колонок в коллекции совпадает с порядком вывода на форме и в табличном документе.
Для ДеревоЗначений всё работает точно так же: у него тоже есть свойство Колонки с методом Добавить, те же параметры и те же правила по именам и типам. Разница только в том, что строки дерева образуют иерархию, а набор колонок — общий для всех уровней. Поэтому приёмы из этой статьи переносятся на дерево без изменений.
Частые ошибки при добавлении колонок
Ошибки повторяются из проекта в проект — вот те, что встречаются чаще всего.
- 🔁 Дубликат имени. «Колонка с таким именем уже существует» — имя уже занято, в том числе в другом регистре. Перед добавлением в цикле проверяйте
Колонки.Найти(Имя) = Неопределено. - ✍️ Пробел или символ в имени. Имя — это идентификатор: только буквы, цифры и подчёркивание, первый символ не цифра. «Сумма, руб.» в имени недопустима — отправляйте такой текст в заголовок.
- 🧩 Нет типа — странности на форме. Колонка без
ОписаниеТиповпринимает любой тип, но на управляемой форме редактируется плохо. Для видимых пользователю данных тип задавайте явно. - 🔢 Число без дробной части.
Новый ОписаниеТипов("Число")без квалификатора округляет значения до целого. Для сумм —Новый КвалификаторыЧисла(15, 2), для количеств —(15, 3). - 🪟 Колонка на управляемой форме не появляется. Таблица на форме — это не
ТаблицаЗначений, а данные формы. Добавление колонки в реквизит с типомТаблицаЗначенийна лету требует методаИзменитьРеквизитыформы, иначе колонка в структуре есть, а в интерфейсе её нет.
Частые вопросы
Можно ли добавить колонку в таблицу на управляемой форме во время работы?
ИзменитьРеквизиты, передав ему добавляемые реквизиты-колонки, а затем связать их с элементом таблицы. Сами по себе колонки, добавленные в ТаблицаЗначений-реквизит обычным Колонки.Добавить, в интерфейсе не отобразятся.Чем Скопировать отличается от СкопироватьКолонки?
СкопироватьКолонки возвращает новую таблицу только со структурой колонок, без строк. Скопировать переносит и колонки, и данные. Если нужна пустая таблица той же формы — берите СкопироватьКолонки.Как задать колонке сразу несколько допустимых типов?
Новый ОписаниеТипов("Число, Строка") строкой или через массив объектов Тип. Такая колонка примет значение любого из перечисленных типов.Что будет, если имя колонки совпадёт с уже существующим?
Сумма и сумма конфликтуют. Перед добавлением проверяйте Колонки.Найти(Имя).Обязательно ли указывать тип колонки?
ОписаниеТипов колонка принимает значение любого типа. Для промежуточных расчётов это нормально, но для данных на форме тип лучше задать — платформа подберёт правильное поле ввода и проконтролирует значения.Как перебрать имена всех колонок таблицы?
Колонки обходится циклом Для Каждого: Для Каждого Колонка Из ТЗ.Колонки Цикл ... КонецЦикла, внутри доступно Колонка.Имя, Колонка.Заголовок, Колонка.ТипЗначения. Так удобно проверять структуру перед выгрузкой или сравнивать две таблицы по набору колонок.