Текущая строка и выделение в таблицах и табличных документах 1С 8.3: свойства, код и события
Содержание
Чтобы выделить строку в 1С программно, присвойте значение свойству ТекущаяСтрока элемента таблицы формы: для динамического списка — ссылку (Элементы.Список.ТекущаяСтрока = Ссылка), для табличной части или таблицы значений — идентификатор строки (Элементы.Товары.ТекущаяСтрока = Строка.ПолучитьИдентификатор()). Несколько строк выделяют через коллекцию ВыделенныеСтроки, а строку табличного документа — через его свойство ТекущаяОбласть.
Отдельного метода «ВыделитьСтроку» или SetCurrentRow во встроенном языке 1С нет. Всё управление выделением строится на свойствах элемента формы и нескольких событиях. Мышью и с клавиатуры строки выделяют стандартно: щелчок, Shift + щелчок для диапазона, Ctrl + щелчок для выборочных строк, Ctrl+A для всех. Ниже примеры для управляемых форм платформы 8.3 — то, что работает в БП 3.0, ЗУП 3.1, УТ 11 и любой собственной конфигурации.
Текущая строка и выделенные строки — в чём разница
В таблице формы одновременно живут два разных понятия. Их путают чаще всего, и отсюда половина вопросов «почему код обработал не те строки».
| Понятие | Свойство | Сколько строк | Что содержит |
|---|---|---|---|
| Текущая строка | ТекущаяСтрока | Всегда одна (или ничего) | Ссылка, ключ записи или идентификатор строки |
| Данные текущей строки | ТекущиеДанные | Одна | Значения колонок текущей строки, только на клиенте |
| Выделенные строки | ВыделенныеСтроки | Ноль, одна или много | Коллекция ссылок или идентификаторов |
Текущая строка — та, на которой стоит курсор (рамка). Выделенные — подсвеченные. Когда пользователь просто щёлкает по строке, она становится и текущей, и единственной выделенной. Когда он отмечает пять строк через Ctrl, текущей остаётся одна — последняя, по которой щёлкнули, а в ВыделенныеСтроки попадают все пять.
Отсюда правило:
- 🎯 команда «открыть», «показать карточку», «перейти» — работает с
ТекущаяСтрокаилиТекущиеДанные; - 📦 групповая команда «провести выбранные», «установить статус», «распечатать отмеченные» — перебирает
ВыделенныеСтроки.
ТекущиеДанные доступны только на клиенте. На сервер передавайте ссылку или идентификатор, а не саму структуру данных строки.
Ещё одна деталь: у таблицы есть и текущая колонка. Её задаёт свойство ТекущийЭлемент самой таблицы — туда присваивают элемент поля, например Элементы.Товары.ТекущийЭлемент = Элементы.ТоварыКоличество.
Как выделить строку в таблице формы программно
Тип значения в ТекущаяСтрока зависит от того, к какому реквизиту привязана таблица. Это главный момент: присвоите не тот тип — строка не выделится, а ошибки может и не быть.
Табличная часть, таблица значений, дерево
Для реквизитов-коллекций (Объект.Товары, реквизит формы типа «Таблица значений» или «Дерево значений») текущая строка задаётся числовым идентификатором строки коллекции данных формы.
&НаКлиенте
Процедура ДобавитьИПерейти(Команда)
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Количество = 1;
Элементы.Товары.ТекущаяСтрока = НоваяСтрока.ПолучитьИдентификатор();
Элементы.Товары.ТекущийЭлемент = Элементы.ТоварыНоменклатура;
ТекущийЭлемент = Элементы.Товары;
Элементы.Товары.ИзменитьСтроку();
КонецПроцедуры
Что здесь происходит по шагам:
- Добавляем строку в табличную часть.
- Ставим на неё курсор через идентификатор.
- Делаем текущей колонку «Номенклатура».
- Передаём фокус самой таблице — иначе курсор встанет, но фокус останется на кнопке.
- Включаем режим редактирования ячейки, чтобы пользователь сразу печатал.
Чтобы перейти к строке по номеру, сначала получите строку коллекции по индексу. Индексы начинаются с нуля, поэтому пятая строка — это Объект.Товары[4]:
&НаКлиенте
Процедура ПерейтиКСтроке(НомерСтроки)
Если НомерСтроки < 1 Или НомерСтроки > Объект.Товары.Количество() Тогда
Возврат;
КонецЕсли;
Строка = Объект.Товары[НомерСтроки - 1];
Элементы.Товары.ТекущаяСтрока = Строка.ПолучитьИдентификатор();
КонецПроцедуры
Найти строку по значению колонки можно методом НайтиСтроки и затем взять идентификатор первой найденной:
Найденные = Объект.Товары.НайтиСтроки(Новый Структура("Номенклатура", ИскомаяНоменклатура));
Если Найденные.Количество() > 0 Тогда
Элементы.Товары.ТекущаяСтрока = Найденные[0].ПолучитьИдентификатор();
КонецЕсли;
Обратная операция — по идентификатору получить строку — делается методом НайтиПоИдентификатору у коллекции: Объект.Товары.НайтиПоИдентификатору(Элементы.Товары.ТекущаяСтрока). Для дерева значений на форме всё так же: и ПолучитьИдентификатор(), и НайтиПоИдентификатору() есть у его элементов.
Динамический список
В форме списка справочника или документа таблица привязана к динамическому списку. Здесь текущая строка — это ссылка на объект, а для списка регистра сведений — ключ записи.
&НаКлиенте
Процедура ПерейтиКДоговору(Команда)
Элементы.Список.ТекущаяСтрока = ВыбранныйДоговор;
КонецПроцедуры
Если объекта нет в списке из-за отбора или он помечен на удаление при скрытых помеченных, курсор не сдвинется. Проверьте отбор, прежде чем искать ошибку в коде.
Открыть форму списка сразу на нужной строке проще всего стандартным параметром ТекущаяСтрока:
ПараметрыФормы = Новый Структура("ТекущаяСтрока", Контрагент);
ОткрытьФорму("Справочник.Контрагенты.ФормаСписка", ПараметрыФормы);
В своей форме списка этот параметр принимают в ПриСозданииНаСервере и присваивают Элементы.Список.ТекущаяСтрока.
Выделение строки в табличном документе
Отчёт, печатная форма или макет на форме — это поле табличного документа. Строк-объектов в нём нет, есть области ячеек. Выделить строку — значит сделать текущей область, охватывающую эту строку.
&НаКлиенте
Процедура ВыделитьСтрокуОтчета(НомерСтроки)
Область = Результат.Область("R" + Формат(НомерСтроки, "ЧГ=0"));
Результат.ТекущаяОбласть = Область;
КонецПроцедуры
Здесь Результат — реквизит формы типа «Табличный документ». Адрес "R12" даёт всю двенадцатую строку, "R12C1:R12C8" — ячейки с первой по восьмую колонку этой строки, "R5:R9" — диапазон строк. Формат(..., "ЧГ=0") нужен, чтобы номер 1200 не превратился в «1 200» с пробелом и адрес не сломался.
Полезные свойства области, когда нужно понять, что выделил пользователь:
- 🔢
Верх,Низ,Лево,Право— номера граничных строк и колонок; - 🧩
ТипОбласти— строки целиком, колонки целиком, прямоугольник ячеек или вся таблица; - 📝
Текст— текст ячейки, если область из одной ячейки.
Перебор всех выделенных пользователем фрагментов — через коллекцию ВыделенныеОбласти:
&НаКлиенте
Процедура ПоказатьВыделенное(Команда)
Для Каждого Область Из Результат.ВыделенныеОбласти Цикл
Сообщить(СтрШаблон("Строки с %1 по %2", Область.Верх, Область.Низ));
КонецЦикла;
КонецПроцедуры
Если пользователь щёлкнул по заголовку колонки, у области будет тип «колонки», а Верх и Низ не ограничат реальный диапазон данных. Проверяйте ТипОбласти, прежде чем перебирать строки по номерам.
Мышью строку табличного документа целиком выделяют щелчком по её номеру слева. Чтобы номера были видны, у поля табличного документа должно быть включено отображение заголовков строк.
Как выделить несколько строк сразу
Разрешить множественное выделение
За то, может ли пользователь выделить больше одной строки, отвечает свойство таблицы формы РежимВыделения. В конфигураторе оно на палитре свойств элемента, в коде — так:
Элементы.Список.РежимВыделения = РежимВыделенияТаблицы.Множественный;
Второе значение — РежимВыделенияТаблицы.Одиночный. Если групповая команда «почему-то обрабатывает только одну строку», первым делом проверьте этот режим.
Рядом есть свойство РежимВыделенияСтроки: РежимВыделенияСтрокиТаблицы.Строка подсвечивает строку целиком, РежимВыделенияСтрокиТаблицы.Ячейка — только текущую ячейку. На количество выделяемых строк оно не влияет, только на вид.
Программно отметить группу строк
Коллекция ВыделенныеСтроки поддерживает добавление и очистку. Пример — выделить в табличной части все строки с нулевым количеством, чтобы пользователь сразу их увидел:
&НаКлиенте
Процедура ВыделитьПустые(Команда)
Выделенные = Элементы.Товары.ВыделенныеСтроки;
Выделенные.Очистить();
Для Каждого Строка Из Объект.Товары Цикл
Если Строка.Количество = 0 Тогда
Выделенные.Добавить(Строка.ПолучитьИдентификатор());
КонецЕсли;
КонецЦикла;
Если Выделенные.Количество() > 0 Тогда
Элементы.Товары.ТекущаяСтрока = Выделенные[0];
КонецЕсли;
КонецПроцедуры
Последний блок ставит курсор на первую отмеченную строку: без этого выделение может оказаться за пределами видимой части таблицы.
Обработать выделенные строки на сервере
Типичная групповая команда в форме списка: собрать ссылки на клиенте и передать массив на сервер.
&НаКлиенте
Процедура УстановитьОтветственного(Команда)
Ссылки = Новый Массив;
Для Каждого Ссылка Из Элементы.Список.ВыделенныеСтроки Цикл
Если ТипЗнч(Ссылка) = Тип("ДокументСсылка.ЗаказКлиента") Тогда
Ссылки.Добавить(Ссылка);
КонецЕсли;
КонецЦикла;
Если Ссылки.Количество() = 0 Тогда
Возврат;
КонецЕсли;
УстановитьОтветственногоНаСервере(Ссылки, Ответственный);
Элементы.Список.Обновить();
КонецПроцедуры
Проверка ТипЗнч здесь не для красоты. Если в динамическом списке включена группировка, в выделение попадают и строки группировок — у них другой тип, и запись по такой «ссылке» упадёт. Тип документа подставьте свой.
Для табличной части алгоритм тот же, только в массив кладут идентификаторы, а на сервере строки находят через НайтиПоИдентификатору. Сам объект при этом на сервер передаётся вместе с формой, если серверная процедура объявлена без &НаСервереБезКонтекста.
Особенности управляемых форм
Почти всё, что ломается при переносе старого кода, связано с разделением клиента и сервера.
| Что нужно | Обычная форма (8.2 и режим совместимости) | Управляемая форма 8.3 |
|---|---|---|
| Текущая строка табличной части | Сама строка табличной части | Числовой идентификатор строки |
| Данные текущей строки | ТекущаяСтрока.Колонка | ТекущиеДанные.Колонка, только на клиенте |
| Где менять выделение | В любом месте модуля формы | На клиенте; на сервере — только присвоить свойство элемента |
| Строки табличного документа | Поле табличного документа | Реквизит «Табличный документ» + элемент поля |
Несколько практических следствий:
- 🖥️
ТекущиеДанныена сервере не существует. Код видаЭлементы.Товары.ТекущиеДанныевнутри&НаСерверевернётНеопределеноили вызовет ошибку — читайте данные на клиенте и передавайте параметром. - 🔁 После
Элементы.Список.Обновить()динамический список старается сохранить текущую строку. Если сохранить нужно другую — присвойтеТекущаяСтрокапосле обновления. - 🧭 В форме, которая открывается из другой, текущую строку удобно задавать в
ПриОткрытииили через параметр формы, а не в обработчике кнопки вызывающей формы. - 🌐 В веб-клиенте и тонком клиенте код работает одинаково, но каждый серверный вызов внутри цикла по выделенным строкам — это лишний запрос по сети. Собирайте массив и вызывайте сервер один раз.
Как подсветить строку цветом, а не выделением
Часто под «выделить строку» имеют в виду «покрасить». Выделение пропадает при первом щелчке пользователя, а цвет должен держаться. Для этого служит условное оформление формы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ЭлементУО = УсловноеОформление.Элементы.Добавить();
ПолеУО = ЭлементУО.Поля.Элементы.Добавить();
ПолеУО.Поле = Новый ПолеКомпоновкиДанных("Товары");
Отбор = ЭлементУО.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Отбор.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Товары.Количество");
Отбор.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
Отбор.ПравоеЗначение = 0;
ЭлементУО.Оформление.УстановитьЗначениеПараметра("ЦветФона", Новый Цвет(255, 235, 235));
КонецПроцедуры
Строки с нулевым количеством станут светло-красными и останутся такими, пока условие выполняется. В поле ПолеУО.Поле указывается имя элемента таблицы формы, а в отборе — путь к данным реквизита.
Без программирования то же самое настраивает пользователь: в форме списка через меню Ещё командой настройки списка, вкладка «Условное оформление». Такая настройка сохраняется только для него.
События при смене текущей строки
Реагировать на перемещение курсора нужно, например, чтобы показывать подробности строки в соседней панели или пересчитывать итог по выделенным.
| Событие | Когда вызывается | Типичное применение |
|---|---|---|
ПриАктивизацииСтроки | Курсор перешёл на другую строку | Обновить связанную панель, доступность кнопок |
ПриАктивизацииПоля | Сменилась текущая колонка | Подсказка по колонке |
Выбор | Двойной щелчок или Enter по строке | Открыть свою форму вместо стандартной |
ПриАктивизации (поле табличного документа) | Сменилась текущая область | Сумма по выделенным ячейкам, расшифровка |
Ключевой приём для ПриАктивизацииСтроки — откладывать тяжёлую работу. Событие срабатывает на каждое нажатие стрелки. Если в нём идёт серверный вызов, при быстрой прокрутке форма начинает тормозить. Решение — обработчик ожидания:
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
ОтключитьОбработчикОжидания("ОбновитьПанельСведений");
ПодключитьОбработчикОжидания("ОбновитьПанельСведений", 0.2, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьПанельСведений()
ТекущиеДанные = Элементы.Список.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
ЗаполнитьСведенияНаСервере(ТекущиеДанные.Ссылка);
КонецПроцедуры
Третий параметр Истина делает обработчик однократным. Пока пользователь листает, вызов всё время переносится; данные загрузятся, когда курсор остановится на 0,2 секунды.
Не стройте логику на том, что ПриАктивизацииСтроки отработает сразу после программной установки ТекущаяСтрока. Платформа вызывает это событие с задержкой. Если после перехода нужно что-то сделать немедленно — вызовите нужную процедуру явно в том же коде.
Проверка ТекущиеДанные = Неопределено обязательна: в пустом списке или после удаления последней строки текущей строки нет, и обращение к ТекущиеДанные.Ссылка даст ошибку.
Что проверить, если строка не выделяется
Частые вопросы
Можно ли выделить строку в форме из серверной процедуры?
Элементы.Список.ТекущаяСтрока в процедуре &НаСервере: свойство элемента вернётся на клиент вместе с формой. Читать ТекущиеДанные на сервере нельзя.Как снять выделение со всех строк?
Элементы.Список.ВыделенныеСтроки.Очистить(). Текущая строка при этом не сбрасывается — курсор останется на месте.Как узнать, сколько строк выделил пользователь?
Элементы.Список.ВыделенныеСтроки.Количество(). Для табличного документа количество выделенных фрагментов возвращает ВыделенныеОбласти.Количество().Как выделить все строки табличной части программно?
ВыделенныеСтроки и в цикле по коллекции добавьте идентификатор каждой строки. Режим выделения таблицы должен быть множественным.Почему после записи объекта курсор прыгает на первую строку?
ПередЗаписью и восстановите текущую строку по индексу в ПослеЗаписи.