Программное выделение строк в таблице формы 1С: код, режимы, события
Содержание
Чтобы выделить строку в табличном поле 1С программно, присвойте её идентификатор свойству ТекущаяСтрока, а для нескольких строк добавьте идентификаторы в коллекцию ВыделенныеСтроки методом Добавить(). В управляемой форме это делается на клиенте: Элементы.Товары.ВыделенныеСтроки.Добавить(ИдСтроки). Чтобы пользователь мог выделять несколько строк сам, у таблицы должен стоять режим выделения «Множественный».
Ниже код для управляемых форм 1С 8.3 (элемент «Таблица формы») и для обычных форм (элемент «Табличное поле»). Объекты похожи, но тип значения в ТекущаяСтрока и ВыделенныеСтроки у них разный, и на этом ломается большинство примеров из интернета.
Что хранится в ТекущаяСтрока и ВыделенныеСтроки
Сначала разберёмся с типами. От источника данных зависит, что лежит в свойствах таблицы.
| Источник данных таблицы | Что в ТекущаяСтрока и ВыделенныеСтроки | Как получить данные строки |
|---|---|---|
| Табличная часть объекта, таблица значений реквизита формы (управляемая форма) | Число — идентификатор строки коллекции | Объект.Товары.НайтиПоИдентификатору(Ид) |
| Дерево значений реквизита формы | Число — идентификатор элемента дерева | ДеревоРеквизит.НайтиПоИдентификатору(Ид) |
| Динамический список справочника, документа | Ссылка на объект | Сама ссылка, данные — запросом или через ТекущиеДанные |
| Динамический список регистра | Ключ записи регистра | Свойства ключа (измерения, период) |
| Табличное поле обычной формы | Сама строка коллекции (СтрокаТабличнойЧасти, СтрокаТаблицыЗначений) | Обращение к полям строки напрямую |
Идентификатор строки в управляемой форме — не номер строки и не индекс. Он не меняется при сортировке и удалении соседних строк. Получают его методом ПолучитьИдентификатор() у самой строки.
Для чтения полей текущей строки на клиенте есть свойство ТекущиеДанные. Оно возвращает структуру с колонками строки, на которой стоит курсор. Если в таблице нет строк или курсор никуда не установлен, вернётся Неопределено — это нужно проверять всегда.
&НаКлиенте
Процедура ПоказатьТекущую(Команда)
ТекДанные = Элементы.Товары.ТекущиеДанные;
Если ТекДанные = Неопределено Тогда
Сообщить("Строка не выбрана");
Возврат;
КонецЕсли;
Сообщить("Номенклатура: " + ТекДанные.Номенклатура + ", кол-во " + ТекДанные.Количество);
КонецПроцедуры
Как программно выделить одну строку таблицы
Одиночное выделение — это установка текущей строки. Курсор встаёт на строку, таблица прокручивается к ней, строка подсвечивается.
Управляемая форма, табличная часть
Допустим, нужно поставить курсор на первую строку с определённым товаром. Находим строки через НайтиСтроки(), берём идентификатор и присваиваем его.
&НаКлиенте
Процедура ПерейтиКТовару(Номенклатура)
Отбор = Новый Структура("Номенклатура", Номенклатура);
Найденные = Объект.Товары.НайтиСтроки(Отбор);
Если Найденные.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Элементы.Товары.ТекущаяСтрока = Найденные[0].ПолучитьИдентификатор();
КонецПроцедуры
Встать на последнюю строку после добавления:
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Количество = 1;
Элементы.Товары.ТекущаяСтрока = НоваяСтрока.ПолучитьИдентификатор();
Динамический список
В списке справочника или документа в ТекущаяСтрока передают ссылку:
Элементы.Список.ТекущаяСтрока = НужныйДокумент;
Строка выделится, только если она попадает в список с учётом отбора. Если документ отфильтрован или помечен на удаление при скрытых помеченных, курсор останется на месте без ошибки.
Чтобы форма списка сразу открылась на нужном элементе, передайте ссылку в параметре открытия:
ОткрытьФорму("Справочник.Номенклатура.ФормаСписка",
Новый Структура("ТекущаяСтрока", Товар));
Обычная форма, табличное поле
Здесь присваивается не идентификатор, а сама строка:
Строка = ТабличнаяЧасть.Товары.Найти(Номенклатура, "Номенклатура");
Если Строка <> Неопределено Тогда
ЭлементыФормы.Товары.ТекущаяСтрока = Строка;
КонецЕсли;
Множественное выделение строк через ВыделенныеСтроки
ВыделенныеСтроки — коллекция, в которой лежат все отмеченные пользователем строки. Её можно читать и менять из кода: методы Добавить(), Удалить(), Очистить(), Количество().
Выделить строки по условию
Пример: выделить в табличной части все строки с нулевой ценой, чтобы пользователь сразу их увидел.
&НаКлиенте
Процедура ВыделитьБезЦены(Команда)
Таблица = Элементы.Товары;
Таблица.ВыделенныеСтроки.Очистить();
Для Каждого Строка Из Объект.Товары Цикл
Если Строка.Цена = 0 Тогда
Таблица.ВыделенныеСтроки.Добавить(Строка.ПолучитьИдентификатор());
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Без Очистить() в начале новые строки добавятся к уже выделенным. Если пользователь до нажатия кнопки отметил три строки вручную, они останутся в выборке.
Выделить все строки
Отдельного метода «выделить всё» у таблицы формы нет. Пользователь нажимает Ctrl+A, а из кода выделяют циклом по коллекции — так же, как выше, только без условия.
Обработать выделенные строки
Типичная задача: пользователь отметил строки, нажал команду, нужно что-то сделать с каждой. Для табличной части перебираем идентификаторы и находим строки:
&НаКлиенте
Процедура УдвоитьКоличество(Команда)
Для Каждого Ид Из Элементы.Товары.ВыделенныеСтроки Цикл
Строка = Объект.Товары.НайтиПоИдентификатору(Ид);
Если Строка <> Неопределено Тогда
Строка.Количество = Строка.Количество * 2;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Для динамического списка в коллекции лежат ссылки. Их удобно передать на сервер массивом и обработать одним запросом:
&НаКлиенте
Процедура Провести(Команда)
Ссылки = Новый Массив;
Для Каждого Элемент Из Элементы.Список.ВыделенныеСтроки Цикл
Ссылки.Добавить(Элемент);
КонецЦикла;
ПровестиНаСервере(Ссылки);
Элементы.Список.Обновить();
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПровестиНаСервере(Ссылки)
Для Каждого Ссылка Из Ссылки Цикл
ДокОбъект = Ссылка.ПолучитьОбъект();
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
КонецЦикла;
КонецПроцедуры
Перебор по ВыделенныеСтроки идёт в порядке выделения, а не в порядке строк на экране. Если важен порядок (например, нумерация), отсортируйте строки по НомерСтроки после того, как найдёте их.
Выделить диапазон строк с N по M
Иногда нужно отметить блок подряд идущих строк, например с 5-й по 12-ю, чтобы пользователь проставил им одну скидку. Номер строки табличной части начинается с 1, а индекс коллекции — с 0, поэтому берём Номер - 1:
&НаКлиенте
Процедура ВыделитьДиапазон(НачНомер, КонНомер)
Таблица = Элементы.Товары;
Таблица.ВыделенныеСтроки.Очистить();
Последний = Мин(КонНомер, Объект.Товары.Количество());
Для Номер = НачНомер По Последний Цикл
Строка = Объект.Товары[Номер - 1];
Таблица.ВыделенныеСтроки.Добавить(Строка.ПолучитьИдентификатор());
КонецЦикла;
Если Последний >= НачНомер Тогда
Таблица.ТекущаяСтрока = Объект.Товары[НачНомер - 1].ПолучитьИдентификатор();
КонецЕсли;
КонецПроцедуры
Для табличной части из 8 строк вызов ВыделитьДиапазон(5, 12) отметит строки 5, 6, 7 и 8: Мин() не даст выйти за границу коллекции. Текущую строку ставим на начало диапазона, чтобы таблица прокрутилась к выделенному блоку.
Снять выделение
Элементы.Товары.ВыделенныеСтроки.Очистить();
// или убрать одну строку:
Элементы.Товары.ВыделенныеСтроки.Удалить(Ид);
В обычной форме код тот же, только в коллекцию кладутся строки, а не идентификаторы: ЭлементыФормы.Товары.ВыделенныеСтроки.Добавить(Строка).
Режим выделения: настройка в конфигураторе и из кода
Если пользователь не может выделить больше одной строки, а ВыделенныеСтроки всегда содержит одну запись, дело в режиме таблицы.
В конфигураторе откройте форму, выделите элемент таблицы в дереве элементов и откройте палитру свойств (Alt+Enter). Нужные свойства:
| Свойство | Значения | На что влияет |
|---|---|---|
| Режим выделения | Одиночный / Множественный | Можно ли отметить несколько строк через Ctrl и Shift |
| Режим выделения строки | Строка / Ячейка | Подсвечивается вся строка или только текущая ячейка |
Из кода режим меняют, например, в ПриСозданииНаСервере, когда одна форма открывается и для просмотра, и для подбора:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("МножественныйВыбор") И Параметры.МножественныйВыбор Тогда
Элементы.Список.РежимВыделения = РежимВыделенияТаблицы.Множественный;
Иначе
Элементы.Список.РежимВыделения = РежимВыделенияТаблицы.Одиночный;
КонецЕсли;
КонецПроцедуры
В обычных формах перечисления называются иначе: РежимВыделенияТабличногоПоля.Множественный и РежимВыделенияСтрокиТабличногоПоля.Строка.
В режиме «Одиночный» вызовы ВыделенныеСтроки.Добавить() не дают множественного выделения: таблица держит одну строку. Если код «молча не работает», сначала проверьте этот режим.
Как узнать, на какой строке стоит курсор
Текущая строка и выделенные строки — разные вещи. Курсор всегда на одной строке, а выделено может быть двадцать. Обычно текущая строка входит в выделенные, но при обработке опирайтесь на то, что нужно задаче:
- 👉 команда действует на «эту строку» — берите
ТекущаяСтрокаилиТекущиеДанные; - 📦 команда групповая — перебирайте
ВыделенныеСтроки; - 🔢 нужен номер строки в табличной части — читайте поле
НомерСтрокиу найденной строки, а не идентификатор.
Пример: узнать номер текущей строки табличной части.
Ид = Элементы.Товары.ТекущаяСтрока;
Если Ид <> Неопределено Тогда
Номер = Объект.Товары.НайтиПоИдентификатору(Ид).НомерСтроки;
КонецЕсли;
На сервере свойства ТекущиеДанные нет: это клиентское свойство. Если серверной процедуре нужна текущая строка, передайте ей идентификатор параметром.
В динамическом списке ТекущиеДанные содержит только поля, которые выведены в список или отмечены в его настройках как используемые всегда. Если код обращается к полю, которого нет среди колонок, будет ошибка «Поле объекта не обнаружено». Решение — добавить поле в список или получить его по ссылке на сервере.
События при смене выделения и как их обрабатывать
Основное событие — ПриАктивизацииСтроки. Оно срабатывает, когда курсор переходит на другую строку, в том числе при выделении мышью с Ctrl и Shift. Типичное применение — показать подробности текущей записи в соседней панели или включить/выключить кнопки.
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
ОтключитьОбработчикОжидания("ОбновитьПанельДеталей");
ПодключитьОбработчикОжидания("ОбновитьПанельДеталей", 0.2, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьПанельДеталей()
Выделено = Элементы.Список.ВыделенныеСтроки.Количество();
Элементы.ФормаПровести.Доступность = (Выделено > 0);
Элементы.ДекорацияВыделено.Заголовок = "Выделено строк: " + Выделено;
КонецПроцедуры
Задержка через ПодключитьОбработчикОжидания нужна, когда в обработчике есть серверный вызов. Пользователь листает список стрелкой, событие идёт на каждую строку. С задержкой 0,2 секунды сервер дёргается один раз, когда курсор остановился.
Другие события таблицы, которые пригодятся рядом:
- 🖱
Выбор— двойной щелчок илиEnterпо строке; в параметрах приходит выбранная строка; - 🔲
ПриАктивизацииПоля— переход на другую колонку, полезен в режиме выделения «Ячейка»; - ✏️
ПередНачаломИзменения— перед редактированием строки, здесь можно запретить правку.
Не меняйте ВыделенныеСтроки внутри ПриАктивизацииСтроки без условия выхода — смена выделения может снова вызвать событие, и форма уйдёт в цикл с подвисанием.
Деревья и иерархические списки: особенности выделения
Дерево значений на форме
Если таблица выводит реквизит типа «Дерево значений», в ВыделенныеСтроки лежат идентификаторы элементов любого уровня. Найти элемент можно через НайтиПоИдентификатору() у самого дерева. Чтобы выделить строку внутри свёрнутой ветки, сначала разверните родителя, иначе пользователь не увидит выделения.
&НаКлиенте
Процедура ВыделитьВДереве(ЭлементДерева)
Родитель = ЭлементДерева.ПолучитьРодителя();
Если Родитель <> Неопределено Тогда
Элементы.Дерево.Развернуть(Родитель.ПолучитьИдентификатор(), Ложь);
КонецЕсли;
Ид = ЭлементДерева.ПолучитьИдентификатор();
Элементы.Дерево.ТекущаяСтрока = Ид;
Элементы.Дерево.ВыделенныеСтроки.Очистить();
Элементы.Дерево.ВыделенныеСтроки.Добавить(Ид);
КонецПроцедуры
Второй параметр Развернуть() — разворачивать ли подчинённые уровни. Для больших деревьев ставьте Ложь: полное раскрытие тысяч узлов заметно тормозит форму.
Иерархический справочник в динамическом списке
В иерархическом списке выделенные строки — ссылки, и среди них могут оказаться группы. Групповые операции обычно должны пропускать папки. Проверку удобно делать на сервере одним запросом:
&НаСервереБезКонтекста
Функция ТолькоЭлементы(Ссылки)
Запрос = Новый Запрос(
"ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура
|ГДЕ Ссылка В (&Ссылки) И НЕ ЭтоГруппа");
Запрос.УстановитьПараметр("Ссылки", Ссылки);
Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецФункции
Чтобы открыть список внутри нужной группы, используйте свойство ТекущийРодитель, а курсор ставьте через ТекущаяСтрока.
Строки группировки
Если в динамическом списке включена группировка по колонке, в ВыделенныеСтроки попадают и строки группировок. Это не ссылки, а значения типа СтрокаГруппировкиДинамическогоСписка. Отсейте их перед обработкой:
Для Каждого Элемент Из Элементы.Список.ВыделенныеСтроки Цикл
Если ТипЗнч(Элемент) = Тип("СтрокаГруппировкиДинамическогоСписка") Тогда
Продолжить;
КонецЕсли;
Ссылки.Добавить(Элемент);
КонецЦикла;
Когда выделение не срабатывает: разбор симптомов
Частые вопросы
Можно ли выделить строки программно в форме, открытой только для просмотра?
Сохраняется ли выделение после Обновить() у динамического списка?
Как выделить строку в табличной части при открытии формы документа?
ПриОткрытии или через ПодключитьОбработчикОжидания с малой задержкой: в ПриСозданииНаСервере установка ТекущаяСтрока для табличной части возможна, но надёжнее делать это на клиенте после отрисовки.Как подсветить строки цветом, не выделяя их?
Как запретить пользователю выделять группы в иерархическом списке?
ПриАктивизацииСтроки убирайте их из ВыделенныеСтроки с защитой от повторного вызова.