Фокус на нужное поле, кнопку или строку таблицы: приёмы для управляемых форм 1С 8.3
Содержание
Чтобы активизировать элемент управляемой формы в 1С 8.3, присвойте его свойству формы ТекущийЭлемент: ТекущийЭлемент = Элементы.Контрагент;. Отдельного метода вроде SetFocus() или Активизировать() у поля нет. Это частое заблуждение тех, кто пришёл из других языков: метод Активизировать() есть у самой формы, и он выводит на передний план окно, а не поле.
В английском синтаксисе то же свойство называется CurrentItem. Работает оно для полей ввода, кнопок и таблиц. Если присваивание есть, а курсор не двигается, почти всегда виновата не строка кода, а окружение: скрытая страница, асинхронный диалог или таблица, где фокус задаётся на трёх уровнях сразу.
Способы программно поставить фокус на элемент формы
В управляемой форме есть три рабочих способа. Они дополняют друг друга, а не заменяют.
| Способ | Где задаётся | Когда подходит |
|---|---|---|
Свойство ТекущийЭлемент | В коде, на клиенте или в ПриСозданииНаСервере | Фокус зависит от условий: новый объект, заполненность реквизитов, режим открытия |
| Флажок «Активизировать по умолчанию» | Палитра свойств элемента в конфигураторе | Фокус на открытии всегда один и тот же |
| Порядок элементов в дереве формы | Редактор формы, вкладка «Элементы» | Нужно поменять порядок перехода по Tab |
Свойство ТекущийЭлемент
Самый гибкий вариант. Пример: новый документ открывается на поле контрагента, а записанный — на табличной части.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Объект.Ссылка.Пустая() Тогда
ТекущийЭлемент = Элементы.Контрагент;
Иначе
ТекущийЭлемент = Элементы.Товары;
КонецЕсли;
КонецПроцедуры
Свойство можно и читать. Так проверяют, где сейчас стоит курсор пользователя:
&НаКлиенте
Процедура ПересчитатьВсё(Команда)
Если ТекущийЭлемент = Элементы.Сумма Тогда
// пользователь стоит в поле суммы — пересчитываем от неё
КонецЕсли;
КонецПроцедуры
Мини-кейс: открыть форму на первом незаполненном поле
Частая просьба пользователей: «пусть курсор сразу встаёт туда, что ещё не заполнено». Решается одной процедурой без перебора всех реквизитов — достаточно списка обязательных полей в нужном порядке:
&НаСервере
Процедура АктивизироватьПервоеПустое()
Порядок = СтрРазделить("Организация,Контрагент,Договор,Склад", ",");
Для Каждого ИмяПоля Из Порядок Цикл
Если Не ЗначениеЗаполнено(Объект[ИмяПоля]) Тогда
ТекущийЭлемент = Элементы[ИмяПоля];
Возврат;
КонецЕсли;
КонецЦикла;
ТекущийЭлемент = Элементы.Товары;
КонецПроцедуры
Вызовите её в конце ПриСозданииНаСервере, после типового заполнения. Здесь имена элементов совпадают с именами реквизитов. Если в вашей форме они различаются, храните пары «реквизит — элемент» в соответствии.
Флажок «Активизировать по умолчанию»
В палитре свойств поля есть флажок АктивизироватьПоУмолчанию. Он говорит платформе, какой элемент получит фокус при открытии формы. Код не нужен.
💡 Если флажок стоит у нескольких элементов, рассчитывать на «правильный» выбор платформы не стоит. Оставьте его у одного.
Порядок обхода и пропуск полей
В управляемой форме фокус по клавише Tab идёт в порядке элементов в дереве формы. Чтобы переставить поле, перетащите его в дереве — отдельного редактора порядка обхода, как в обычных формах, здесь нет.
Свойство ПропускатьПриВводе исключает поле из обхода клавиатурой. Мышью в такое поле попасть можно, из кода через ТекущийЭлемент — тоже.
События, связанные с получением и потерей фокуса
Здесь разработчиков чаще всего ждёт сюрприз. У обычного поля ввода управляемой формы нет событий «получил фокус» и «потерял фокус». Обработчиков с именами вроде ПриПолученииФокуса в палитре свойств поля вы не найдёте.
Что есть вместо них:
- 🔹
ПриИзменении— срабатывает, когда пользователь изменил значение и ушёл из поля или нажал Enter. Это самое близкое к «потере фокуса», но если значение не менялось, событие не вызывается. - 🔹
ОкончаниеВводаТекста— когда ввод текста завершён. Здесь можно перехватить и проверить введённую строку до того, как она станет значением. - 🔹
ИзменениеТекстаРедактирования— на каждое изменение текста при включённом свойстве обновления текста. Годится для живого поиска. - 🔹
ПриАктивизацииСтрокииПриАктивизацииПоля— у таблицы формы: пользователь перешёл на другую строку или в другую колонку. - 🔹
ПриАктивизации— у поля табличного документа: выделение переместилось на другую ячейку или область.
Если всё-таки нужно знать, куда ушёл курсор
Для обычных полей события нет, поэтому применяют обработчик ожидания. Он раз в полсекунды сравнивает ТекущийЭлемент с запомненным значением:
&НаКлиенте
Перем ПредыдущийЭлемент;
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ПодключитьОбработчикОжидания("ОтследитьФокус", 0.5);
КонецПроцедуры
&НаКлиенте
Процедура ОтследитьФокус() Экспорт
Если ТекущийЭлемент <> ПредыдущийЭлемент Тогда
// фокус сменился: ПредыдущийЭлемент -> ТекущийЭлемент
ПредыдущийЭлемент = ТекущийЭлемент;
КонецЕсли;
КонецПроцедуры
⚠️ Это нагрузка на клиент, а в веб-клиенте — лишняя работа браузера. Используйте приём, только если без него задача не решается, и отключайте обработчик через ОтключитьОбработчикОжидания при закрытии формы.
Не дать уйти из поля и вернуть фокус после ошибки
Параметра Отказ, который запрещает пользователю покинуть обычное поле, в управляемой форме нет. Задачу «не выпускать из поля, пока значение неверное» решают тремя путями.
Вернуть фокус обработчиком ожидания
Если поставить ТекущийЭлемент прямо в ПриИзменении, фокус часто всё равно уезжает. Платформа завершает переход, который начал пользователь клавишей Tab или кликом, уже после вашего обработчика. Выход — короткая отложенная установка:
&НаКлиенте
Процедура ИННПриИзменении(Элемент)
Если СтрДлина(Объект.ИНН) <> 10 И СтрДлина(Объект.ИНН) <> 12 Тогда
ПоказатьПредупреждение(, "ИНН должен содержать 10 или 12 цифр");
ПодключитьОбработчикОжидания("ВернутьФокусВИНН", 0.1, Истина);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ВернутьФокусВИНН() Экспорт
ТекущийЭлемент = Элементы.ИНН;
КонецПроцедуры
Третий параметр Истина означает однократный вызов. Без него обработчик будет вызываться каждые 0,1 секунды и «запрёт» пользователя в поле.
Отказ при окончании редактирования строки
У таблицы формы параметр Отказ есть — в событии ПередОкончаниемРедактирования. Если установить его в Истина, строка останется в режиме редактирования, а курсор не уйдёт из неё.
&НаКлиенте
Процедура ТоварыПередОкончаниемРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования, Отказ)
Если ОтменаРедактирования Тогда
Возврат; // пользователь нажал Esc — не мешаем
КонецЕсли;
Если Элемент.ТекущиеДанные.Количество <= 0 Тогда
Отказ = Истина;
Элементы.Товары.ТекущийЭлемент = Элементы.ТоварыКоличество;
КонецЕсли;
КонецПроцедуры
Проверка ОтменаРедактирования обязательна. Без неё пользователь не сможет выйти из строки даже клавишей Esc.
Сообщение, привязанное к полю
Для ошибок при записи удобнее не держать фокус силой, а показать сообщение с привязкой к полю. Пользователь щёлкает по сообщению — платформа сама активизирует нужный элемент.
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не указан договор";
Сообщение.Поле = "Объект.Договор";
Сообщение.Сообщить();
В конфигурациях на БСП то же самое делает ОбщегоНазначенияКлиентСервер.СообщитьПользователю с путём к реквизиту третьим параметром.
Активизация строк и колонок в таблице формы
С таблицами одного ТекущийЭлемент мало. Фокус задаётся на трёх уровнях: сама таблица, строка и колонка.
| Что нужно | Свойство или метод |
|---|---|
| Фокус на таблицу | ТекущийЭлемент = Элементы.Товары |
| Нужная строка | Элементы.Товары.ТекущаяСтрока = <идентификатор или ключ> |
| Нужная колонка | Элементы.Товары.ТекущийЭлемент = Элементы.ТоварыЦена |
| Сразу начать редактирование | Элементы.Товары.ИзменитьСтроку() |
| Добавить строку и встать в неё | Элементы.Товары.ДобавитьСтроку() |
Табличная часть и таблица значений на форме
Для коллекций данных формы в ТекущаяСтрока передают не саму строку, а её идентификатор. Пример: найти первую строку с нулевой ценой и поставить курсор в колонку цены.
&НаКлиенте
Процедура НайтиСтрокуБезЦены(Команда)
Для Каждого Строка Из Объект.Товары Цикл
Если Строка.Цена = 0 Тогда
Элементы.Товары.ТекущаяСтрока = Строка.ПолучитьИдентификатор();
Элементы.Товары.ТекущийЭлемент = Элементы.ТоварыЦена;
ТекущийЭлемент = Элементы.Товары;
Элементы.Товары.ИзменитьСтроку();
Возврат;
КонецЕсли;
КонецЦикла;
ПоказатьПредупреждение(, "Все цены заполнены");
КонецПроцедуры
Порядок важен: сначала строка и колонка, потом фокус на таблицу, в конце — режим редактирования.
Динамический список
В списке справочника или документа ТекущаяСтрока — это ссылка на объект. Строка должна попадать под текущий отбор, иначе курсор не встанет.
Элементы.Список.ТекущаяСтрока = НайденнаяСсылка;
💡 При вызове формы выбора нужную строку задают через параметр ТекущаяСтрока в параметрах ОткрытьФорму. Это стандартный параметр форм списка и выбора.
Тормоза в ПриАктивизацииСтроки
Если в ПриАктивизацииСтроки есть серверный вызов, при пролистывании списка стрелками клиент начинает «залипать». Практичный приём — отложить обработку:
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
ОтключитьОбработчикОжидания("ОбновитьПанельДанных");
ПодключитьОбработчикОжидания("ОбновитьПанельДанных", 0.2, Истина);
КонецПроцедуры
Пока пользователь листает, обработчик всё время откладывается. Сервер вызывается один раз — когда курсор остановился.
Элементы на страницах и в скрытых группах
Фокус нельзя поставить на элемент, который не виден. Платформа не выдаёт ошибку — курсор просто остаётся на месте. Проверьте всю цепочку родителей элемента.
- 📄 Страница не активна. Сначала переключите страницу, потом ставьте фокус:
Элементы.ГруппаСтраницы.ТекущаяСтраница = Элементы.СтраницаТовары;
ТекущийЭлемент = Элементы.Товары;
- 🙈
Видимость = Ложьу самого элемента или у любой группы выше. - 🚫
Доступность = Ложь— недоступное поле фокус не получает. Поле сТолькоПросмотр = Истинаполучает: в нём можно выделить и скопировать текст. - 📁 Свёрнутая группа. У свёртываемой группы есть методы
Показать()иСкрыть(). Разверните группу, затем активизируйте поле. - ⚙️ Функциональные опции и права. Если элемент скрыт из-за отключённой опции или нехватки прав, в коде лучше заранее проверить его видимость и выбрать запасной вариант.
Фокус после диалогов и в подчинённых окнах
В 8.3 с отключённым режимом модальности код после ПоказатьВопрос или ОткрытьФорму не ждёт закрытия окна. Если поставить ТекущийЭлемент сразу после вызова, это произойдёт до ответа пользователя — и диалог потом вернёт фокус на прежнее место.
Правильно — ставить фокус в обработчике оповещения:
&НаКлиенте
Процедура ОчиститьТовары(Команда)
Оповещение = Новый ОписаниеОповещения("ОчиститьТоварыЗавершение", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Очистить табличную часть?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ОчиститьТоварыЗавершение(Ответ, ДополнительныеПараметры) Экспорт
Если Ответ = КодВозвратаДиалога.Да Тогда
Объект.Товары.Очистить();
ТекущийЭлемент = Элементы.Контрагент;
КонецЕсли;
КонецПроцедуры
Своя форма-диалог
- 🔸 В открываемой форме фокус задаётся её собственным
ТекущийЭлементвПриСозданииНаСервереилиПриОткрытии. - 🔸 После закрытия окна с режимом
БлокироватьОкноВладельцафокус возвращается в форму-владельца, на тот элемент, где он был. Нужен другой — задайте его в обработчике оповещения о закрытии. - 🔸 Окно открыто, но спряталось за другими — вызовите у формы
Активизировать(). Это и есть тот метод, который путают с установкой фокуса на поле.
Обычные формы (толстый клиент)
В обычных формах принцип тот же, отличается только коллекция элементов:
| Форма | Как задать фокус |
|---|---|
| Управляемая | ТекущийЭлемент = Элементы.Контрагент; |
| Обычная | ТекущийЭлемент = ЭлементыФормы.Контрагент; |
В обычной форме порядок перехода по Tab настраивается отдельно, через порядок обхода в редакторе формы.
Почему фокус не встаёт: разбор ошибок
ТоварыНоменклатура вместо Номенклатура.ТекущийЭлемент = "Контрагент". Нужен сам объект элемента: ТекущийЭлемент = Элементы.Контрагент или Элементы["Контрагент"].Частые вопросы
Можно ли поставить фокус на кнопку командной панели?
ТекущийЭлемент = Элементы.ФормаЗаписатьИЗакрыть; переводит на неё фокус, и Enter нажмёт её. Имя кнопки смотрите в дереве элементов.Работает ли ТекущийЭлемент в веб-клиенте и мобильном клиенте?
Как выделить весь текст в поле после установки фокуса?
УстановитьГраницыВыделения() с позициями начала и конца. Вызывайте его после установки ТекущийЭлемент, на клиенте.Можно ли задать фокус в расширении конфигурации, не меняя типовую форму?
ПриОткрытии с вызовом после типового и присвойте ТекущийЭлемент. Типовой код при этом не меняется, обновления конфигурации проходят проще.