К статье
Практический материал

Разработка и Конфигурация · 11 мин

1С: как выбрать строку табличной части

Как выбрать строку табличной части в 1С: методы НайтиСтроки, Найти, перебор в цикле, работа с текущей строкой формы. Примеры кода, ошибки и проверка результата.

«Выбрать строку табличной части» в 1С — задача, которая стоит и перед разработчиком, пишущем код на встроенном языке, и перед пользователем, работающем с документом в режиме предприятия. Под выбором может пониматься поиск строк по условию, получение текущей выделенной строки в форме, перебор всех строк для обработки или установка курсора на нужную позицию. Каждый сценарий решается своим инструментом, и путаница между ними — частая причина ошибок.

Основные программные методы — НайтиСтроки(), Найти(), ВыбратьСтроку() (в толстом клиенте для управляемых и обычных форм) и прямой перебор коллекции в цикле. В форме документа дополнительно используются свойства ТекущаяСтрока и ТекущиеДанные элемента таблицы. Ниже разобраны все варианты с примерами кода, условиями применения и типичными ошибками.

Что такое табличная часть и как устроен доступ к строкам

Табличная часть — это коллекция строк, подчинённая объекту: документу, справочнику или обработке. Каждая строка имеет номер (начиная с 1) и набор реквизитов, определённых в конфигураторе. Программно табличная часть доступна как свойство объекта, например ДокументОбъект.Товары.

Коллекция поддерживает обращение по индексу: Товары[0] — первая строка, Товары[Товары.Количество() - 1] — последняя. Индексация начинается с нуля, а нумерация строк (свойство НомерСтроки) — с единицы. Это расхождение регулярно приводит к ошибкам «сдвига на единицу» при ручном обращении по номеру.

Важно различать два контекста: работа с данными объекта (на сервере, в модуле объекта) и работа с формой (на клиенте). В первом случае доступны методы коллекции, во втором — свойства элемента формы «Таблица», которые управляют визуальным выделением строк.

Поиск строк по условию: НайтиСтроки и Найти

Метод НайтиСтроки(ПараметрыОтбора) возвращает массив всех строк, удовлетворяющих отбору. Отбор задаётся структурой, где ключ — имя реквизита, а значение — искомое значение:

Отбор = Новый Структура("Номенклатура", ИскомыйТовар);

НайденныеСтроки = Объект.Товары.НайтиСтроки(Отбор);

Для Каждого Строка Из НайденныеСтроки Цикл

Строка.Количество = Строка.Количество + 1;

КонецЦикла;

Если нужна только одна строка, удобнее метод Найти(Значение, ИмяКолонки). Он возвращает первую найденную строку или Неопределено, если совпадений нет. Результат обязательно проверяйте перед обращением к реквизитам, иначе получите ошибку «Значение не является значением объектного типа».

Строка = Объект.Товары.Найти(ИскомыйТовар, "Номенклатура");

Если Строка = Неопределено Тогда

Сообщить("Строка с таким товаром не найдена");

Иначе

Строка.Цена = НоваяЦена;

КонецЕсли;

Перебор строк в цикле

Когда условие сложное (сравнение «больше», поиск по подстроке, проверка нескольких реквизитов с «ИЛИ»), применяется прямой перебор коллекции:

Для Каждого Строка Из Объект.Товары Цикл

Если Строка.Сумма > 100000 И Строка.СтавкаНДС = Ставка20 Тогда

// обработка строки

КонецЕсли;

КонецЦикла;

Если внутри цикла строки удаляются, перебирать коллекцию «Для Каждого» нельзя — индексы смещаются, и часть строк будет пропущена. Безопасные варианты: обратный цикл по индексу от конца к началу или предварительный сбор строк в массив через НайтиСтроки с последующим удалением.

Для Индекс = -Объект.Товары.Количество() + 1 По 0 Цикл

Строка = Объект.Товары[-Индекс];

Если Строка.Количество = 0 Тогда

Объект.Товары.Удалить(Строка);

КонецЕсли;

КонецЦикла;

Типичные ошибки
01
Удаление строк внутри цикла «Для Каждого» — коллекция смещается, часть строк пропускается или возникает ошибка индекса
02
Обращение к Товары[НомерСтроки] без вычитания единицы — индексация с нуля, поэтому нужен Товары[НомерСтроки - 1]
03
Отсутствие проверки результата Найти() на Неопределено — падение кода при отсутствии искомой строки
04
Поиск по строковому реквизиту без учёта регистра и пробелов — строка не находится, хотя визуально совпадает

Как получить текущую выделенную строку в форме

В управляемой форме документа табличная часть отображается элементом «Таблица». Текущая строка, на которой стоит курсор пользователя, доступна через свойства элемента:

// Данные текущей строки (ДанныеФормыСтруктура)

ТекСтрока = Элементы.Товары.ТекущиеДанные;

Если ТекСтрока <> Неопределено Тогда

Сообщить(ТекСтрока.Номенклатура);

КонецЕсли;

// Идентификатор строки в коллекции данных формы

ИдСтроки = Элементы.Товары.ТекущаяСтрока;

Различие принципиально: ТекущиеДанные — это сами данные строки (или Неопределено, если строка не выбрана), а ТекущаяСтрока — числовой идентификатор строки в коллекции ДанныеФормыКоллекция. По идентификатору строку можно получить методом Объект.Товары.НайтиПоИдентификатору(ИдСтроки).

Для множественного выделения (пользователь выделил несколько строк с Ctrl или Shift) используется свойство Элементы.Товары.ВыделенныеСтроки — массив идентификаторов. Это стандартный способ реализовать групповые операции: удаление, изменение цены, заполнение реквизита сразу в нескольких строках.

bsl
Для Каждого ИдСтроки Из Элементы.Товары.ВыделенныеСтроки Цикл
    Строка = Объект.Товары.НайтиПоИдентификатору(ИдСтроки);
    Строка.Пометка = Истина;
КонецЦикла;

Как установить курсор на нужную строку программно

Обратная задача — после добавления или поиска строки показать её пользователю, то есть спозиционировать таблицу. Для этого свойству ТекущаяСтрока элемента формы присваивается идентификатор нужной строки:

НоваяСтрока = Объект.Товары.Добавить();

НоваяСтрока.Номенклатура = Товар;

Элементы.Товары.ТекущаяСтрока = НоваяСтрока.ПолучитьИдентификатор();

Метод ПолучитьИдентификатор() вызывается у строки коллекции данных формы и возвращает именно тот идентификатор, который понимает элемент «Таблица». Присваивать номер строки или саму строку напрямую нельзя — позиционирование не сработает.

В обычных формах (толстый клиент) механика иная: там у табличного поля есть метод ТекущаяСтрока, принимающий саму строку табличной части напрямую. При переносе кода из обычных форм в управляемые этот фрагмент требует переработки.

Порядок действий: найти строку и показать её пользователю
  1. 1
    Сформируйте структуру отбора с именем реквизита и искомым значением
  2. 2
    Вызовите Объект.Товары.НайтиСтроки(Отбор) и проверьте, что массив не пуст
  3. 3
    Возьмите первую строку массива и получите её идентификатор через ПолучитьИдентификатор()
  4. 4
    Присвойте идентификатор свойству Элементы.Товары.ТекущаяСтрока
  5. 5
    Проверьте визуально: курсор таблицы установлен на нужной строке

Выбор строки пользователем в режиме предприятия

Если задача стоит не в коде, а в интерфейсе: клик по строке выделяет её, Ctrl+клик добавляет строки к выделению, Shift+клик выделяет диапазон. Для поиска нужной строки в длинной табличной части используйте сортировку по колонке (клик по заголовку) или стандартный поиск по таблице через Ctrl+F — он ищет по всем видимым колонкам.

Во многих типовых документах доступен подбор: кнопка «Подобрать» или «Добавить» открывает форму выбора номенклатуры, где отобранные позиции переносятся в табличную часть. Это быстрее ручного построчного ввода и снижает риск ошибок в артикулах и наименованиях.

Если строка «не выделяется» или таблица недоступна для редактирования, проверьте: документ проведён (в ряде конфигураций табличная часть блокируется), у пользователя есть права на изменение, документ не открыт в режиме просмотра другим сеансом.

Контрольные точки

Как проверить результат

Результат Найти()
Норма

Возвращена строка, реквизиты читаются без ошибок

Тревожный признак

Возвращено Неопределено — отбор не сработал, проверьте значение и тип данных

Позиционирование таблицы
Норма

Курсор встал на нужную строку, она подсвечена

Тревожный признак

Курсор остался на прежнем месте — вероятно, присвоен номер строки вместо идентификатора

Массив НайтиСтроки
Норма

Количество элементов соответствует ожидаемому числу совпадений

Тревожный признак

Массив пуст при видимых совпадениях — проверьте регистр, пробелы и тип сравниваемых значений

Выбор строк из запроса и по ссылке на объект

Когда табличная часть нужна не в форме, а в отчёте или обработке, строки выбирают запросом. Табличная часть доступна как виртуальная таблица с точкой: Документ.РеализацияТоваровУслуг.Товары. Запрос возвращает строки с полем Ссылка (документ-владелец) и НомерСтроки:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Товары.Ссылка,

| Товары.НомерСтроки,

| Товары.Номенклатура,

| Товары.Количество

|ИЗ

| Документ.РеализацияТоваровУслуг.Товары КАК Товары

|ГДЕ

| Товары.Ссылка = &Ссылка";

Если у вас есть ссылка на документ и нужно изменить строки, получите объект методом Ссылка.ПолучитьОбъект(), измените табличную часть и вызовите Записать(). Помните: запись объекта перезаписывает документ целиком, поэтому в многопользовательской базе между чтением и записью данные могут измениться другим пользователем — при массовых обработках учитывайте конфликты блокировок.

Частые вопросы

Чем НайтиСтроки отличается от Найти?

НайтиСтроки принимает структуру отбора и возвращает массив всех подходящих строк — он нужен, когда совпадений может быть несколько. Найти принимает значение и имя колонки и возвращает только первую найденную строку либо Неопределено. Для уникальных значений (например, штрихкод) удобнее Найти, для групповой обработки — НайтиСтроки.

Почему Найти не находит строку, хотя значение в таблице есть?

Чаще всего не совпадает тип данных (строка против числа), есть лишние пробелы или неразрывные пробелы в строковом реквизите, либо сравниваются ссылки разных видов. Выведите значение реквизита и искомое значение в сообщение и сравните посимвольно.

Как получить номер текущей строки табличной части в форме?

Через Элементы.Товары.ТекущиеДанные получите строку и прочитайте её свойство НомерСтроки. Учтите, что если курсор не установлен (таблица пуста или фокус в другом элементе), ТекущиеДанные вернёт Неопределено — проверка обязательна.

Можно ли выбрать строки табличной части без открытия формы документа?

Да. Получите объект через Ссылка.ПолучитьОбъект() и работайте с табличной частью как с обычной коллекцией: НайтиСтроки, Найти, перебор в цикле. Для чтения без изменения эффективнее запрос к табличной части — он не загружает весь объект в память.

Как удалить все строки, подходящие под условие?

Надёжный способ — получить массив через НайтиСтроки(Отбор) и в цикле вызвать Товары.Удалить(Строка) для каждого элемента. Удаление по собранному массиву безопасно, потому что массив не связан с индексами коллекции и не смещается при удалении.

Итог

Что важно запомнить

Поиск по условию — НайтиСтроки и Найти с обязательной проверкой результата. Текущая строка в форме — Элементы.Таблица.ТекущиеДанные и ТекущаяСтрока, позиционирование выполняется присваиванием идентификатора строки. При удалении в цикле используйте обратный перебор или массив строк. Перед массовыми изменениями табличных частей делайте резервную копию.