УдалитьОбласть, обратный цикл и выделенные строки: чистим табличный документ без потерь
Содержание
Строки в табличном документе 1С удаляют методом УдалитьОбласть(): получаете область строк через Область("R5") или Область("R5:R10") и передаёте её вместе с типом смещения ТипСмещенияТабличногоДокумента.ПоВертикали. Строки ниже удалённых поднимаются вверх, высота таблицы уменьшается. Если удаляете несколько строк в цикле, идите снизу вверх, иначе часть строк будет пропущена.
Чаще всего строки удаляют из готовой печатной формы или отчёта: убрать пустые строки, нули или выделенные пользователем позиции. Всё описанное относится к платформе 1С:Предприятие 8.3 и не зависит от конфигурации: табличный документ одинаково работает в БП, ЗУП, УТ и в собственных разработках.
Как устроены строки табличного документа
Табличный документ — это не коллекция строк, как таблица значений или табличная часть документа. У него нет свойства «Строки», нет метода Удалить(Строка) и нельзя обойти его через Для Каждого. Это сетка ячеек, к которой обращаются по координатам.
Ключевые понятия:
- 📐 Область — прямоугольник ячеек. Её получают методом
Область(): по адресу в стиле R1C1, по номерам строк и колонок или по имени области макета. - 📏
ВысотаТаблицы— номер последней заполненной строки.ШиринаТаблицы— то же для колонок. - ↕️ Тип смещения — что делать с соседними ячейками после удаления: поднять снизу (
ПоВертикали) или сдвинуть справа (ПоГоризонтали).
Адреса, которые понадобятся чаще всего:
| Адрес | Что выбирает |
|---|---|
"R5" | всю строку 5 целиком |
"R5:R10" | строки с 5 по 10 |
"R5C1:R5C3" | ячейки 1–3 в строке 5 (не всю строку) |
"C3" | всю колонку 3 |
Разница между "R5" и "R5C1:R5C3" принципиальная. Первая область — строка от края до края. Вторая — прямоугольник, и при его удалении сдвинутся только три колонки, а остальная часть таблицы останется на месте.
Если нужно удалить строку из таблицы значений или табличной части, а не из печатной формы, — это другая задача. Там работает Коллекция.Удалить(Строка), а табличный документ к ней отношения не имеет.
Удаление одной строки и диапазона строк
Минимальный пример — убрать пятую строку:
ТабДок.УдалитьОбласть(ТабДок.Область("R5"), ТипСмещенияТабличногоДокумента.ПоВертикали);
Диапазон удаляется одним вызовом, без цикла:
ТабДок.УдалитьОбласть(ТабДок.Область("R5:R10"), ТипСмещенияТабличногоДокумента.ПоВертикали);
После этого строка, которая была 11-й, становится 5-й. ВысотаТаблицы уменьшится на 6.
Когда номера строк вычисляются, адрес собирайте через Формат() с параметром ЧГ=0. Без него число 1250 превратится в строку с неразрывным пробелом «1 250», и платформа не поймёт адрес:
Процедура УдалитьСтроки(ТабДок, Верх, Низ)
Адрес = СтрШаблон("R%1:R%2", Формат(Верх, "ЧГ=0"), Формат(Низ, "ЧГ=0"));
ТабДок.УдалитьОбласть(ТабДок.Область(Адрес), ТипСмещенияТабличногоДокумента.ПоВертикали);
КонецПроцедуры
Эту процедуру удобно держать в общем модуле: дальше она используется во всех примерах.
Удаление колонок
Логика та же, меняются адрес и направление сдвига:
ТабДок.УдалитьОбласть(ТабДок.Область("C3"), ТипСмещенияТабличногоДокумента.ПоГоризонтали);
Колонки правее третьей сдвинутся влево. Ширина колонок сохраняется вместе с ними.
Всегда указывайте тип смещения явно. Код без второго параметра читается двусмысленно, а при удалении строк нужен именно сдвиг по вертикали. Явный параметр снимает вопрос у того, кто будет сопровождать код после вас.
Удаление строк по условию в цикле
Типичная задача — убрать из готового отчёта пустые строки, строки с нулевыми суммами или строки с определённым текстом. Главное правило: обходите строки снизу вверх.
Почему не сверху вниз. Допустим, нужно удалить строки 5 и 6. Цикл дошёл до пятой и удалил её. Шестая поднялась на место пятой, а счётчик перешёл к шестой — и проверил бывшую седьмую. Строка, которая должна была уйти, осталась в документе.
При обходе снизу удаление затрагивает только строки ниже текущей, а они уже проверены.
Обратный цикл
Границу цикла считаем один раз до его начала, а номер строки вычисляем от неё:
Высота = ТабДок.ВысотаТаблицы;
Для Сч = 0 По Высота - 1 Цикл
НомерСтроки = Высота - Сч;
АдресЯчейки = "R" + Формат(НомерСтроки, "ЧГ=0") + "C1";
Если ПустаяСтрока(ТабДок.Область(АдресЯчейки).Текст) Тогда
УдалитьСтроки(ТабДок, НомерСтроки, НомерСтроки);
КонецЕсли;
КонецЦикла;
При Высота = 40 цикл пройдёт номера 40, 39, … 1. Условие проверяет текст первой колонки — подставьте свою колонку или свою функцию проверки.
Как проверить, что строка пустая целиком
Если под «пустой» понимается строка без текста во всех ячейках, вынесите проверку в функцию:
Функция СтрокаПустая(ТабДок, НомерСтроки)
Для НомерКолонки = 1 По ТабДок.ШиринаТаблицы Цикл
Адрес = СтрШаблон("R%1C%2", Формат(НомерСтроки, "ЧГ=0"), Формат(НомерКолонки, "ЧГ=0"));
Если Не ПустаяСтрока(ТабДок.Область(Адрес).Текст) Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
КонецФункции
Функция выходит на первой же заполненной ячейке, поэтому на обычных строках работает быстро. Дольше всего она проверяет действительно пустые строки — все колонки подряд.
Учтите: свойство Текст возвращает то, что видно в ячейке. Ячейка с числом 0 и форматом, который скрывает нули, может выглядеть пустой, но Текст у неё зависит от формата. Если отбор идёт по суммам, надёжнее проверять данные до вывода, а не текст после.
Массовое удаление строк и производительность
Каждый вызов УдалитьОбласть() сдвигает всё, что ниже. На отчёте в 50 строк это незаметно. На документе в десятки тысяч строк, из которого убирают каждую вторую, построчное удаление превращается в заметную паузу.
Три способа ускорить работу — от простого к радикальному.
1. Удалять сериями, а не по одной строке
Подряд идущие строки на удаление собираем в серию и удаляем одним вызовом. Обход по-прежнему снизу вверх:
Высота = ТабДок.ВысотаТаблицы;
НизСерии = 0; // 0 — серия не начата
Для Сч = 0 По Высота - 1 Цикл
НомерСтроки = Высота - Сч;
Если СтрокаПустая(ТабДок, НомерСтроки) Тогда
Если НизСерии = 0 Тогда
НизСерии = НомерСтроки;
КонецЕсли;
ВерхСерии = НомерСтроки;
ИначеЕсли НизСерии > 0 Тогда
УдалитьСтроки(ТабДок, ВерхСерии, НизСерии);
НизСерии = 0;
КонецЕсли;
КонецЦикла;
Если НизСерии > 0 Тогда
УдалитьСтроки(ТабДок, ВерхСерии, НизСерии);
КонецЕсли;
Если пустыми оказались строки 12, 13, 14 и 30, выйдет два вызова: R30:R30 и R12:R14. Серию удаляем в момент, когда встретили заполненную строку выше неё, — к этому моменту все её строки уже проверены. Блок после цикла закрывает серию, которая дошла до первой строки.
2. Собрать новый документ из нужных строк
Когда удалить надо больше, чем оставить, проще не удалять, а копировать. Создайте пустой табличный документ и выводите в него только подходящие строки через ПолучитьОбласть() и Вывести():
Результат = Новый ТабличныйДокумент;
Для НомерСтроки = 1 По ТабДок.ВысотаТаблицы Цикл
Если Не СтрокаПустая(ТабДок, НомерСтроки) Тогда
Результат.Вывести(ТабДок.ПолучитьОбласть("R" + Формат(НомерСтроки, "ЧГ=0")));
КонецЕсли;
КонецЦикла;
Здесь цикл прямой: исходный документ не меняется, номера строк не плывут. После вывода перенесите в новый документ настройки печати — ориентацию страницы, поля, масштаб. Они хранятся в самом документе и при выводе областей не копируются.
3. Не выводить лишнее вовсе
Самый быстрый способ — не удалять строки после формирования. Если форму собираете вы сами из макета, проверяйте условие перед Вывести(). Если отчёт построен на системе компоновки данных, задайте отбор в настройках: компоновщик не выведет лишние записи, и итоги посчитаются уже без них. Удаление строк из готового результата СКД итоги не пересчитывает — суммы в группировках останутся прежними.
Удаление строк вручную: в режиме 1С:Предприятие и в макете
Не всегда нужен код. Если надо разово поправить сохранённый файл или макет печатной формы, строки удаляют мышью.
Сохранённый файл MXL в режиме 1С:Предприятие:
- Откройте файл через
Главное меню → Файл → Открыть. - Выделите строки щелчком по их номерам слева. Несколько строк — с зажатой
Shift, разрозненные — сCtrl. - Вызовите контекстное меню правой кнопкой по номеру строки и выберите удаление. Строки ниже поднимутся.
- Сохраните файл.
Макет в Конфигураторе правится так же: откройте макет, выделите строки по номерам и удалите их через контекстное меню.
В макете у строк бывают имена областей («Шапка», «Строка», «Подвал»), а модуль печати обращается к ним через ПолучитьОбласть("Строка"). Удалите строки, на которых держится именованная область, — и печать упадёт с ошибкой при обращении к области. Перед удалением посмотрите имена областей слева от таблицы. Типовые макеты лучше менять через расширение конфигурации, а не в основной конфигурации.
Готовый отчёт в типовой конфигурации может быть открыт только на просмотр. Тогда сохраните результат в MXL или Excel и правьте копию.
Табличный документ на управляемой форме и в веб-клиенте
На управляемой форме табличный документ — это реквизит формы типа ТабличныйДокумент, который отображается элементом «Поле табличного документа». Объект доступен и на клиенте, и на сервере, но где удалять строки — разница ощутимая.
Удаление выделенных пользователем строк
Пользователь выделил строки в поле и нажал вашу кнопку. Выделение лежит в свойстве ВыделенныеОбласти. Областей может быть несколько, и удалять их тоже надо снизу вверх — от области с наибольшим номером верхней строки:
&НаКлиенте
Процедура УдалитьВыделенные(Команда)
Границы = Новый Соответствие;
Верхи = Новый СписокЗначений;
Для Каждого Обл Из ТабДок.ВыделенныеОбласти Цикл
Если ТипЗнч(Обл) <> Тип("ОбластьЯчеекТабличногоДокумента") Тогда
Продолжить;
КонецЕсли;
Если Обл.ТипОбласти <> ТипОбластиЯчеекТабличногоДокумента.Строки Тогда
Продолжить;
КонецЕсли;
Границы.Вставить(Обл.Верх, Обл.Низ);
Верхи.Добавить(Обл.Верх);
КонецЦикла;
Верхи.СортироватьПоЗначению(НаправлениеСортировки.Убыв);
Для Каждого Элемент Из Верхи Цикл
УдалитьСтроки(ТабДок, Элемент.Значение, Границы[Элемент.Значение]);
КонецЦикла;
КонецПроцедуры
Код берёт только области, выделенные по номерам строк целиком. Прямоугольник ячеек и рисунки он пропускает, чтобы случайно не сдвинуть половину таблицы. Если пользователь выделил одни и те же строки дважды, перекрывающиеся области лучше объединить заранее.
УдалитьСтроки здесь должна быть доступна на клиенте: объявите её в модуле формы с &НаКлиенте или в общем модуле с флагом «Клиент».
Где выполнять массовую обработку
Реквизит формы при вызове серверной процедуры передаётся на сервер и обратно целиком. Для отчёта на 20 тысяч строк это заметный объём, а цикл с проверкой каждой ячейки на клиенте, особенно в веб-клиенте, работает медленнее, чем на сервере.
Практичная схема:
- 🖥️ Тяжёлую чистку делайте на сервере — в той же процедуре, где документ формируется. Тогда он уйдёт на клиент один раз, уже без лишних строк.
- 🖱️ На клиенте оставьте точечные операции — удаление пары выделенных строк по кнопке. Ради них гонять документ на сервер нет смысла.
- 🌐 В веб-клиенте проверяйте поведение отдельно: выделение и прокрутка большого документа там заметно медленнее, чем в тонком клиенте.
Если документ должен быть недоступен для ручной правки, установите у поля табличного документа свойство «Только просмотр» — пользователь не удалит строки сам.
Ошибки при удалении строк табличного документа
| Симптом | Причина | Что исправить |
|---|---|---|
| Удаляется не каждая строка, часть остаётся | Цикл идёт сверху вниз, строки сдвигаются под счётчиком | Обход от ВысотаТаблицы к 1 |
| Таблица «поехала»: колонки справа съехали относительно левых | Удалялся прямоугольник R5C1:R5C3, а не строка R5 | Адрес строки без колонок |
Ошибка при вызове Область() на больших номерах | Номер склеен в адрес без Формат(…, "ЧГ=0"), в строке появился пробел-разделитель разрядов | Формат или СтрШаблон с форматированными числами |
| Итоги в отчёте не сходятся с видимыми строками | Строки убраны из результата СКД после вывода | Отбор в настройках компоновки |
| Печать падает на обращении к области | В макете удалены строки именованной области | Восстановить область или поправить модуль печати |
| После удаления «уплыли» номера, сохранённые заранее | Номера строк запомнены до удаления, а потом использованы | Удалять снизу вверх или пересчитывать номера |
Последний случай частый в доработках: в одном цикле собирают массив номеров «на удаление», а удаляют в порядке возрастания. Первое удаление сдвигает все последующие номера. Отсортируйте массив по убыванию — и проблема уходит.
Частые вопросы
Можно ли отменить удаление строк в коде?
Сохраняется ли оформление строк, которые поднялись после удаления?
Как удалить все строки сразу?
Очистить() полностью очищает табличный документ. Если нужно оставить шапку, удалите диапазон от первой строки после шапки до ВысотаТаблицы.Как найти строку с нужным текстом, чтобы её удалить?
НайтиТекст() возвращает область найденной ячейки. Номер строки берите из её свойства Верх и передавайте в удаление.Влияет ли удаление строк на сохранённый в Excel файл?
Записать() в файл попадает текущее состояние документа, без удалённых строк.