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