При разработке сложных интерфейсов на платформе 1С:Предприятие 8.3 часто возникает необходимость динамического создания и заполнения таблиц. Типичная ситуация: программист создает реквизиты формы программно, выводит их на экран, а затем пытается заполнить данными. Однако на этом этапе многие сталкиваются с тем, что данные в разных колонках «разъезжаются»: вместо того чтобы заполнять одну и ту же строку, программа создает новые, и таблица начинает «расти вниз». Кроме того, часто возникает вопрос эстетики — как сделать так, чтобы пустые числовые поля не мозолили глаза нулями.
В этой статье мы подробно разберем, почему возникает эффект смещения строк, как правильно адресовать данные в существующей коллекции и каким образом настроить отображение «пустых» значений без нарушения типизации данных.
Рассмотрим ситуацию, описанную в теме. Разработчик сначала заполняет колонку Товар, а затем в другом цикле пытается заполнить колонки Цена и Количество. Проблема кроется в использовании метода Добавить(). Проанализируем фрагмент кода из вопроса:
Для Сч = 0 По Объект.Товары.Количество-1 Цикл
СтрокаТЗ = ЭтотОбъект["Список" + ДаннаяСтраница].Добавить();
СтрокаТЗ.Товар = Объект.Товары[Сч].Номенклатура;
КонецЦикла;
Когда этот цикл отрабатывает, в таблице создается, например, 10 строк. В каждой из них заполнена только колонка Товар. Если далее в коде вы снова вызываете метод Добавить(), чтобы заполнить цены, платформа 1С честно создаст 11-ю, 12-ю и последующие строки. Метод Добавить() всегда создает новую запись в конце коллекции ДанныеФормыКоллекция или ТаблицаЗначений.
Чтобы данные попадали в те же самые строки, нам нужно не добавлять новые, а обращаться к уже существующим по индексу или перебирать их в цикле.
Если структура вашей таблицы подразумевает, что количество строк известно заранее (например, оно совпадает с количеством строк в другом объекте), мы можем использовать обращение по индексу. Рассмотрим, как переписать код правильно:
// Предположим, мы уже заполнили товары и у нас есть 10 строк
// Теперь нам нужно заполнить цены для этих же 10 строк
КоллекцияТаблицы = ЭтотОбъект["Список" + ДаннаяСтраница];
Для Сч = 0 По КоллекцияТаблицы.Количество() - 1 Цикл
// Мы не используем Добавить(), мы берем существующую строку
ТекущаяСтрока = КоллекцияТаблицы[Сч];
// Заполняем нужные колонки
ТекущаяСтрока.Цена = ПолучитьЦену(ТекущаяСтрока.Товар);
ТекущаяСтрока.Количество = 1;
КонецЦикла;
В этом случае данные будут записываться строго в те строки, которые уже есть в таблице, и никакого «смещения вниз» не произойдет.
Если нам не важен индекс, а нужно просто пройтись по всей таблице и дозаполнить пустые поля, удобнее использовать цикл Для каждого. Проанализируем ситуацию, когда у нас уже есть сформированная таблица:
КоллекцияТаблицы = ЭтотОбъект["Список" + ДаннаяСтраница];
Для Каждого СтрокаТЗ Из КоллекцияТаблицы Цикл
// Если колонка создана динамически, к ней можно обращаться через []
ИмяКолонкиЦена = "Цена" + НомерПоставщика;
СтрокаТЗ[ИмяКолонкиЦена] = ДанныеПоставщика.Цена;
КонецЦикла;
Важный момент: Если вы работаете с динамически созданными реквизитами формы (как в сообщении 5), помните, что обращение к ним через точку СтрокаТЗ.ИмяРеквизита может не сработать, если имя формируется строкой. Всегда используйте квадратные скобки СтрокаТЗ["ИмяРеквизита"] для надежности.
Автор вопроса спрашивает: «как сделать поле пустым без всяких 0». Здесь важно понимать механику типов данных в 1С. Если колонка имеет тип Число, она не может быть «абсолютно пустой». По умолчанию значением числового типа является 0. Если тип Строка — это пустая строка "".
Пытаться программно записать туда Неопределено или NULL в типизированную колонку — плохая практика, которая может привести к ошибкам при расчетах или сортировке. Правильный подход — использовать настройки **отображения** на уровне интерфейса.
Способ 1: Использование формата в элементе формы
Чтобы пользователь не видел нули, нам нужно настроить свойство Формат у элемента формы (поля ввода), который отображает эти данные. В строке формата следует указать параметр ЧН=0 (Число Ноль равно пустоте). Рассмотрим, как это сделать программно при создании элемента:
// При создании программного поля формы
НовоеПоле = Элементы.Добавить(ИмяПоля, Тип("ПолеФормы"), Род);
НовоеПоле.ПутьКДанным = "Список." + ИмяРеквизита;
НовоеПоле.Вид = ВидПоляФормы.ПолеВвода;
// Устанавливаем формат отображения, чтобы скрыть нули
НовоеПоле.Формат = "ЧН=0";
Способ 2: Отметка незаполненного
Если вам нужно, чтобы поле выглядело пустым, пока пользователь сам не введет значение, можно использовать свойство АвтоОтметкаНезаполненного. Это подсветит поле, если оно равно значению по умолчанию (например, 0), но при этом визуально оно может выглядеть чистым в зависимости от настроек темы оформления.
В сообщении 5 автор совершает критическую ошибку производительности — вызывает метод ИзменитьРеквизиты() внутри цикла. Разберем, почему это плохо. Каждый вызов этого метода заставляет сервер полностью перестроить структуру формы и передать огромный объем данных на клиент. Если у вас 50 колонок, форма будет перестраиваться 50 раз, что вызовет сильные «тормоза» интерфейса.
Рассмотрим правильный алгоритм работы с динамическими реквизитами:
ДобавляемыеРеквизиты.РеквизитФормы.ИзменитьРеквизиты(ДобавляемыеРеквизиты) один раз после завершения цикла.Если ваши данные уже подготовлены в объекте ТаблицаЗначений на сервере, и имена колонок в ТЗ совпадают с именами реквизитов в ДанныеФормыКоллекция, самым эффективным способом будет использование метода Загрузить(). Это работает в десятки раз быстрее, чем перебор строк в цикле 1С.
// ТЗДанных - это объект ТаблицаЗначений с колонками Товар, Цена, Количество
// СписокТоваров - это Реквизит Формы (ДанныеФормыКоллекция)
ЭтаФорма.СписокТоваров.Загрузить(ТЗДанных);
Этот метод полностью очищает текущую таблицу формы и заполняет её данными из ТЗ. Это идеальный вариант, если вы формируете таблицу «с нуля» при открытии формы или нажатии кнопки.
Для корректной работы с табличными частями и динамическими таблицами на форме важно помнить:
Добавить() — только для создания новых строк.Таблица[Индекс] — для редактирования существующих данных.Формат (параметр ЧН=), а не через попытку очистить значение в коде.ИзменитьРеквизиты, собирая изменения в массив.Применяя эти правила, вы создадите быстрый, надежный и чистый интерфейс, который будет предсказуемо работать с любыми объемами данных.