Фокус на элемент формы из кода: ТекущийЭлемент, таблицы, списки
Содержание
Чтобы программно установить фокус в 1С на нужное поле управляемой формы, присвойте его свойству формы ТекущийЭлемент: ТекущийЭлемент = Элементы.Наименование;. Отдельного метода вроде SetFocus в языке 1С нет — фокус переводится именно через это свойство, а для строк таблиц — через ТекущаяСтрока.
Строка работает в обработчике открытия формы, в команде по кнопке, в обработчике оповещения. Ниже — где именно её ставить, как перевести курсор в нужную колонку табличной части и что делать, если платформа «перебивает» фокус.
Свойство ТекущийЭлемент: основной способ установки фокуса
В управляемой форме у объекта ФормаКлиентскогоПриложения есть свойство ТекущийЭлемент. Оно и читается, и записывается:
- 📖 чтение — какое поле сейчас активно;
- ✍️ запись — куда перевести фокус.
Минимальный пример в модуле формы:
&НаКлиенте
Процедура ПерейтиКНаименованию(Команда)
ТекущийЭлемент = Элементы.Наименование;
КонецПроцедуры
Внутри модуля формы писать ЭтаФорма. или ЭтотОбъект. перед свойством не обязательно. Если фокус ставится из общего модуля, передайте туда саму форму и обращайтесь Форма.ТекущийЭлемент = Форма.Элементы.Наименование.
Что можно сделать текущим элементом
| Элемент | Получает фокус | Комментарий |
|---|---|---|
| Поле ввода, флажок, переключатель | Да | Основной случай |
| Таблица формы | Да | Плюс отдельно выбирается строка и колонка |
| Поле табличного документа, HTML-документа | Да | Курсор попадает внутрь поля |
| Группа, страница | Нет | Активируют поле внутри группы |
| Невидимое или недоступное поле | Нет | Сначала включите Видимость и Доступность |
Поле с флагом ТолькоПросмотр фокус получает: пользователь может выделить и скопировать текст, но не изменить его. А вот поле с Доступность = Ложь в обход клавиатуры и кода не попадёт.
Как узнать, где сейчас фокус
&НаКлиенте
Процедура ПоказатьАктивноеПоле(Команда)
Если ТекущийЭлемент <> Неопределено Тогда
Сообщить("Активен элемент: " + ТекущийЭлемент.Имя);
КонецЕсли;
КонецПроцедуры
Приём пригодится для отладки: если фокус «уплывает», выводите имя текущего элемента в разных обработчиках и смотрите, где он меняется.
Фокус при открытии формы
Есть три способа сделать так, чтобы форма открывалась сразу с курсором в нужном поле. Выбор зависит от того, постоянное это поле или меняется от ситуации.
Способ 1. Без кода — «Активизировать по умолчанию»
В конфигураторе откройте форму, выделите поле в дереве элементов и в палитре свойств включите флажок «Активизировать по умолчанию». В коде этому соответствует свойство элемента АктивизироватьПоУмолчанию.
💡 Это самый надёжный вариант для постоянного поля: платформа сама ставит фокус после построения формы, обработчики писать не нужно.
Способ 2. В обработчике ПриОткрытии
Если поле выбирается по условию, ставьте фокус в клиентском обработчике ПриОткрытии:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Если Объект.Ссылка.Пустая() Тогда
ТекущийЭлемент = Элементы.Наименование;
Иначе
ТекущийЭлемент = Элементы.Комментарий;
КонецЕсли;
КонецПроцедуры
Новый элемент справочника открывается с курсором в наименовании, существующий — в комментарии.
Способ 3. В ПриСозданииНаСервере
Свойство ТекущийЭлемент доступно и в серверном обработчике ПриСозданииНаСервере. Это удобно, когда решение зависит от данных, которые и так читаются на сервере, или от параметра формы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ИмяПоля = "";
Если Параметры.Свойство("АктивноеПоле", ИмяПоля) И ЗначениеЗаполнено(ИмяПоля) Тогда
Элемент = Элементы.Найти(ИмяПоля);
Если Элемент <> Неопределено Тогда
ТекущийЭлемент = Элемент;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Вызов из другой формы:
ПараметрыФормы = Новый Структура("Ключ, АктивноеПоле", Ссылка, "ИНН");
ОткрытьФорму("Справочник.Контрагенты.ФормаОбъекта", ПараметрыФормы);
Если параметр АктивноеПоле не объявлен в параметрах формы, при открытии произойдёт ошибка. Добавьте его на вкладке «Параметры» редактора формы, тип — Строка.
Табличная часть и списки: строка, колонка, редактирование
У таблицы формы фокус устроен в два уровня. Сначала форма должна сделать текущей саму таблицу, затем таблица — нужную строку и колонку.
| Что нужно | Свойство или метод |
|---|---|
| Перевести фокус в таблицу | ТекущийЭлемент = Элементы.Товары |
| Выбрать строку табличной части | Элементы.Товары.ТекущаяСтрока = Идентификатор |
| Выбрать колонку | Элементы.Товары.ТекущийЭлемент = Элементы.ТоварыКоличество |
| Открыть ячейку на редактирование | Элементы.Товары.ИзменитьСтроку() |
Новая строка с курсором в колонке «Количество»
Типичная задача: подобрали номенклатуру, добавили строку и сразу хотим, чтобы пользователь ввёл количество.
&НаКлиенте
Процедура ДобавитьСтрокуИПерейтиККоличеству(Номенклатура)
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Номенклатура = Номенклатура;
НоваяСтрока.Количество = 1;
ТекущийЭлемент = Элементы.Товары;
Элементы.Товары.ТекущаяСтрока = НоваяСтрока.ПолучитьИдентификатор();
Элементы.Товары.ТекущийЭлемент = Элементы.ТоварыКоличество;
Элементы.Товары.ИзменитьСтроку();
КонецПроцедуры
Ключевой момент: ТекущаяСтрока у табличной части принимает не номер строки и не саму строку, а идентификатор из ПолучитьИдентификатор(). Передача НоваяСтрока или НоваяСтрока.НомерСтроки — частая причина, почему курсор остаётся на месте.
Имя колонки берите из дерева элементов формы. Обычно оно складывается из имени таблицы и реквизита (ТоварыКоличество), но разработчик мог его переименовать.
Переход к строке по условию
Найти строку и поставить на неё курсор:
&НаКлиенте
Процедура НайтиСтрокуПоНоменклатуре(Номенклатура)
Отбор = Новый Структура("Номенклатура", Номенклатура);
Найденные = Объект.Товары.НайтиСтроки(Отбор);
Если Найденные.Количество() > 0 Тогда
ТекущийЭлемент = Элементы.Товары;
Элементы.Товары.ТекущаяСтрока = Найденные[0].ПолучитьИдентификатор();
КонецЕсли;
КонецПроцедуры
Дерево значений на форме
Для реквизита формы типа «Дерево значений» действует та же схема с идентификатором. Разница в том, что строка может лежать внутри свёрнутой ветки, и её нужно сначала показать. Метод Развернуть таблицы-дерева раскрывает ветку по идентификатору строки-родителя:
Родитель = НайденнаяСтрока.ПолучитьРодителя();
Если Родитель <> Неопределено Тогда
Элементы.Дерево.Развернуть(Родитель.ПолучитьИдентификатор(), Истина);
КонецЕсли;
ТекущийЭлемент = Элементы.Дерево;
Элементы.Дерево.ТекущаяСтрока = НайденнаяСтрока.ПолучитьИдентификатор();
Второй параметр Истина раскрывает ветку со всеми вложенными уровнями. Если свёрнуты и уровни выше, поднимитесь циклом по ПолучитьРодителя() до строки верхнего уровня и вызовите Развернуть для неё.
Динамический список
В списке справочника или документа ТекущаяСтрока — это ссылка на объект:
Элементы.Список.ТекущаяСтрока = СсылкаНаЭлемент;
Открыть форму списка сразу на нужной позиции можно стандартным параметром ТекущаяСтрока:
ОткрытьФорму("Справочник.Номенклатура.ФормаСписка",
Новый Структура("ТекущаяСтрока", СсылкаНаЭлемент));
Реакция на смену строки и колонки
Когда пользователь или код меняет текущую строку, у таблицы формы срабатывает событие ПриАктивизацииСтроки, при смене колонки — ПриАктивизацииПоля. Это место, где удобно обновлять подсказку под таблицей или доступность команд.
Не ставьте в этих обработчиках ТекущийЭлемент на другой элемент без условия: перевод фокуса снова вызовет активизацию, и форма начнёт «дёргаться». Если без этого никак, используйте флаг-переменную модуля, чтобы обработчик не срабатывал повторно.
ПриАктивизацииСтроки вызывается часто, в том числе при прокрутке стрелками. Тяжёлые серверные вызовы из него лучше откладывать через ПодключитьОбработчикОжидания.
Фокус по кнопке и после диалогов
С кнопкой всё просто: команда формы выполняется на клиенте, присвоение ТекущийЭлемент в её обработчике срабатывает сразу. Сложности начинаются, когда между нажатием и установкой фокуса есть асинхронный диалог.
После вопроса пользователю
ПоказатьВопрос не останавливает выполнение кода. Если поставить фокус сразу после вызова, его перехватит окно вопроса. Фокус нужно ставить в процедуре обработки ответа:
&НаКлиенте
Процедура ПроверитьИНН(Команда)
Если Не ЗначениеЗаполнено(Объект.ИНН) Тогда
Оповещение = Новый ОписаниеОповещения("ПослеВопросаОбИНН", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "ИНН не заполнен. Заполнить сейчас?",
РежимДиалогаВопрос.ДаНет);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПослеВопросаОбИНН(Ответ, ДополнительныеПараметры) Экспорт
Если Ответ = КодВозвратаДиалога.Да Тогда
ТекущийЭлемент = Элементы.ИНН;
КонецЕсли;
КонецПроцедуры
То же правило для ПоказатьПредупреждение, ПоказатьВводЗначения, ОткрытьФорму с оповещением о закрытии.
Поле на другой странице формы
Если поле лежит на неактивной закладке, сначала откройте закладку, потом ставьте фокус:
Элементы.ГруппаСтраницы.ТекущаяСтраница = Элементы.СтраницаРеквизиты;
ТекущийЭлемент = Элементы.КПП;
Так поведение предсказуемо в тонком и веб-клиенте: пользователь видит, куда перешёл курсор.
Фокус через сообщение пользователю
При проверке заполнения не всегда нужно сразу перебрасывать курсор. Удобнее показать сообщение, привязанное к полю: пользователь щёлкает по нему в окне сообщений, и платформа сама активирует нужный элемент.
&НаКлиенте
Процедура ПроверитьРеквизиты(Команда)
Если Не ЗначениеЗаполнено(Объект.ИНН) Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Заполните ИНН контрагента";
Сообщение.Поле = "Объект.ИНН";
Сообщение.Сообщить();
КонецЕсли;
КонецПроцедуры
В свойстве Поле указывается путь к данным (Объект.ИНН), а не имя элемента формы. Для строки табличной части путь включает индекс: Объект.Товары[2].Количество — индекс считается с нуля, то есть это третья строка.
В конфигурациях на БСП то же делает процедура ОбщегоНазначенияКлиентСервер.СообщитьПользователю: третьим параметром ей передают путь к полю. Если несколько полей не заполнены, выводите сообщение по каждому, а ТекущийЭлемент ставьте только на первое — иначе курсор будет прыгать.
Курсор в конец текста
Чтобы курсор встал не в начало, а в конец уже заполненного поля, после установки фокуса задайте границы выделения:
ТекущийЭлемент = Элементы.Комментарий;
Позиция = СтрДлина(Объект.Комментарий) + 1;
Элементы.Комментарий.УстановитьГраницыВыделения(Позиция, Позиция);
Когда фокус не ставится: ошибки и обходные приёмы
Ошибка в коде установки фокуса обычно бывает двух видов: исключение «Поле объекта не обнаружено» из-за неверного имени или «тихий» отказ — код выполнился, а курсор не сдвинулся.
Защита от неверного имени элемента
Обращение Элементы.ИмяКоторогоНет вызывает исключение. Когда имя приходит из параметра или настройки, используйте Элементы.Найти() — он вернёт Неопределено:
&НаКлиенте
Процедура УстановитьФокусПоИмени(ИмяЭлемента)
Элемент = Элементы.Найти(ИмяЭлемента);
Если Элемент = Неопределено Тогда
Возврат;
КонецЕсли;
Если Не Элемент.Видимость Или Не Элемент.Доступность Тогда
Возврат;
КонецЕсли;
ТекущийЭлемент = Элемент;
КонецПроцедуры
Проверку Видимость и Доступность делайте только для полей: у декораций и групп набор свойств другой. Если в процедуру могут попасть разные типы элементов, проверьте тип: ТипЗнч(Элемент) = Тип("ПолеФормы").
Отложенная установка через обработчик ожидания
Бывает, что фокус выставлен правильно, но платформа тут же переводит его обратно. Так случается в ПриИзменении поля: после выхода из обработчика курсор уходит к следующему полю по порядку обхода. Выручает отложенный вызов:
&НаКлиенте
Процедура ВидОперацииПриИзменении(Элемент)
ПодключитьОбработчикОжидания("ФокусНаСумму", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ФокусНаСумму() Экспорт
ТекущийЭлемент = Элементы.Сумма;
КонецПроцедуры
Третий параметр Истина делает обработчик однократным. Интервал 0.1 секунды — минимальный, его хватает, чтобы платформа закончила свою обработку.
Управляемые и обычные формы: в чём разница
В обычных формах толстого клиента свойство тоже называется ТекущийЭлемент, но элементы берутся из коллекции ЭлементыФормы, а не Элементы:
// Обычная форма
ТекущийЭлемент = ЭлементыФормы.Наименование;
// Управляемая форма
ТекущийЭлемент = Элементы.Наименование;
Остальные отличия управляемых форм, которые влияют на фокус:
- 🖥️ Клиент и сервер. Фокус — это состояние интерфейса. Меняйте его в клиентских процедурах; исключение —
ПриСозданииНаСервере, когда форма ещё не показана. - 🧭 Порядок обхода. Клавиша Enter и Tab идут по полям в порядке их расположения в дереве элементов. Чтобы поле пропускалось при вводе, но кликом было доступно, включите у него свойство «Пропускать при вводе» (
ПропускатьПриВводе). - 🔘 Кнопка по умолчанию. Какая кнопка сработает по Ctrl+Enter, задаёт флажок «Кнопка по умолчанию» в свойствах кнопки, а не установка фокуса.
- 🪟 Активность окна.
ТекущийЭлементпереводит фокус внутри формы. Чтобы вывести на передний план само окно уже открытой формы, вызовите у неё методАктивизировать(). - 🌐 Веб-клиент. Установка фокуса работает так же, но отложенный приём с обработчиком ожидания здесь нужен чаще: браузер дольше перерисовывает форму.
Если дорабатываете типовую конфигурацию, ставьте фокус из расширения: в обработчике ПриОткрытии с директивой &После. Так типовой модуль формы не меняется, и обновления пройдут без ручного сравнения.