Одной из классических задач при разработке в среде 1С:Предприятие 7.7 является программная очистка табличной части документа от строк, не соответствующих определенным критериям. Начинающие разработчики часто сталкиваются с проблемой "пропуска" строк при удалении в обычном цикле. В этой статье мы подробно разберем, почему так происходит, и рассмотрим наиболее эффективные методы решения этой задачи.
Прежде чем перейти к коду, давайте проанализируем ситуацию. Представьте, что мы обходим таблицу с первой строки по последнюю. Как только мы вызываем метод УдалитьСтроку(), все последующие строки поднимаются на одну позицию вверх. Строка, которая была третьей, становится второй. Однако счетчик цикла в следующей итерации переходит к третьему индексу, и бывшая третья (а ныне вторая) строка оказывается необработанной. Именно поэтому при простом переборе "сверху вниз" часть строк, подлежащих удалению, остается в таблице.
Рассмотрим способы, которые позволяют избежать этой логической ловушки.
Это самый простой и надежный метод. Если мы начнем удаление с последней строки и будем двигаться к первой, сдвиг нижележащих строк (которых уже нет или которые мы уже обработали) никак не повлияет на индексы тех строк, которые нам еще предстоит проверить. Проанализируем пример кода:
НомСтроки = КоличествоСтрок();
Пока НомСтроки > 0 Цикл
ПолучитьСтрокуПоНомеру(НомСтроки);
// Проверяем условие, например, цена меньше 100
Если Цена < 100 Тогда
УдалитьСтроку(НомСтроки);
КонецЕсли;
НомСтроки = НомСтроки - 1;
КонецЦикла;
Важный нюанс: В 1С 7.7 при использовании УдалитьСтроку() без параметров удаляется текущая выбранная строка. Если же мы работаем в цикле Пока, важно явно управлять счетчиком НомСтроки, уменьшая его на каждой итерации, независимо от того, было удаление или нет.
Для больших табличных частей часто удобнее и быстрее работать не напрямую с объектом документа, а с выгруженной копией данных. Это позволяет избежать лишних обновлений экранной формы в процессе обработки. Разберем этот алгоритм по шагам:
ТаблицаЗначений.Пример реализации:
ТЗ = СоздатьОбъект("ТаблицаЗначений");
ВыгрузитьТабличнуюЧасть(ТЗ);
УдалитьСтроки(); // Очищаем ТЧ документа полностью
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
// Условие: оставляем только товар с ценой >= 100
Если ТЗ.Цена >= 100 Тогда
НоваяСтрока();
Товар = ТЗ.Товар;
Количество = ТЗ.Количество;
Цена = ТЗ.Цена;
Сумма = ТЗ.Сумма;
// Переносим все необходимые реквизиты
КонецЕсли;
КонецЦикла;
Этот метод считается более "чистым" с точки зрения архитектуры, так как он минимизирует количество операций удаления и пересчета итогов внутри самого документа.
Если вы все же предпочитаете обходить таблицу от начала к концу, вам необходимо вручную управлять индексом. Суть заключается в следующем: если строка удалена, мы не увеличиваем счетчик, так как на место удаленной строки уже встала следующая. Если строка оставлена — переходим к следующему номеру.
Посмотрим на пример:
Ном = 1;
Пока Ном <= КоличествоСтрок() Цикл
ПолучитьСтрокуПоНомеру(Ном);
Если Цена < 100 Тогда
УдалитьСтроку(Ном);
// Индекс не увеличиваем, так как следующая строка "прыгнула" на текущий индекс
Иначе
Ном = Ном + 1; // Переходим дальше
КонецЕсли;
КонецЦикла;
Для очень больших объемов данных (тысячи строк) постоянное удаление может тормозить систему. В таких случаях мы можем применить хитрость с сортировкой. Выясним причину эффективности этого метода: операция КоличествоСтрок(НовоеЗначение) работает мгновенно, "отсекая" хвост таблицы.
Алгоритм действий:
ФлагУдаления.ФлагУдаления по возрастанию. Все строки с "1" окажутся внизу.КоличествоСтрок().ЗагрузитьТабличнуюЧасть().При реализации удаления в форме документа следует учитывать несколько важных аспектов:
Позиционирование: Помните, что после метода ЗагрузитьТабличнуюЧасть() или массового удаления строк текущее позиционирование курсора в форме может сбиться. Если пользователю важно остаться на конкретной строке, этот момент нужно обрабатывать отдельно через АктивизироватьСтроку().
Визуальное мерцание: Если вы удаляете много строк непосредственно в форме, интерфейс может "моргать". Для ускорения процесса и улучшения визуального восприятия можно использовать внешние компоненты (например, FormEx) для временной блокировки обновления формы, хотя в стандартной поставке 7.7 такой функционал ограничен.
Транзакции: Если удаление строк является частью сложного процесса обработки, желательно выполнять весь код внутри транзакции (НачатьТранзакцию() ... ЗафиксироватьТранзакцию()). Это гарантирует, что если в процессе произойдет ошибка, документ не останется в "полуобработанном" состоянии.
Выясним, какой метод выбрать? Для большинства задач в 1С 7.7 Способ №1 (обратный цикл) является оптимальным сочетанием простоты и надежности. Если же логика отбора строк очень сложная или таблица огромная — используйте Способ №2 (через ТЗ).