Программно ставим курсор на нужную строку табличной части: код для управляемой и обычной формы
Содержание
Чтобы программно сделать текущей строку в табличной части 1С 8.3 на управляемой форме, присвойте свойству элемента-таблицы идентификатор строки: Элементы.Товары.ТекущаяСтрока = Строка.ПолучитьИдентификатор();. Саму строку при этом сначала находят в коллекции данных формы — по индексу, по номеру или через НайтиСтроки.
Самая частая ошибка — переносить приём из обычных форм и присваивать ТекущаяСтрока саму строку. В обычной форме так и делают, а в управляемой свойство ждёт число-идентификатор. Курсор не двигается, разработчик ищет проблему в событиях. Ниже код для обоих типов форм, поиск, выделение нескольких строк и разбор ошибок.
Что такое текущая строка и чем она отличается от данных
У таблицы на форме есть два разных понятия, которые легко спутать:
- 🎯 Текущая строка — строка, на которой стоит курсор. Её задаёт свойство
ТекущаяСтрокаэлемента формы. - 📦 Текущие данные — содержимое этой строки. Свойство
ТекущиеДанныевозвращает объект строки илиНеопределено, если таблица пуста или курсор никуда не поставлен. - ✅ Выделенные строки — массив идентификаторов всех отмеченных строк, свойство
ВыделенныеСтроки. Текущая строка обычно входит в него, но выделенных может быть несколько.
ТекущиеДанные только читают. Записать в него другую строку нельзя: чтобы сменить позицию, меняют ТекущаяСтрока.
Тип значения ТекущаяСтрока зависит от того, к чему привязана таблица:
| Источник данных таблицы | Что лежит в ТекущаяСтрока |
|---|---|
| Табличная часть объекта, таблица значений реквизита формы (управляемая форма) | Число — идентификатор строки в коллекции данных формы |
| Дерево значений реквизита формы | Число — идентификатор элемента дерева |
| Динамический список | Ключ строки, обычно ссылка на элемент или документ |
| Табличная часть в обычной форме (толстый клиент) | Сама строка табличной части |
Отсюда и правило: прежде чем писать код, посмотрите, какой реквизит указан в свойстве ПутьКДанным таблицы.
Базовый способ: найти строку и передать её идентификатор
На управляемой форме табличная часть документа живёт в реквизите Объект как коллекция данных формы. Идентификатор строки возвращает её метод ПолучитьИдентификатор(), а обратное преобразование делает метод коллекции НайтиПоИдентификатору().
Поиск строки по значению колонки
У коллекции данных формы для поиска есть НайтиСтроки. Он принимает структуру отбора и возвращает массив подходящих строк:
&НаКлиенте
Процедура ПерейтиКНоменклатуре(Номенклатура)
Отбор = Новый Структура("Номенклатура", Номенклатура);
НайденныеСтроки = Объект.Товары.НайтиСтроки(Отбор);
Если НайденныеСтроки.Количество() = 0 Тогда
Сообщить("Товар в документе не найден");
Возврат;
КонецЕсли;
Элементы.Товары.ТекущаяСтрока = НайденныеСтроки[0].ПолучитьИдентификатор();
ТекущийЭлемент = Элементы.Товары;
КонецПроцедуры
Вторая строка после присвоения переводит фокус ввода на таблицу. Без неё курсор встанет на нужную строку, но фокус останется на поле, где пользователь нажал кнопку, и выделение будет бледным.
В отбор можно передать несколько колонок: Новый Структура("Номенклатура, Характеристика", Товар, Характеристика). Строка найдётся, только если совпадут все значения.
Чем Найти отличается от НайтиСтроки
Метод Найти(Значение, Колонки) есть у табличной части объекта и у таблицы значений. У коллекции данных формы на клиенте его нет — вызов закончится ошибкой Метод объекта не обнаружен (Найти).
Если поиск удобнее делать через Найти (например, ищется значение сразу в нескольких колонках), делайте это на сервере над объектом, а на клиент возвращайте номер строки:
&НаСервере
Функция НомерСтрокиСЗначением(Значение)
ДокументОбъект = РеквизитФормыВЗначение("Объект");
Строка = ДокументОбъект.Товары.Найти(Значение, "Номенклатура, Склад");
Если Строка = Неопределено Тогда
Возврат 0;
КонецЕсли;
Возврат Строка.НомерСтроки;
КонецФункции
Обратно в реквизит формы объект здесь не возвращаем — мы только читаем, поэтому идентификаторы строк на клиенте остаются прежними.
Новая строка сразу под курсором
Типовая задача: кнопка «Добавить из подбора» создаёт строку, и курсор должен встать на неё с открытой ячейкой:
&НаКлиенте
Процедура ДобавитьСтроку(Команда)
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Количество = 1;
Элементы.Товары.ТекущаяСтрока = НоваяСтрока.ПолучитьИдентификатор();
Элементы.Товары.ТекущийЭлемент = Элементы.ТоварыНоменклатура;
Элементы.Товары.ИзменитьСтроку();
КонецПроцедуры
Свойство ТекущийЭлемент у таблицы задаёт колонку, а ИзменитьСтроку() открывает ячейку на редактирование. Имя ТоварыНоменклатура — имя элемента-колонки на форме, его видно в дереве элементов конфигуратора.
Переход к строке по номеру и индексу
Метода НТСтр в платформе 8.3 нет. За этим названием обычно скрывается задача «перейти к строке с номером N». Её решают через индекс коллекции или колонку НомерСтроки.
Две вещи, которые нужно держать в голове:
НомерСтрокив табличной части начинается с 1.- Индекс коллекции начинается с 0. Строка с номером 5 имеет индекс 4.
&НаКлиенте
Процедура ПерейтиКНомеру(Номер)
Если Номер < 1 Или Номер > Объект.Товары.Количество() Тогда
Сообщить(СтрШаблон("В документе нет строки %1", Формат(Номер, "ЧГ=0")));
Возврат;
КонецЕсли;
Строка = Объект.Товары[Номер - 1];
Элементы.Товары.ТекущаяСтрока = Строка.ПолучитьИдентификатор();
КонецПроцедуры
Проверка границ здесь обязательна. Без неё при номере больше количества строк получите Индекс находится за границами диапазона.
Следующая и предыдущая строка
Индекс текущей строки возвращает метод коллекции Индекс(). От него легко шагнуть вперёд или назад:
&НаКлиенте
Процедура СледующаяСтрока(Команда)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
Индекс = Объект.Товары.Индекс(ТекущиеДанные);
Если Индекс < Объект.Товары.Количество() - 1 Тогда
Элементы.Товары.ТекущаяСтрока = Объект.Товары[Индекс + 1].ПолучитьИдентификатор();
КонецЕсли;
КонецПроцедуры
Учтите: индекс считается по порядку строк в данных. Если пользователь отсортировал таблицу кликом по заголовку колонки, «следующая в данных» может оказаться не той, что видна ниже на экране.
Когда ставить курсор: события формы и синхронизация
Код установки текущей строки правильный, а курсор после открытия формы стоит на первой строке. Причина почти всегда в моменте вызова.
При открытии формы
Для табличных частей подходит обработчик ПриОткрытии. Если форма открывается с параметром, по которому нужно спозиционироваться, свойство можно задать и в ПриСозданииНаСервере: элементы формы доступны на сервере, значение уйдёт на клиент вместе с формой.
Для динамического списка это стандартный приём: в параметр формы передают ссылку и в ПриСозданииНаСервере пишут Элементы.Список.ТекущаяСтрока = Параметры.ТекущаяСтрока;.
Когда форма ещё не дорисована
Бывает, что курсор нужно поставить после асинхронного действия: закрытия формы подбора, ответа на вопрос, загрузки данных. Если в этот момент таблица перестраивается, присвоение теряется. Помогает отложенный вызов через обработчик ожидания:
&НаКлиенте
Перем ИдентификаторДляПерехода;
&НаКлиенте
Процедура ПослеЗагрузки()
ИдентификаторДляПерехода = Объект.Товары[0].ПолучитьИдентификатор();
ПодключитьОбработчикОжидания("УстановитьТекущуюСтроку", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура УстановитьТекущуюСтроку()
Элементы.Товары.ТекущаяСтрока = ИдентификаторДляПерехода;
КонецПроцедуры
Третий параметр Истина делает обработчик однократным, повторно он не сработает.
Событие ПриАктивизацииСтроки
Это событие таблицы срабатывает, когда текущая строка меняется — и пользователем, и программно. В нём обычно обновляют связанные элементы: подчинённую таблицу, панель с итогами по строке, доступность кнопок.
Не меняйте ТекущаяСтрока внутри ПриАктивизацииСтроки той же таблицы без защиты. Перевод курсора снова вызовет событие, и форма начнёт прыгать между строками. Если такая логика нужна, ставьте флаг-реквизит перед присвоением и выходите из обработчика, пока он взведён.
Синхронизация двух таблиц
Классика: слева таблица документов, справа их строки. При активизации строки слева правую таблицу фильтруют и ставят курсор на первую подходящую строку. Отбор задают через свойство таблицы ОтборСтрок (тип ФиксированнаяСтруктура), а позицию — тем же ТекущаяСтрока по идентификатору первой найденной строки.
Какой способ выбрать: сравнение приёмов
| Приём | Когда применять | На что обратить внимание |
|---|---|---|
НайтиСтроки + ПолучитьИдентификатор | Ищем строку по значениям колонок на клиенте | Возвращается массив, может быть пустым |
Индекс [Номер - 1] | Известен номер строки | Проверять границы, индекс с нуля |
НайтиПоИдентификатору | Идентификатор сохранён заранее | После перезагрузки данных идентификатор устаревает |
Найти на сервере → номер строки | Сложный поиск над объектом | Не возвращать объект в форму без нужды |
Ссылка в ТекущаяСтрока | Динамический список | Строка должна попадать под отбор списка |
Строка табличной части в ТекущаяСтрока | Обычная форма, толстый клиент | В управляемой форме так не работает |
Для обычных форм код короче, потому что свойство принимает саму строку:
Строка = ТабличнаяЧасть.Найти(Товар, "Номенклатура");
Если Строка <> Неопределено Тогда
ЭлементыФормы.ТабличнаяЧасть.ТекущаяСтрока = Строка;
КонецЕсли;
Здесь ЭлементыФормы — коллекция элементов обычной формы, а ТабличнаяЧасть — имя элемента и реквизита, как они названы в вашей форме.
Ошибки, из-за которых курсор не встаёт на место
Отдельно про устаревшие идентификаторы. Идентификатор действует, пока живёт конкретная строка в данных формы. Любой код вида ДокументОбъект = РеквизитФормыВЗначение("Объект"); ...; ЗначениеВРеквизитФормы(ДокументОбъект, "Объект"); пересоздаёт коллекцию. Поэтому перед таким вызовом сохраняйте не идентификатор, а то, по чему строку можно найти снова: НомерСтроки или значения ключевых колонок.
Продвинутые приёмы: выделение, сообщения и деревья
Выделить несколько строк программно
ВыделенныеСтроки — массив идентификаторов. Его можно очистить и заполнить заново:
&НаКлиенте
Процедура ВыделитьБезЦены(Команда)
Элементы.Товары.ВыделенныеСтроки.Очистить();
ПерваяНайдена = Ложь;
Для Каждого Строка Из Объект.Товары Цикл
Если Строка.Цена = 0 Тогда
Ид = Строка.ПолучитьИдентификатор();
Элементы.Товары.ВыделенныеСтроки.Добавить(Ид);
Если Не ПерваяНайдена Тогда
Элементы.Товары.ТекущаяСтрока = Ид;
ПерваяНайдена = Истина;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Чтобы выделение нескольких строк работало, в свойствах таблицы должен быть включён множественный режим выделения.
Перевести пользователя к ошибке через сообщение
Вместо ручной установки курсора можно привязать сообщение к полю строки. Пользователь щёлкает по сообщению, и платформа сама активирует нужную ячейку:
Индекс = Объект.Товары.Индекс(Строка);
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не указана цена";
Сообщение.Поле = СтрШаблон("Объект.Товары[%1].Цена", Формат(Индекс, "ЧН=0; ЧГ=0"));
Сообщение.Сообщить();
В квадратных скобках — индекс с нуля, а не номер строки. Формат с ЧГ=0 убирает пробел-разделитель групп, иначе при индексе от 1000 путь сломается, а ЧН=0 выводит ноль для первой строки вместо пустой строки.
В конфигурациях на БСП то же самое делает ОбщегоНазначенияКлиентСервер.СообщитьПользователю с путём к полю в третьем параметре.
Деревья значений
На форме с деревом поиск идёт по уровням: у элемента дерева есть ПолучитьЭлементы(), по ним обходят дочерние строки рекурсивно. Найденному элементу берут ПолучитьИдентификатор() и присваивают ТекущаяСтрока. Если родитель свёрнут, разверните его методом таблицы Развернуть(ИдентификаторРодителя) — иначе курсор встанет на скрытую строку и пользователь его не увидит.