Активная и выделенная строка таблицы формы: код для 1С 8.3

· 9 мин

Содержание

Чтобы программно выделить строку в табличной части 1С 8.3 на управляемой форме, присвойте свойству ТекущаяСтрока элемента таблицы идентификатор строки: Элементы.Товары.ТекущаяСтрока = Объект.Товары[0].ПолучитьИдентификатор();. Таблица сама прокрутится к строке, курсор встанет на неё.

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

Как устроены активная и выделенные строки табличной части

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

  • 🎯 Активная (текущая) строка — та, на которой стоит курсор. Она одна. Свойство ТекущаяСтрока, данные — ТекущиеДанные.
  • ✅ Выделенные строки — подсвеченные строки при множественном выделении (Shift или Ctrl + щелчок). Их может быть много. Свойство ВыделенныеСтроки.
  • 🖱️ Текущая колонка — свойство ТекущийЭлемент у самой таблицы. Им ставят курсор в нужное поле строки.

В управляемой форме табличная часть документа — это реквизит Объект.Товары типа ДанныеФормыКоллекция. А на экране её показывает элемент Элементы.Товары типа ТаблицаФормы. Данные меняют через Объект, а положение курсора — через Элементы.

ЗадачаУправляемая формаОбычная форма
Сделать строку активнойЭлементы.Товары.ТекущаяСтрока = ИдЭлементыФормы.Товары.ТекущаяСтрока = СтрокаТЧ
Прочитать активную строкуЭлементы.Товары.ТекущиеДанныеЭлементыФормы.Товары.ТекущиеДанные
Выделить несколько строкЭлементы.Товары.ВыделенныеСтроки.Добавить(Ид)ЭлементыФормы.Товары.ВыделенныеСтроки.Добавить(СтрокаТЧ)
Что передаётсяидентификатор (число)сама строка табличной части

В английском синтаксисе встроенного языка это CurrentRow, CurrentData и SelectedRows. Методов SetCurrentRow или ActiveRow у таблицы формы нет — если встретили их в примерах из интернета, это не код 1С.

Установка активной строки через ТекущаяСтрока

Идентификатор строки получают методом ПолучитьИдентификатор() у элемента коллекции. Он доступен и на клиенте, и на сервере.

Первая и последняя строка

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

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

Индексы коллекции начинаются с нуля, а НомерСтроки — с единицы. Строка с номером 5 — это Объект.Товары[4].

Строка по номеру

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

Новая строка сразу после добавления

После Добавить() курсор остаётся на старом месте. Чтобы пользователь сразу видел новую строку, переставьте его явно:

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

Переход на строку и фокус: ТекущийЭлемент и ИзменитьСтроку

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

  1. Фокус на таблицу: ТекущийЭлемент = Элементы.Товары; — свойство самой формы.
  2. Нужная колонка: Элементы.Товары.ТекущийЭлемент = Элементы.ТоварыКоличество; — курсор встанет в поле «Количество» активной строки. Имя элемента колонки смотрите в дереве элементов формы.
  3. Режим редактирования: Элементы.Товары.ИзменитьСтроку(); — открывает активную строку для ввода, как если бы пользователь нажал F2 или Enter.
&НаКлиенте
Процедура ВвестиКоличествоВСтроке(Идентификатор)
	
	ТекущийЭлемент = Элементы.Товары;
	Элементы.Товары.ТекущаяСтрока = Идентификатор;
	Элементы.Товары.ТекущийЭлемент = Элементы.ТоварыКоличество;
	Элементы.Товары.ИзменитьСтроку();
	
КонецПроцедуры

Так делают, например, после подбора: товар добавлен, курсор сразу в количестве, пользователь печатает цифру и жмёт Enter.

Выделение строки при открытии формы

Здесь два разных сценария: форма объекта (документ с табличной частью) и форма списка.

Форма документа

Ставьте строку в обработчике ПриОткрытии. К этому моменту данные объекта уже на клиенте, элементы созданы.

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

Нужную строку можно вычислить и на сервере в ПриСозданииНаСервере: сохранить идентификатор в реквизит формы, а в ПриОткрытии только присвоить его. Это удобно, когда условие поиска требует запроса к базе.

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	// ИдСтрокиДляПерехода — реквизит формы типа Число; -1 означает «не задано»
	ИдСтрокиДляПерехода = -1;
	Если Параметры.Свойство("НомерСтроки") И Параметры.НомерСтроки > 0
		И Параметры.НомерСтроки <= Объект.Товары.Количество() Тогда
		ИдСтрокиДляПерехода = Объект.Товары[Параметры.НомерСтроки - 1].ПолучитьИдентификатор();
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
	
	Если ИдСтрокиДляПерехода >= 0 Тогда
		Элементы.Товары.ТекущаяСтрока = ИдСтрокиДляПерехода;
	КонецЕсли;
	
КонецПроцедуры

Значение -1 вместо проверки ЗначениеЗаполнено() выбрано намеренно: идентификатор строки — число, и ноль для него допустимое значение. Проверка на заполненность приняла бы такую строку за «пустую».

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

Форма списка

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

ПараметрыФормы = Новый Структура("ТекущаяСтрока", СсылкаНаНоменклатуру);
ОткрытьФорму("Справочник.Номенклатура.ФормаВыбора", ПараметрыФормы, ЭтотОбъект);

Список откроется с курсором на переданном элементе. Внутри уже открытой формы списка то же самое делает Элементы.Список.ТекущаяСтрока = Ссылка;.

Отличия управляемых и обычных форм

В обычных формах (толстый клиент) всё проще с типами: свойство ТекущаяСтрока принимает саму строку табличной части.

// Обычная форма документа
Процедура ПриОткрытии()
	
	Если Товары.Количество() > 0 Тогда
		ЭлементыФормы.Товары.ТекущаяСтрока = Товары[Товары.Количество() - 1];
	КонецЕсли;
	
КонецПроцедуры

Главные отличия, которые ломают перенос кода:

  • 🔢 Тип значения. В обычной форме — строка табличной части, в управляемой — идентификатор. Код Элементы.Товары.ТекущаяСтрока = Объект.Товары[0] в управляемой форме работать не будет.
  • 🖥️ Клиент и сервер. В управляемой форме данные строк есть на клиенте в виде данных формы. Ссылочные поля доступны, но обращаться через точку к реквизитам этих ссылок (Строка.Номенклатура.Артикул) на клиенте нельзя — нужен вызов сервера.
  • 🧭 Имена. ЭлементыФормы в обычной форме и Элементы в управляемой. Реквизит табличной части — Товары и Объект.Товары.
  • ⏱️ Событие ПриАктивизацииСтроки. В управляемой форме оно вызывается с небольшой задержкой, а не мгновенно. Если в нём тяжёлая логика, программная смена строки покажет результат не сразу.

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

Ошибки при программном выделении строки

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

Отдельно про ТекущиеДанные: при пустой таблице или при снятом курсоре свойство возвращает Неопределено. Проверяйте это до обращения к полям, иначе получите ошибку на клиенте.

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

Множественное выделение и поиск строки по значению

Найти строку и встать на неё

Для поиска по значению поля в коллекции данных формы есть НайтиСтроки(). Метод принимает структуру отбора и возвращает массив найденных строк.

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

Выделить все найденные строки

Сначала включите множественное выделение — в свойствах элемента таблицы в конфигураторе или кодом. Затем очистите старое выделение и добавьте идентификаторы.

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

Активную строку ставим на первую найденную, чтобы таблица прокрутилась к выделению. Иначе выделенные строки могут оказаться за пределами видимой области.

Обработать то, что выделил пользователь

Обратная задача — пройти по выделенным строкам. В ВыделенныеСтроки лежат идентификаторы, строки по ним достают через НайтиПоИдентификатору():

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

Если обработка удаляет выделенные строки, сначала соберите идентификаторы в отдельный массив, а удаляйте уже по нему. Удаление прямо в цикле по ВыделенныеСтроки меняет коллекцию, по которой вы идёте.

Выделение в динамическом списке

В форме списка справочника или журнала документов ВыделенныеСтроки хранит не идентификаторы, а ссылки. Поэтому и добавлять в выделение нужно ссылки:

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

Строка попадёт в выделение, только если она проходит текущий отбор списка. Элемент, скрытый отбором или находящийся в свёрнутой группе иерархического списка, подсвечен не будет.

Реакция на программную смену строки

Обработчик ПриАктивизацииСтроки срабатывает и тогда, когда строку меняет код, а не пользователь. Если в нём заполняются зависимые поля или вызывается сервер, программное выделение в цикле запустит его много раз подряд.

Два способа этого избежать:

  • 🚦 поставить флаг в реквизите формы перед массовым выделением и проверять его в начале ПриАктивизацииСтроки;
  • ⏳ в самом обработчике не делать работу сразу, а подключить обработчик ожидания через ПодключитьОбработчикОжидания("ОбновитьПодвал", 0.1, Истина) — тогда отработает только последняя активизация.

Поиск на сервере по сложному условию

Когда условие требует данных из базы (например, «товары, у которых нет остатка»), ищите на сервере и возвращайте на клиент массив идентификаторов. Идентификаторы одинаковы на клиенте и сервере в пределах одной формы, поэтому их можно безопасно передавать через серверный вызов.

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

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

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

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