Программно ставим курсор на нужную строку табличной части: код для управляемой и обычной формы

· 9 мин

Содержание

Чтобы программно сделать текущей строку в табличной части 1С 8.3 на управляемой форме, присвойте свойству элемента-таблицы идентификатор строки: Элементы.Товары.ТекущаяСтрока = Строка.ПолучитьИдентификатор();. Саму строку при этом сначала находят в коллекции данных формы — по индексу, по номеру или через НайтиСтроки.

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

Что такое текущая строка и чем она отличается от данных

У таблицы на форме есть два разных понятия, которые легко спутать:

  • 🎯 Текущая строка — строка, на которой стоит курсор. Её задаёт свойство ТекущаяСтрока элемента формы.
  • 📦 Текущие данные — содержимое этой строки. Свойство ТекущиеДанные возвращает объект строки или Неопределено, если таблица пуста или курсор никуда не поставлен.
  • ✅ Выделенные строки — массив идентификаторов всех отмеченных строк, свойство ВыделенныеСтроки. Текущая строка обычно входит в него, но выделенных может быть несколько.

ТекущиеДанные только читают. Записать в него другую строку нельзя: чтобы сменить позицию, меняют ТекущаяСтрока.

Тип значения ТекущаяСтрока зависит от того, к чему привязана таблица:

Источник данных таблицыЧто лежит в ТекущаяСтрока
Табличная часть объекта, таблица значений реквизита формы (управляемая форма)Число — идентификатор строки в коллекции данных формы
Дерево значений реквизита формыЧисло — идентификатор элемента дерева
Динамический списокКлюч строки, обычно ссылка на элемент или документ
Табличная часть в обычной форме (толстый клиент)Сама строка табличной части

Отсюда и правило: прежде чем писать код, посмотрите, какой реквизит указан в свойстве ПутьКДанным таблицы.

Базовый способ: найти строку и передать её идентификатор

На управляемой форме табличная часть документа живёт в реквизите Объект как коллекция данных формы. Идентификатор строки возвращает её метод ПолучитьИдентификатор(), а обратное преобразование делает метод коллекции НайтиПоИдентификатору().

Поиск строки по значению колонки

У коллекции данных формы для поиска есть НайтиСтроки. Он принимает структуру отбора и возвращает массив подходящих строк:

&НаКлиенте
Процедура ПерейтиКНоменклатуре(Номенклатура)

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

    Если НайденныеСтроки.Количество() = 0 Тогда
        Сообщить("Товар в документе не найден");
        Возврат;
    КонецЕсли;

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

КонецПроцедуры

Вторая строка после присвоения переводит фокус ввода на таблицу. Без неё курсор встанет на нужную строку, но фокус останется на поле, где пользователь нажал кнопку, и выделение будет бледным.

В отбор можно передать несколько колонок: Новый Структура("Номенклатура, Характеристика", Товар, Характеристика). Строка найдётся, только если совпадут все значения.

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

Метод Найти(Значение, Колонки) есть у табличной части объекта и у таблицы значений. У коллекции данных формы на клиенте его нет — вызов закончится ошибкой Метод объекта не обнаружен (Найти).

Если поиск удобнее делать через Найти (например, ищется значение сразу в нескольких колонках), делайте это на сервере над объектом, а на клиент возвращайте номер строки:

&НаСервере
Функция НомерСтрокиСЗначением(Значение)

    ДокументОбъект = РеквизитФормыВЗначение("Объект");
    Строка = ДокументОбъект.Товары.Найти(Значение, "Номенклатура, Склад");
    Если Строка = Неопределено Тогда
        Возврат 0;
    КонецЕсли;
    Возврат Строка.НомерСтроки;

КонецФункции

Обратно в реквизит формы объект здесь не возвращаем — мы только читаем, поэтому идентификаторы строк на клиенте остаются прежними.

Новая строка сразу под курсором

Типовая задача: кнопка «Добавить из подбора» создаёт строку, и курсор должен встать на неё с открытой ячейкой:

&НаКлиенте
Процедура ДобавитьСтроку(Команда)

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

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

КонецПроцедуры

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

Переход к строке по номеру и индексу

Метода НТСтр в платформе 8.3 нет. За этим названием обычно скрывается задача «перейти к строке с номером N». Её решают через индекс коллекции или колонку НомерСтроки.

Две вещи, которые нужно держать в голове:

  1. НомерСтроки в табличной части начинается с 1.
  2. Индекс коллекции начинается с 0. Строка с номером 5 имеет индекс 4.
&НаКлиенте
Процедура ПерейтиКНомеру(Номер)

    Если Номер < 1 Или Номер > Объект.Товары.Количество() Тогда
        Сообщить(СтрШаблон("В документе нет строки %1", Формат(Номер, "ЧГ=0")));
        Возврат;
    КонецЕсли;

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

КонецПроцедуры

Проверка границ здесь обязательна. Без неё при номере больше количества строк получите Индекс находится за границами диапазона.

Следующая и предыдущая строка

Индекс текущей строки возвращает метод коллекции Индекс(). От него легко шагнуть вперёд или назад:

&НаКлиенте
Процедура СледующаяСтрока(Команда)

    ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;

    Индекс = Объект.Товары.Индекс(ТекущиеДанные);
    Если Индекс < Объект.Товары.Количество() - 1 Тогда
        Элементы.Товары.ТекущаяСтрока = Объект.Товары[Индекс + 1].ПолучитьИдентификатор();
    КонецЕсли;

КонецПроцедуры

Учтите: индекс считается по порядку строк в данных. Если пользователь отсортировал таблицу кликом по заголовку колонки, «следующая в данных» может оказаться не той, что видна ниже на экране.

Когда ставить курсор: события формы и синхронизация

Код установки текущей строки правильный, а курсор после открытия формы стоит на первой строке. Причина почти всегда в моменте вызова.

При открытии формы

Для табличных частей подходит обработчик ПриОткрытии. Если форма открывается с параметром, по которому нужно спозиционироваться, свойство можно задать и в ПриСозданииНаСервере: элементы формы доступны на сервере, значение уйдёт на клиент вместе с формой.

Для динамического списка это стандартный приём: в параметр формы передают ссылку и в ПриСозданииНаСервере пишут Элементы.Список.ТекущаяСтрока = Параметры.ТекущаяСтрока;.

Когда форма ещё не дорисована

Бывает, что курсор нужно поставить после асинхронного действия: закрытия формы подбора, ответа на вопрос, загрузки данных. Если в этот момент таблица перестраивается, присвоение теряется. Помогает отложенный вызов через обработчик ожидания:

&НаКлиенте
Перем ИдентификаторДляПерехода;

&НаКлиенте
Процедура ПослеЗагрузки()
    ИдентификаторДляПерехода = Объект.Товары[0].ПолучитьИдентификатор();
    ПодключитьОбработчикОжидания("УстановитьТекущуюСтроку", 0.1, Истина);
КонецПроцедуры

&НаКлиенте
Процедура УстановитьТекущуюСтроку()
    Элементы.Товары.ТекущаяСтрока = ИдентификаторДляПерехода;
КонецПроцедуры

Третий параметр Истина делает обработчик однократным, повторно он не сработает.

Событие ПриАктивизацииСтроки

Это событие таблицы срабатывает, когда текущая строка меняется — и пользователем, и программно. В нём обычно обновляют связанные элементы: подчинённую таблицу, панель с итогами по строке, доступность кнопок.

Не меняйте ТекущаяСтрока внутри ПриАктивизацииСтроки той же таблицы без защиты. Перевод курсора снова вызовет событие, и форма начнёт прыгать между строками. Если такая логика нужна, ставьте флаг-реквизит перед присвоением и выходите из обработчика, пока он взведён.

Синхронизация двух таблиц

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

Какой способ выбрать: сравнение приёмов

ПриёмКогда применятьНа что обратить внимание
НайтиСтроки + ПолучитьИдентификаторИщем строку по значениям колонок на клиентеВозвращается массив, может быть пустым
Индекс [Номер - 1]Известен номер строкиПроверять границы, индекс с нуля
НайтиПоИдентификаторуИдентификатор сохранён заранееПосле перезагрузки данных идентификатор устаревает
Найти на сервере → номер строкиСложный поиск над объектомНе возвращать объект в форму без нужды
Ссылка в ТекущаяСтрокаДинамический списокСтрока должна попадать под отбор списка
Строка табличной части в ТекущаяСтрокаОбычная форма, толстый клиентВ управляемой форме так не работает

Для обычных форм код короче, потому что свойство принимает саму строку:

Строка = ТабличнаяЧасть.Найти(Товар, "Номенклатура");
Если Строка <> Неопределено Тогда
    ЭлементыФормы.ТабличнаяЧасть.ТекущаяСтрока = Строка;
КонецЕсли;

Здесь ЭлементыФормы — коллекция элементов обычной формы, а ТабличнаяЧасть — имя элемента и реквизита, как они названы в вашей форме.

Ошибки, из-за которых курсор не встаёт на место

Диагностика: выберите симптом

Отдельно про устаревшие идентификаторы. Идентификатор действует, пока живёт конкретная строка в данных формы. Любой код вида ДокументОбъект = РеквизитФормыВЗначение("Объект"); ...; ЗначениеВРеквизитФормы(ДокументОбъект, "Объект"); пересоздаёт коллекцию. Поэтому перед таким вызовом сохраняйте не идентификатор, а то, по чему строку можно найти снова: НомерСтроки или значения ключевых колонок.

Продвинутые приёмы: выделение, сообщения и деревья

Выделить несколько строк программно

ВыделенныеСтроки — массив идентификаторов. Его можно очистить и заполнить заново:

&НаКлиенте
Процедура ВыделитьБезЦены(Команда)

    Элементы.Товары.ВыделенныеСтроки.Очистить();
    ПерваяНайдена = Ложь;

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

КонецПроцедуры

Чтобы выделение нескольких строк работало, в свойствах таблицы должен быть включён множественный режим выделения.

Перевести пользователя к ошибке через сообщение

Вместо ручной установки курсора можно привязать сообщение к полю строки. Пользователь щёлкает по сообщению, и платформа сама активирует нужную ячейку:

Индекс = Объект.Товары.Индекс(Строка);
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не указана цена";
Сообщение.Поле = СтрШаблон("Объект.Товары[%1].Цена", Формат(Индекс, "ЧН=0; ЧГ=0"));
Сообщение.Сообщить();

В квадратных скобках — индекс с нуля, а не номер строки. Формат с ЧГ=0 убирает пробел-разделитель групп, иначе при индексе от 1000 путь сломается, а ЧН=0 выводит ноль для первой строки вместо пустой строки.

В конфигурациях на БСП то же самое делает ОбщегоНазначенияКлиентСервер.СообщитьПользователю с путём к полю в третьем параметре.

Деревья значений

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

Проверка перед тем, как искать проблему глубже
Выполнено: 0 / 6

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

Можно ли поставить курсор на строку, не переводя фокус на таблицу?
Да. Присвоение ТекущаяСтрока меняет позицию без смены фокуса. Строка будет текущей, но подсветка слабее, пока пользователь не перейдёт в таблицу.
Как узнать номер текущей строки?
Прочитайте Элементы.Товары.ТекущиеДанные.НомерСтроки, предварительно проверив ТекущиеДанные на Неопределено.
Работает ли ТекущаяСтрока в веб-клиенте?
Да, свойство и методы коллекции данных формы одинаково работают в тонком и веб-клиенте.
Почему после записи документа курсор прыгает на первую строку?
При записи форма перечитывает объект, и идентификаторы строк меняются. Запомните номер строки в ПередЗаписью и восстановите позицию в ПослеЗаписи.
Можно ли поставить курсор на строку, скрытую отбором?
Нет. Строка, которая не проходит ОтборСтрок, не отображается, и курсор на неё не встанет. Сначала снимите или измените отбор.