Программное выделение строк в таблице формы 1С: код, режимы, события

· 9 мин

Содержание

Чтобы выделить строку в табличном поле 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 по строке; в параметрах приходит выбранная строка;
  • 🔲 ПриАктивизацииПоля — переход на другую колонку, полезен в режиме выделения «Ячейка»;
  • ✏️ ПередНачаломИзменения — перед редактированием строки, здесь можно запретить правку.

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

Деревья и иерархические списки: особенности выделения

Дерево значений на форме

Если таблица выводит реквизит типа «Дерево значений», в ВыделенныеСтроки лежат идентификаторы элементов любого уровня. Найти элемент можно через НайтиПоИдентификатору() у самого дерева. Чтобы выделить строку внутри свёрнутой ветки, сначала разверните родителя, иначе пользователь не увидит выделения.

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

Второй параметр Развернуть() — разворачивать ли подчинённые уровни. Для больших деревьев ставьте Ложь: полное раскрытие тысяч узлов заметно тормозит форму.

Иерархический справочник в динамическом списке

В иерархическом списке выделенные строки — ссылки, и среди них могут оказаться группы. Групповые операции обычно должны пропускать папки. Проверку удобно делать на сервере одним запросом:

&НаСервереБезКонтекста
Функция ТолькоЭлементы(Ссылки)
    Запрос = Новый Запрос(
    "ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура
    |ГДЕ Ссылка В (&Ссылки) И НЕ ЭтоГруппа");
    Запрос.УстановитьПараметр("Ссылки", Ссылки);
    Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецФункции

Чтобы открыть список внутри нужной группы, используйте свойство ТекущийРодитель, а курсор ставьте через ТекущаяСтрока.

Строки группировки

Если в динамическом списке включена группировка по колонке, в ВыделенныеСтроки попадают и строки группировок. Это не ссылки, а значения типа СтрокаГруппировкиДинамическогоСписка. Отсейте их перед обработкой:

Для Каждого Элемент Из Элементы.Список.ВыделенныеСтроки Цикл
    Если ТипЗнч(Элемент) = Тип("СтрокаГруппировкиДинамическогоСписка") Тогда
        Продолжить;
    КонецЕсли;
    Ссылки.Добавить(Элемент);
КонецЦикла;

Когда выделение не срабатывает: разбор симптомов

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

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

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