ТабличныйДокумент в управляемой форме: очистка, удаление строк и перезаполнение без ошибок
Содержание
Табличный документ в 1С 8.3 очищают одной строкой: ТабДок.Очистить(). В тонком клиенте этот вызов работает и в процедуре &НаКлиенте, и в &НаСервере, если ТабДок — реквизит формы типа ТабличныйДокумент. А вот заполнить документ заново из макета на клиенте нельзя: макеты доступны только на сервере, поэтому очистку и вывод обычно делают в одной серверной процедуре.
Типичная боль выглядит так: кнопка «Сформировать» нажата второй раз, а новый отчёт дописался под старым. Или код из обычного приложения перенесли в управляемую форму, и он перестал компилироваться. Оба случая решаются правильным разделением очистки и вывода между клиентом и сервером, плюс парой приёмов для удаления строк, колонок и именованных областей.
Как устроен табличный документ в тонком клиенте
В тонком клиенте форма живёт на двух сторонах. Данные формы, включая реквизит типа ТабличныйДокумент, передаются между клиентом и сервером при каждом серверном вызове с контекстом. На экране документ показывает элемент формы — поле табличного документа.
Из этого следуют три практических правила:
- 📄 Реквизит и элемент — разные вещи. Очищают реквизит (
ТабДок), а не элемент (Элементы.ТабДок). У элемента нет методаОчистить(). - 🖥️ Макеты — только на сервере.
ПолучитьМакет()у объекта или менеджера иПолучитьОбщийМакет()в тонком клиенте недоступны. Отсюда и большинство ошибок при переносе старого кода. - 🔁 Каждый вызов
&НаСерверегоняет документ туда и обратно. Если в документе десятки тысяч строк, это заметно по скорости.
Сам объект ТабличныйДокумент на клиенте доступен: можно читать ячейки, удалять строки, очищать. Нельзя только достать макет конфигурации.
| Действие | На клиенте | На сервере |
|---|---|---|
ТабДок.Очистить() | да | да |
ТабДок.УдалитьОбласть(...) | да | да |
Чтение ячеек через Область(...) | да | да |
ПолучитьМакет(), ПолучитьОбщийМакет() | нет | да |
| Запрос к базе для заполнения | нет | да |
Метод Очистить(): базовая очистка содержимого
Самый частый сценарий — перед повторным формированием отчёта стереть всё, что было выведено раньше. Делают это первой строкой серверной процедуры заполнения:
&НаКлиенте
Процедура Сформировать(Команда)
СформироватьНаСервере();
КонецПроцедуры
&НаСервере
Процедура СформироватьНаСервере()
ТабДок.Очистить();
Макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет");
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
ТабДок.Вывести(ОбластьШапка);
Запрос = Новый Запрос("ВЫБРАТЬ Наименование ИЗ Справочник.Номенклатура");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ОбластьСтрока.Параметры.Наименование = Выборка.Наименование;
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
КонецПроцедуры
Пример для обработки или отчёта с основным реквизитом Объект. В форме документа или справочника вместо РеквизитФормыВЗначение("Объект") вызывают модуль менеджера: Справочники.Номенклатура.ПолучитьМакет("Макет").
Если нужно просто стереть документ без перезаполнения, например по кнопке «Очистить», сервер не нужен:
&НаКлиенте
Процедура ОчиститьРезультат(Команда)
ТабДок.Очистить();
КонецПроцедуры
Такой вызов не тратит серверный вызов и срабатывает мгновенно.
Очистить() или Новый ТабличныйДокумент
Иногда вместо очистки пишут ТабДок = Новый ТабличныйДокумент. Для реквизита формы так лучше не делать: новый объект приходит с настройками по умолчанию. Всё, что задано для документа в коде формы раньше (параметры печати, фиксация шапки, ключ параметров печати), придётся выставлять заново.
💡 Для локальной переменной внутри процедуры разницы нет: создайте новый документ, заполните его и только в конце присвойте реквизиту или верните из функции.
Параметры печати (ОриентацияСтраницы, поля, масштаб) и фиксацию строк надёжнее задавать после заполнения, в конце процедуры. Тогда документ выглядит одинаково при первом и повторном формировании.
Удаление строк и колонок из табличного документа программно
Когда нужно убрать только часть содержимого, применяют УдалитьОбласть(). Метод принимает область и тип смещения: что делать с ячейками, стоящими ниже или правее.
Удалить строки
// удалить строки с 5-й по 10-ю, нижние строки поднимутся вверх
Область = ТабДок.Область("R5:R10");
ТабДок.УдалитьОбласть(Область, ТипСмещенияТабличногоДокумента.ПоВертикали);
Удалить колонки
// удалить 3-ю и 4-ю колонки, правые сдвинутся влево
Область = ТабДок.Область("C3:C4");
ТабДок.УдалитьОбласть(Область, ТипСмещенияТабличногоДокумента.ПоГоризонтали);
Удалить всё ниже заданной строки
Бывает, что шапку отчёта на первых строках нужно сохранить, а всё, что под ней, убрать. Номер последней строки берите из свойства ВысотаТаблицы, а не задавайте числом наугад:
ПерваяУдаляемая = 6;
Если ТабДок.ВысотаТаблицы >= ПерваяУдаляемая Тогда
Адрес = "R" + Формат(ПерваяУдаляемая, "ЧГ=0") + ":R" + Формат(ТабДок.ВысотаТаблицы, "ЧГ=0");
ТабДок.УдалитьОбласть(ТабДок.Область(Адрес), ТипСмещенияТабличногоДокумента.ПоВертикали);
КонецЕсли;
Проверка высоты защищает от ошибки на пустом документе: если строк меньше шести, удалять нечего и адрес области получился бы неверным.
Удалить строки по условию
Частая задача — убрать из готового документа пустые строки или строки с нулевой суммой. Удалять нужно снизу вверх, иначе после каждого удаления номера оставшихся строк съезжают и цикл пропускает соседние строки.
&НаКлиенте
Процедура УдалитьПустыеСтроки(Команда)
Высота = ТабДок.ВысотаТаблицы;
Для Сч = 1 По Высота Цикл
НомерСтроки = Высота - Сч + 1;
Ячейка = ТабДок.Область(НомерСтроки, 2, НомерСтроки, 2);
Если ПустаяСтрока(Ячейка.Текст) Тогда
ТабДок.УдалитьОбласть(
ТабДок.Область("R" + Формат(НомерСтроки, "ЧГ=0") + ":R" + Формат(НомерСтроки, "ЧГ=0")),
ТипСмещенияТабличногоДокумента.ПоВертикали);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Обратите внимание на Формат(..., "ЧГ=0"): без него номер строки 1250 превратится в строку с неразрывным пробелом, и адрес R1 250 окажется неверным.
Стереть текст, но оставить строки
Если строки должны остаться на месте, а пропасть должно только содержимое, используйте метод Очистить() у самой области ячеек. У него три необязательных параметра: очищать ли текст, формат и примечания.
Область = ТабДок.Область("R5C1:R10C6");
Область.Очистить(Истина, Ложь, Ложь); // только текст, оформление сохранится
Именованные области и макеты при перезаполнении
Именованная область — участок макета или документа со своим именем: «Шапка», «Строка», «Итоги». В готовом документе такие имена сохраняются, если их задали при выводе или в макете.
Найти и удалить именованную область:
Итоги = ТабДок.Области.Найти("Итоги");
Если Итоги <> Неопределено Тогда
ТабДок.УдалитьОбласть(Итоги, ТипСмещенияТабличногоДокумента.ПоВертикали);
КонецЕсли;
Проверка на Неопределено обязательна. Обращение ТабДок.Области.Итоги к несуществующей области падает с ошибкой.
Частый приём — частично обновить отчёт: удалить табличную часть, а шапку оставить. Порядок такой:
- Найдите номер первой строки табличной части, например по
ВерхняяГраницау именованной области. - Удалите строки от этой границы до
ТабДок.ВысотаТаблицы. - На сервере выведите новые строки из макета через
ТабДок.Вывести(...)— они добавятся в конец, то есть сразу под шапку.
💡 Получайте области макета через ПолучитьОбласть() один раз, до цикла. В цикле меняйте только Параметры и вызывайте Вывести(). Параметры области не сбрасываются сами: если в строке поле может быть пустым, явно присваивайте ему пустое значение, иначе в строку попадёт значение из предыдущей итерации.
Очистка при выводе нескольких документов в один
Печатная форма часто собирается сразу для нескольких выделенных документов: пять накладных подряд в одном табличном документе. Здесь очистка нужна ровно один раз — до начала цикла, а не для каждого документа.
Типичная схема на сервере:
- Очистите итоговый документ:
ТабДок.Очистить(). - В цикле по ссылкам выведите шапку, строки и подвал очередного документа.
- Перед каждым следующим документом, кроме первого, вызовите
ТабДок.ВывестиГоризонтальныйРазделительСтраниц(), чтобы он начинался с новой страницы. - После цикла задайте параметры печати и ключ
КлючПараметровПечати, чтобы платформа запоминала настройки принтера для этой формы.
&НаСервере
Процедура ВывестиНесколько(МассивСсылок)
ТабДок.Очистить();
ПервыйДокумент = Истина;
Для Каждого Ссылка Из МассивСсылок Цикл
Если Не ПервыйДокумент Тогда
ТабДок.ВывестиГоризонтальныйРазделительСтраниц();
КонецЕсли;
ПервыйДокумент = Ложь;
// ... вывод областей для Ссылка ...
КонецЦикла;
ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Портрет;
ТабДок.КлючПараметровПечати = "ПечатьНакладной";
КонецПроцедуры
Если очистку поставить внутрь цикла, на экране останется только последний документ — частая ошибка при переделке печати одного документа в пакетную.
💡 Хотите, чтобы табличная часть не разрывалась посреди строки при переходе на новую страницу? Перед выводом очередной строки проверьте, помещается ли она, методом ТабДок.ПроверитьВывод(...) с массивом выводимых областей. Если не помещается — выведите разделитель страниц и повторите шапку таблицы.
Скорость: большие отчёты в тонком клиенте
На маленьком документе разница между способами незаметна. На отчёте в 20–50 тысяч строк она измеряется секундами. Что реально помогает:
- ⚡ Одна очистка вместо цикла удалений. Если нужно убрать почти всё, быстрее
Очистить()и вывести заново нужное, чем тысячу раз вызыватьУдалитьОбласть(). - 📦 Один серверный вызов. Очистка, запрос и вывод — в одной процедуре
&НаСервере. Не вызывайте сервер в цикле по строкам с клиента. - 🧩 Сборка в локальной переменной. Функция
&НаСервереБезКонтекстастроит документ в переменной и возвращает его. На сервер не уходят остальные данные формы, только результат приходит обратно. - ⏳ Фоновое задание для долгих отчётов. Если формирование занимает больше нескольких секунд, выполняйте его в фоне и кладите результат во временное хранилище через
ПоместитьВоВременноеХранилище(). Форма при этом не зависает.
Пример сборки без контекста формы:
&НаКлиенте
Процедура Сформировать(Команда)
ТабДок = СформироватьДокумент(Период);
КонецПроцедуры
&НаСервереБезКонтекста
Функция СформироватьДокумент(Период)
Результат = Новый ТабличныйДокумент;
// ... запрос и вывод областей в Результат ...
Возврат Результат;
КонецФункции
Здесь очищать нечего: присваивание реквизиту полностью заменяет старый документ.
Если выбрали этот вариант, параметры печати задавайте внутри функции у Результат. Настройки старого документа при присваивании не переносятся.
Показать, что отчёт устарел
Пока идёт долгое формирование, пользователь видит старые цифры и может принять их за актуальные. В управляемой форме у поля табличного документа есть свойство ОтображениеСостояния. Через него поверх поля выводят полупрозрачную пелену и текст вроде «Отчёт не сформирован», а после заполнения убирают её. Так сделано в отчётах типовых конфигураций на БСП.
&НаКлиенте
Процедура ПоказатьНеактуальность()
Состояние = Элементы.ТабДок.ОтображениеСостояния;
Состояние.Видимость = Истина;
Состояние.ДополнительныйРежимОтображения = ДополнительныйРежимОтображения.Неактуальность;
Состояние.Текст = "Отчёт не сформирован. Нажмите «Сформировать».";
КонецПроцедуры
После вывода нового результата выставьте Видимость = Ложь и ДополнительныйРежимОтображения.НеИспользовать.
Частые ошибки при очистке и перезаполнении
Ещё одна неочевидная ситуация — вызов Очистить() у элемента формы: Элементы.ТабДок.Очистить(). Такая строка не скомпилируется, потому что у поля табличного документа нет этого метода. Очищайте реквизит, к которому поле привязано, — его имя видно в свойстве поля ПутьКДанным.
Если пользователю нужно очистить документ вручную
Не всегда очистку пишет программист. Если в поле табличного документа включено редактирование (свойство Редактирование у поля формы), пользователь может выделить ячейки мышью и нажать Delete — текст в выделенных ячейках сотрётся.
Когда это разрешать, а когда нет:
- ✅ Форма-«черновик», где пользователь сам готовит таблицу для печати или выгрузки.
- ❌ Отчёт с расшифровками: ручная правка сбивает связь цифр с данными, а при следующем формировании изменения всё равно пропадут.
Для отчётов надёжнее отдельная команда «Очистить» в командной панели формы, которая вызывает ТабДок.Очистить() на клиенте, и запрет редактирования поля.
Частые вопросы
Сбрасывает ли Очистить() расшифровки ячеек?
Можно ли очистить табличный документ в веб-клиенте так же, как в тонком?
&НаКлиенте и &НаСервере одинаково работает в тонком и веб-клиенте: объект ТабличныйДокумент доступен на клиенте в обоих режимах.Как узнать, что документ уже пустой?
ТабДок.ВысотаТаблицы = 0. У только что очищенного документа высота и ширина таблицы равны нулю.Почему после очистки поле на форме прокручено не в начало?
Элементы.ТабДок.ТекущаяОбласть = ТабДок.Область("R1C1").