К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как установить курсор в дереве в 1С

Как программно установить курсор на нужную строку дерева в 1С через ТекущаяСтрока, найти строку по значению и развернуть родительские ветки.

Позиционирование курсора на нужной строке дерева — типовая задача при разработке управляемых форм в 1С. Она возникает при открытии формы с уже выбранным элементом, после добавления или изменения строки, при поиске по дереву и при синхронизации двух связанных таблиц. Во всех этих случаях используется свойство ТекущаяСтрока элемента формы, но работа с деревом имеет особенности: значение должно быть идентификатором строки коллекции, а не самой строкой данных.

Главное, что нужно понимать: свойству ТекущаяСтрока присваивается идентификатор строки (число, возвращаемое методом ПолучитьИдентификатор() или хранящееся в реквизите строки), а не ссылка на объект и не сами данные строки. Путаница между «строкой данных» и «идентификатором строки» — причина подавляющего большинства ошибок при работе с деревьями и динамическими списками на форме.

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

Как устроено позиционирование курсора в дереве

Дерево значений, выведенное на управляемую форму, представлено элементом формы типа «Таблица» с отображением в виде дерева. У этого элемента есть свойство ТекущаяСтрока, доступное и для чтения, и для записи. Чтение возвращает идентификатор текущей активной строки, запись — перемещает курсор на строку с указанным идентификатором.

Каждая строка дерева значений на форме имеет служебный идентификатор — целое число, уникальное в пределах коллекции. Получить его можно методом ПолучитьИдентификатор(), вызванным у объекта строки дерева. Обратный переход выполняется методом НайтиПоИдентификатору() у коллекции дерева.

Важно отличать дерево значений от динамического списка с группировкой. Для динамического списка в ТекущаяСтрока записывается ссылка на объект (или ключ записи регистра), а не числовой идентификатор. Смешение этих подходов — частая причина того, что курсор «не встает» на нужную строку.

Установка курсора на первую строку дерева

Простейший сценарий — спозиционироваться на первую строку верхнего уровня после заполнения дерева. Для этого получают коллекцию строк корня, берут первый элемент и передают его идентификатор в свойство элемента формы.

Процедура УстановитьКурсорНаПервуюСтроку()

СтрокиВерхнегоУровня = Дерево.ПолучитьЭлементы();

Если СтрокиВерхнегоУровня.Количество() > 0 Тогда

Элементы.Дерево.ТекущаяСтрока = СтрокиВерхнегоУровня[0].ПолучитьИдентификатор();

КонецЕсли;

КонецПроцедуры

Здесь Дерево — реквизит формы типа «ДеревоЗначений», а Элементы.Дерево — элемент формы, связанный с этим реквизитом. Проверка количества строк обязательна: попытка обратиться к несуществующему элементу пустой коллекции приведет к ошибке.

Аналогично устанавливается курсор на последнюю строку — используется индекс Количество() - 1. Это удобно после программного добавления новой строки, когда пользователь должен сразу увидеть и отредактировать её.

Установка курсора на строку по значению поля

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

Поиск в пределах одного уровня

Если известно, на каком уровне находится строка, используют НайтиСтроки() у соответствующей коллекции:

СтруктураПоиска = Новый Структура("Номенклатура", ИскомаяСсылка);

НайденныеСтроки = Дерево.ПолучитьЭлементы()[0].ПолучитьЭлементы();

Результат = НайденныеСтроки; // коллекция подчиненных строк

// Поиск через НайтиСтроки доступен у таблицы значений;

// для дерева выполняют перебор коллекции

Для Каждого СтрокаДерева Из Результат Цикл

Если СтрокаДерева.Номенклатура = ИскомаяСсылка Тогда

Элементы.Дерево.ТекущаяСтрока = СтрокаДерева.ПолучитьИдентификатор();

Прервать;

КонецЕсли;

КонецЦикла;

Рекурсивный поиск по всему дереву

Когда уровень вложенности неизвестен, применяют рекурсивную процедуру обхода. Найденный идентификатор передают через параметр или переменную формы:

Процедура НайтиИУстановитьСтроку(КоллекцияСтрок, ИскомоеЗначение, НайденныйИдентификатор)

Для Каждого СтрокаДерева Из КоллекцияСтрок Цикл

Если СтрокаДерева.Ссылка = ИскомоеЗначение Тогда

НайденныйИдентификатор = СтрокаДерева.ПолучитьИдентификатор();

Возврат;

КонецЕсли;

НайтиИУстановитьСтроку(СтрокаДерева.ПолучитьЭлементы(), ИскомоеЗначение, НайденныйИдентификатор);

Если НайденныйИдентификатор <> Неопределено Тогда

Возврат;

КонецЕсли;

КонецЦикла;

КонецПроцедуры

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

Порядок действий
  1. 1
    Найдите нужную строку дерева перебором или рекурсивным поиском по значению поля
  2. 2
    Получите её идентификатор методом ПолучитьИдентификатор()
  3. 3
    Разверните родительские ветки через Элементы.Дерево.Развернуть()
  4. 4
    Присвойте идентификатор свойству Элементы.Дерево.ТекущаяСтрока
  5. 5
    Проверьте визуально, что курсор встал на нужную строку

Развертывание веток перед установкой курсора

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

Родитель = НайденнаяСтрока.ПолучитьРодителя();

Пока Родитель <> Неопределено Цикл

Элементы.Дерево.Развернуть(Родитель.ПолучитьИдентификатор(), Ложь);

Родитель = Родитель.ПолучитьРодителя();

КонецЦикла;

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

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

Особые сценарии позиционирования

Курсор на добавленную строку

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

НоваяСтрока = РодительскаяКоллекция.Добавить();

НоваяСтрока.Наименование = "Новая позиция";

Элементы.Дерево.ТекущаяСтрока = НоваяСтрока.ПолучитьИдентификатор();

Восстановление позиции после обновления дерева

При перезаполнении дерева идентификаторы строк меняются — старые значения становятся недействительными. Поэтому перед обновлением сохраняют не идентификатор, а ключевое значение строки (например, ссылку), а после перезаполнения заново ищут строку по этому значению и устанавливают курсор. Это стандартный паттерн для форм с кнопкой «Обновить».

Позиционирование в динамическом списке с иерархией

Для динамического списка (например, иерархического справочника) механика иная: в ТекущаяСтрока записывается ссылка на элемент, и платформа сама раскрывает иерархию. Дополнительно свойство Отображение элемента формы должно допускать показ дерева (ОтображениеТаблицы.Дерево или ИерархическийСписок).

Сравнение вариантов

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

ТекущаяСтрока принимает числовой идентификатор строки. Родительские ветки нужно разворачивать вручную методом Развернуть().

Динамический список

ТекущаяСтрока принимает ссылку или ключ записи. Платформа сама позиционирует список, но отображение должно быть иерархическим.

Обычная таблица значений

Как и дерево, использует идентификатор строки, но без вложенности — развертывание не требуется.

Типичные ошибки и их устранение

Ошибки при установке курсора редко сопровождаются сообщениями — чаще просто «ничего не происходит». Поэтому важно знать типовые причины и проверять их последовательно.

Типичные ошибки
01
Присвоение ссылки вместо идентификатора строки для дерева значений — курсор не перемещается, ошибки нет
02
Использование старого идентификатора после перезаполнения дерева — идентификаторы пересоздаются, нужно искать строку заново
03
Установка курсора на строку в свернутой ветке без вызова Развернуть() — строка активна, но не видна
04
Присваивание ТекущаяСтрока до окончания заполнения дерева на сервере — позиционирование выполняется в ПриСозданииНаСервере слишком рано
05
Обращение к Элементы.Дерево при неверном имени элемента формы — возникает ошибка «Поле объекта не обнаружено»

Отдельно стоит упомянуть контекст выполнения. Если дерево заполняется в серверной процедуре, а позиционирование выполняется там же, результат может не отобразиться корректно. Установку ТекущаяСтрока надежнее выполнять на клиенте — например, в обработчике ПриОткрытии() или после возврата из серверного вызова.

Контрольные точки

Как проверить результат

Значение ТекущаяСтрока после присваивания
Норма

Возвращает тот же идентификатор, что был присвоен

Тревожный признак

Возвращает Неопределено или другой идентификатор

Видимость строки
Норма

Строка подсвечена и находится в видимой области

Тревожный признак

Строка активна, но скрыта в свернутой ветке

Срабатывание ПриАктивизацииСтроки
Норма

Обработчик вызывается с ожидаемой строкой

Тревожный признак

Обработчик не вызывается или получает другую строку

Ограничения и практические рекомендации

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

Для больших деревьев (тысячи строк) рекурсивный поиск при каждом позиционировании становится узким местом. Оптимизация — хранить соответствие «ключ строки → идентификатор» в реквизите формы и обновлять его при изменении дерева, либо искать только в раскрытой части, если логика задачи это допускает.

Если курсор нужно установить сразу при открытии формы, делайте это в обработчике ПриОткрытии на клиенте, а не в ПриСозданииНаСервере. К моменту открытия дерево уже передано на клиент, и позиционирование срабатывает стабильнее.
ПЗ
Практическое замечание

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

Итог

Что важно запомнить

Курсор в дереве 1С устанавливается через Элементы.Дерево.ТекущаяСтрока = ПолучитьИдентификатор() найденной строки. Родительские ветки разворачивайте до присваивания. После перезаполнения дерева ищите строку заново по ключевому значению, а не по старому идентификатору.

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

Почему присваивание ТекущаяСтрока не дает видимого эффекта?

Чаще всего строка находится в свернутой ветке — разверните родителей методом Развернуть() до установки курсора. Также проверьте, что передается именно идентификатор строки (число), а не ссылка или сама строка данных.

Чем идентификатор строки отличается от ссылки?

Идентификатор — служебное число, которое платформа присваивает строке на форме; он существует только в контексте данной формы. Ссылка — уникальный указатель на объект базы данных. Для дерева значений в ТекущаяСтрока передается идентификатор, для динамического списка — ссылка.

Как установить курсор после полного перезаполнения дерева?

Перед очисткой сохраните ключевое значение текущей строки (например, ссылку из колонки). После заполнения найдите строку с этим значением перебором или рекурсивным поиском и присвойте её новый идентификатор свойству ТекущаяСтрока. Старые идентификаторы после перезаполнения недействительны.

Вызывает ли программная установка курсора событие ПриАктивизацииСтроки?

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

Как спозиционироваться на строке в динамическом списке с иерархией?

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

Где правильнее устанавливать курсор — на сервере или на клиенте?

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