В процессе разработки конфигураций на платформе 1С:Предприятие часто возникает задача по обеспечению логической связности строк в табличных частях. Типичный пример — учет ГСМ и путевых листов, где значение реквизита СпидометрВыезда текущей строки должно строго соответствовать значению СпидометрВозвращения предыдущей строки. В этой статье мы подробно разберем, как правильно реализовать такой механизм, проанализируем типичные ошибки начинающих разработчиков и рассмотрим продвинутые методы оптимизации этой задачи.
Рассмотрим ситуацию, с которой столкнулся автор темы. При попытке заполнить реквизит следующей строки он использовал следующий код:
Процедура ТЧПЛПробегПоGPSПриИзменении(Элемент)
Для Каждого СтрТЧ Из Объект.ТЧПЛ Цикл
СтрТЧ.СпидометрВозвращения = СтрТЧ.СпидометрВыезда + СтрТЧ.ПробегПоGPS;
СтрТЧ.СпидометрВыезда[Объект.ТЧПЛ.Индекс(СтрТЧ)+1] = СтрТЧ.СпидометрВозвращения;
КонецЦикла;
КонецПроцедуры
Выясним причину возникновения ошибки «Получение элемента по индексу для значения не определено». Ошибка заключается в том, что разработчик пытается применить оператор получения по индексу [] не к самой табличной части, а к переменной СтрТЧ, которая является объектом текущей строки. Кроме того, при достижении последней строки индекс +1 выйдет за пределы коллекции, что также вызовет исключение. Проанализируем правильные подходы к решению этой задачи.
Это наиболее элегантный и производительный способ. Суть метода заключается в том, что в цикле мы запоминаем текущую строку в отдельную переменную в конце итерации, чтобы на следующем шаге иметь к ней доступ. Разберем реализацию этого алгоритма:
ПредыдущаяСтрока = Неопределено;
Для Каждого СтрТЧ Из Объект.ТЧПЛ Цикл
// Если это не первая итерация, устанавливаем значение из предыдущей строки
Если НЕ ПредыдущаяСтрока = Неопределено Тогда
СтрТЧ.СпидометрВыезда = ПредыдущаяСтрока.СпидометрВозвращения;
КонецЕсли;
// Рассчитываем текущий возврат
СтрТЧ.СпидометрВозвращения = СтрТЧ.СпидометрВыезда + СтрТЧ.ПробегПоGPS;
// Запоминаем текущую строку для использования на следующем шаге цикла
ПредыдущаяСтрока = СтрТЧ;
КонецЦикла;
Преимущества данного метода:
Индекс() или обращения к коллекции по номеру.В платформе 1С каждая строка табличной части имеет свойство НомерСтроки. Важно помнить, что нумерация строк в интерфейсе начинается с 1, в то время как индексы в коллекции программного объекта — с 0. Рассмотрим, как реализовать логику через обращение к коллекции:
Для Каждого СтрТЧ Из Объект.ТЧПЛ Цикл
Если СтрТЧ.НомерСтроки > 1 Тогда
// Получаем предыдущую строку по индексу (НомерСтроки - 2)
// НомерСтроки 2 имеет индекс 1, значит предыдущая (индекс 0) = 2 - 2
СтрТЧ.СпидометрВыезда = Объект.ТЧПЛ[СтрТЧ.НомерСтроки - 2].СпидометрВозвращения;
КонецЕсли;
СтрТЧ.СпидометрВозвращения = СтрТЧ.СпидометрВыезда + СтрТЧ.ПробегПоGPS;
КонецЦикла;
Важное примечание: При использовании этого метода нужно быть осторожным. Если табличная часть отсортирована пользователем вручную в интерфейсе, физический порядок строк в коллекции Объект.ТЧПЛ может не совпадать с визуальным порядком НомерСтроки, если не было выполнено обновление индексов.
Представим, что в табличной части сотни строк. Полный пересчет всей таблицы при изменении значения в середине списка — не самая оптимальная операция. Рассмотрим, как запустить пересчет только «хвоста» таблицы, начиная с измененной строки.
Для этого в обработчике события ПриИзменении реквизита строки мы можем определить индекс текущей строки и использовать цикл Для со счетчиком:
&НаКлиенте
Процедура ТЧПЛПробегПоGPSПриИзменении(Элемент)
ТекущаяСтрока = Элементы.ТЧПЛ.ТекущиеДанные;
Если ТекущаяСтрока = Неопределено Тогда
Возврат;
КонецЕсли;
// Сначала рассчитаем возврат для текущей строки
ТекущаяСтрока.СпидометрВозвращения = ТекущаяСтрока.СпидометрВыезда + ТекущаяСтрока.ПробегПоGPS;
// Определяем индекс текущей строки в коллекции
ИндексНачала = Объект.ТЧПЛ.Индекс(ТекущаяСтрока);
ВсегоСтрок = Объект.ТЧПЛ.Количество();
// Запускаем цикл со следующей строки до самого конца
Для и = ИндексНачала + 1 По ВсегоСтрок - 1 Цикл
СтрокаДляОбработки = Объект.ТЧПЛ[и];
СтрокаПредыдущая = Объект.ТЧПЛ[и - 1];
СтрокаДляОбработки.СпидометрВыезда = СтрокаПредыдущая.СпидометрВозвращения;
СтрокаДляОбработки.СпидометрВозвращения = СтрокаДляОбработки.СпидометрВыезда + СтрокаДляОбработки.ПробегПоGPS;
КонецЦикла;
КонецПроцедуры
Реализация «цепочки» значений требует внимания не только к изменению чисел, но и к структуре таблицы. Проанализируем критические моменты:
ПослеУдаления табличной части вызывать процедуру полного пересчета всей колонки.ПриИзменении самой таблицы (которое срабатывает при перемещении) для актуализации данных.СпидометрВыезда обычно должно подтягиваться из данных информационной базы (например, из предыдущего путевого листа по данному автомобилю). Логично добавить проверку: если Индекс == 0, то выполнять запрос к серверу или искать последний закрытый документ.Использование вышеописанных методов позволит создать надежный и удобный интерфейс для пользователя, минимизируя вероятность ввода ошибочных данных в учетную систему.