Фокус на элемент формы из кода: ТекущийЭлемент, таблицы, списки

· 9 мин

Содержание

Чтобы программно установить фокус в 1С на нужное поле управляемой формы, присвойте его свойству формы ТекущийЭлемент: ТекущийЭлемент = Элементы.Наименование;. Отдельного метода вроде SetFocus в языке 1С нет — фокус переводится именно через это свойство, а для строк таблиц — через ТекущаяСтрока.

Строка работает в обработчике открытия формы, в команде по кнопке, в обработчике оповещения. Ниже — где именно её ставить, как перевести курсор в нужную колонку табличной части и что делать, если платформа «перебивает» фокус.

Свойство ТекущийЭлемент: основной способ установки фокуса

В управляемой форме у объекта ФормаКлиентскогоПриложения есть свойство ТекущийЭлемент. Оно и читается, и записывается:

  • 📖 чтение — какое поле сейчас активно;
  • ✍️ запись — куда перевести фокус.

Минимальный пример в модуле формы:

&НаКлиенте
Процедура ПерейтиКНаименованию(Команда)
	ТекущийЭлемент = Элементы.Наименование;
КонецПроцедуры

Внутри модуля формы писать ЭтаФорма. или ЭтотОбъект. перед свойством не обязательно. Если фокус ставится из общего модуля, передайте туда саму форму и обращайтесь Форма.ТекущийЭлемент = Форма.Элементы.Наименование.

Что можно сделать текущим элементом

ЭлементПолучает фокусКомментарий
Поле ввода, флажок, переключательДаОсновной случай
Таблица формыДаПлюс отдельно выбирается строка и колонка
Поле табличного документа, HTML-документаДаКурсор попадает внутрь поля
Группа, страницаНетАктивируют поле внутри группы
Невидимое или недоступное полеНетСначала включите Видимость и Доступность

Поле с флагом ТолькоПросмотр фокус получает: пользователь может выделить и скопировать текст, но не изменить его. А вот поле с Доступность = Ложь в обход клавиатуры и кода не попадёт.

Как узнать, где сейчас фокус

&НаКлиенте
Процедура ПоказатьАктивноеПоле(Команда)
	Если ТекущийЭлемент <> Неопределено Тогда
		Сообщить("Активен элемент: " + ТекущийЭлемент.Имя);
	КонецЕсли;
КонецПроцедуры

Приём пригодится для отладки: если фокус «уплывает», выводите имя текущего элемента в разных обработчиках и смотрите, где он меняется.

Фокус при открытии формы

Есть три способа сделать так, чтобы форма открывалась сразу с курсором в нужном поле. Выбор зависит от того, постоянное это поле или меняется от ситуации.

Способ 1. Без кода — «Активизировать по умолчанию»

В конфигураторе откройте форму, выделите поле в дереве элементов и в палитре свойств включите флажок «Активизировать по умолчанию». В коде этому соответствует свойство элемента АктивизироватьПоУмолчанию.

💡 Это самый надёжный вариант для постоянного поля: платформа сама ставит фокус после построения формы, обработчики писать не нужно.

Способ 2. В обработчике ПриОткрытии

Если поле выбирается по условию, ставьте фокус в клиентском обработчике ПриОткрытии:

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

Новый элемент справочника открывается с курсором в наименовании, существующий — в комментарии.

Способ 3. В ПриСозданииНаСервере

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

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	ИмяПоля = "";
	Если Параметры.Свойство("АктивноеПоле", ИмяПоля) И ЗначениеЗаполнено(ИмяПоля) Тогда
		Элемент = Элементы.Найти(ИмяПоля);
		Если Элемент <> Неопределено Тогда
			ТекущийЭлемент = Элемент;
		КонецЕсли;
	КонецЕсли;
КонецПроцедуры

Вызов из другой формы:

ПараметрыФормы = Новый Структура("Ключ, АктивноеПоле", Ссылка, "ИНН");
ОткрытьФорму("Справочник.Контрагенты.ФормаОбъекта", ПараметрыФормы);

Если параметр АктивноеПоле не объявлен в параметрах формы, при открытии произойдёт ошибка. Добавьте его на вкладке «Параметры» редактора формы, тип — Строка.

Табличная часть и списки: строка, колонка, редактирование

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

Что нужноСвойство или метод
Перевести фокус в таблицуТекущийЭлемент = Элементы.Товары
Выбрать строку табличной частиЭлементы.Товары.ТекущаяСтрока = Идентификатор
Выбрать колонкуЭлементы.Товары.ТекущийЭлемент = Элементы.ТоварыКоличество
Открыть ячейку на редактированиеЭлементы.Товары.ИзменитьСтроку()

Новая строка с курсором в колонке «Количество»

Типичная задача: подобрали номенклатуру, добавили строку и сразу хотим, чтобы пользователь ввёл количество.

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

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

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

Имя колонки берите из дерева элементов формы. Обычно оно складывается из имени таблицы и реквизита (ТоварыКоличество), но разработчик мог его переименовать.

Переход к строке по условию

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

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

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

Для реквизита формы типа «Дерево значений» действует та же схема с идентификатором. Разница в том, что строка может лежать внутри свёрнутой ветки, и её нужно сначала показать. Метод Развернуть таблицы-дерева раскрывает ветку по идентификатору строки-родителя:

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

Второй параметр Истина раскрывает ветку со всеми вложенными уровнями. Если свёрнуты и уровни выше, поднимитесь циклом по ПолучитьРодителя() до строки верхнего уровня и вызовите Развернуть для неё.

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

В списке справочника или документа ТекущаяСтрока — это ссылка на объект:

Элементы.Список.ТекущаяСтрока = СсылкаНаЭлемент;

Открыть форму списка сразу на нужной позиции можно стандартным параметром ТекущаяСтрока:

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

Реакция на смену строки и колонки

Когда пользователь или код меняет текущую строку, у таблицы формы срабатывает событие ПриАктивизацииСтроки, при смене колонки — ПриАктивизацииПоля. Это место, где удобно обновлять подсказку под таблицей или доступность команд.

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

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

Фокус по кнопке и после диалогов

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

После вопроса пользователю

ПоказатьВопрос не останавливает выполнение кода. Если поставить фокус сразу после вызова, его перехватит окно вопроса. Фокус нужно ставить в процедуре обработки ответа:

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

&НаКлиенте
Процедура ПослеВопросаОбИНН(Ответ, ДополнительныеПараметры) Экспорт
	Если Ответ = КодВозвратаДиалога.Да Тогда
		ТекущийЭлемент = Элементы.ИНН;
	КонецЕсли;
КонецПроцедуры

То же правило для ПоказатьПредупреждение, ПоказатьВводЗначения, ОткрытьФорму с оповещением о закрытии.

Поле на другой странице формы

Если поле лежит на неактивной закладке, сначала откройте закладку, потом ставьте фокус:

Элементы.ГруппаСтраницы.ТекущаяСтраница = Элементы.СтраницаРеквизиты;
ТекущийЭлемент = Элементы.КПП;

Так поведение предсказуемо в тонком и веб-клиенте: пользователь видит, куда перешёл курсор.

Фокус через сообщение пользователю

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

&НаКлиенте
Процедура ПроверитьРеквизиты(Команда)
	Если Не ЗначениеЗаполнено(Объект.ИНН) Тогда
		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = "Заполните ИНН контрагента";
		Сообщение.Поле = "Объект.ИНН";
		Сообщение.Сообщить();
	КонецЕсли;
КонецПроцедуры

В свойстве Поле указывается путь к данным (Объект.ИНН), а не имя элемента формы. Для строки табличной части путь включает индекс: Объект.Товары[2].Количество — индекс считается с нуля, то есть это третья строка.

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

Курсор в конец текста

Чтобы курсор встал не в начало, а в конец уже заполненного поля, после установки фокуса задайте границы выделения:

ТекущийЭлемент = Элементы.Комментарий;
Позиция = СтрДлина(Объект.Комментарий) + 1;
Элементы.Комментарий.УстановитьГраницыВыделения(Позиция, Позиция);

Когда фокус не ставится: ошибки и обходные приёмы

Ошибка в коде установки фокуса обычно бывает двух видов: исключение «Поле объекта не обнаружено» из-за неверного имени или «тихий» отказ — код выполнился, а курсор не сдвинулся.

Защита от неверного имени элемента

Обращение Элементы.ИмяКоторогоНет вызывает исключение. Когда имя приходит из параметра или настройки, используйте Элементы.Найти() — он вернёт Неопределено:

&НаКлиенте
Процедура УстановитьФокусПоИмени(ИмяЭлемента)
	Элемент = Элементы.Найти(ИмяЭлемента);
	Если Элемент = Неопределено Тогда
		Возврат;
	КонецЕсли;
	Если Не Элемент.Видимость Или Не Элемент.Доступность Тогда
		Возврат;
	КонецЕсли;
	ТекущийЭлемент = Элемент;
КонецПроцедуры

Проверку Видимость и Доступность делайте только для полей: у декораций и групп набор свойств другой. Если в процедуру могут попасть разные типы элементов, проверьте тип: ТипЗнч(Элемент) = Тип("ПолеФормы").

Отложенная установка через обработчик ожидания

Бывает, что фокус выставлен правильно, но платформа тут же переводит его обратно. Так случается в ПриИзменении поля: после выхода из обработчика курсор уходит к следующему полю по порядку обхода. Выручает отложенный вызов:

&НаКлиенте
Процедура ВидОперацииПриИзменении(Элемент)
	ПодключитьОбработчикОжидания("ФокусНаСумму", 0.1, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ФокусНаСумму() Экспорт
	ТекущийЭлемент = Элементы.Сумма;
КонецПроцедуры

Третий параметр Истина делает обработчик однократным. Интервал 0.1 секунды — минимальный, его хватает, чтобы платформа закончила свою обработку.

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

Управляемые и обычные формы: в чём разница

В обычных формах толстого клиента свойство тоже называется ТекущийЭлемент, но элементы берутся из коллекции ЭлементыФормы, а не Элементы:

// Обычная форма
ТекущийЭлемент = ЭлементыФормы.Наименование;

// Управляемая форма
ТекущийЭлемент = Элементы.Наименование;

Остальные отличия управляемых форм, которые влияют на фокус:

  • 🖥️ Клиент и сервер. Фокус — это состояние интерфейса. Меняйте его в клиентских процедурах; исключение — ПриСозданииНаСервере, когда форма ещё не показана.
  • 🧭 Порядок обхода. Клавиша Enter и Tab идут по полям в порядке их расположения в дереве элементов. Чтобы поле пропускалось при вводе, но кликом было доступно, включите у него свойство «Пропускать при вводе» (ПропускатьПриВводе).
  • 🔘 Кнопка по умолчанию. Какая кнопка сработает по Ctrl+Enter, задаёт флажок «Кнопка по умолчанию» в свойствах кнопки, а не установка фокуса.
  • 🪟 Активность окна. ТекущийЭлемент переводит фокус внутри формы. Чтобы вывести на передний план само окно уже открытой формы, вызовите у неё метод Активизировать().
  • 🌐 Веб-клиент. Установка фокуса работает так же, но отложенный приём с обработчиком ожидания здесь нужен чаще: браузер дольше перерисовывает форму.

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

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

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