Как установить курсор в нужную позицию маскированного поля ввода в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов в 1С:Предприятии часто возникает необходимость упростить ввод данных для пользователя. Один из классических сценариев — использование масок ввода для сложных кодов, артикулов или номеров документов (например, 9999/99.99.9999/99999). Однако при попытке сделать поле «умным» и автоматически сдвигать курсор в начало определенной группы маски при клике разработчики сталкиваются с серьезными ограничениями платформы.

В этой статье мы подробно разберем, почему стандартными средствами платформы 1С сложно «поймать» позицию курсора в момент клика, проанализируем поведение функций работы с выделением текста и рассмотрим три практических способа решения этой задачи.

В чем заключается техническая сложность в 1С?

Главная проблема кроется в событийной модели элементов управления 1С. Для стандартного элемента «Поле ввода» на управляемой форме отсутствуют такие низкоуровневые события, как:

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

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

Давайте подробно рассмотрим, как работают функции позиционирования курсора и какие обходные пути (workarounds) существуют для реализации этой задачи.


Инструменты работы с курсором: ПолучитьГраницыВыделения() и УстановитьГраницыВыделения()

Для программного управления выделением и позицией курсора в 1С используются два ключевых метода элемента формы. Рассмотрим их синтаксис:

  1. ПолучитьГраницыВыделения(НачалоВыделения, КонецВыделения) — считывает текущую позицию курсора или границы выделенного фрагмента текста. Если текст не выделен, а курсор просто стоит в поле, переменные НачалоВыделения и КонецВыделения вернут одинаковое число (индекс символа, начиная с 1).
  2. УстановитьГраницыВыделения(НачалоВыделения, КонецВыделения) — устанавливает фокус и выделяет фрагмент текста. Чтобы просто установить курсор в нужную позицию без выделения текста, достаточно передать одинаковое значение в оба параметра: УстановитьГраницыВыделения(Позиция, Позиция).

Проанализируем ограничения при совместном использовании этих методов с маской ввода. Когда на поле ввода наложена жесткая маска (например, @9999/99.99.9999/99999), платформа 1С берет на себя строгий контроль за вводом символов. Попытки принудительно изменить границы выделения во время интерактивного ввода часто приводят к тому, что платформа сбрасывает курсор в начало или конец поля, игнорируя программные настройки.


Вариант решения №1: Разделение ввода на три независимых поля (Рекомендуемый UX-подход)

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

Гораздо более изящным и простым в реализации решением является разделение одного сложного поля на три отдельных поля ввода, визуально оформленных как единое целое. Для этого мы убираем общую маску и создаем три поля:

На форме эти поля располагаются горизонтально в одной группе без отступов, а между ними размещаются декоративные надписи-разделители "/". Чтобы сделать ввод бесшовным, настроим автоматический переход фокуса между полями при достижении максимальной длины ввода.

Разберем по шагам код обработчиков событий для автоперехода:


&НаКлиенте
Процедура ПолеГруппа1ПриИзменении(Элемент)
    // Как только введены все 4 символа первой группы, перекидываем фокус на вторую
    Если СтрДлина(Объект.ПолеГруппа1) = 4 Тогда
        ЭтаФорма.ТекущийЭлемент = Элементы.ПолеГруппа2;
        // Устанавливаем курсор в самую первую позицию второго поля
        Элементы.ПолеГруппа2.УстановитьГраницыВыделения(1, 1);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПолеГруппа2ПриИзменении(Элемент)
    // Длина маски второй группы "99.99.9999" составляет 10 символов с учетом точек
    Если СтрДлина(Объект.ПолеГруппа2) = 10 Тогда
        ЭтаФорма.ТекущийЭлемент = Элементы.ПолеГруппа3;
        Элементы.ПолеГруппа3.УстановитьГраницыВыделения(1, 1);
    КонецЕсли;
КонецПроцедуры

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


Вариант решения №2: Эмуляция события через быстрый обработчик ожидания

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

Разберем алгоритм настройки обработчика ожидания:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Подключаем обработчик с интервалом 0.1 секунды (100 миллисекунд)
    ПодключитьОбработчикОжидания("ПроверитьИПозиционироватьКурсор", 0.1, Ложь);
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьИПозиционироватьКурсор()
    ТекущийЭлементФормы = ЭтаФорма.ТекущийЭлемент;
    
    // Проверяем, что фокус находится именно на нашем маскированном поле
    Если ТекущийЭлементФормы = Элементы.НомерОперации Тогда
        
        НачалоВыделения = 0;
        КонецВыделения = 0;
        
        // Получаем текущую позицию курсора
        ТекущийЭлементФормы.ПолучитьГраницыВыделения(НачалоВыделения, КонецВыделения);
        
        // Наша маска: 9999/99.99.9999/99999
        // Индексы символов разделителей '/': 5 и 16
        // Первая группа: 1-4 символы
        // Вторая группа: 6-15 символы
        // Третья группа: 17-21 символы
        
        Если НачалоВыделения > 5 И НачалоВыделения < 16 Тогда
            // Пользователь кликнул во вторую группу.
            // Если курсор стоит не в начале группы (позиция 6), принудительно сдвигаем его туда
            Если НачалоВыделения <> 6 Тогда
                ТекущийЭлементФормы.УстановитьГраницыВыделения(6, 6);
            КонецЕсли;
            
        ИначеЕсли НачалоВыделения > 16 Тогда
            // Пользователь кликнул в третью группу.
            // Если курсор стоит не в начале группы (позиция 17), сдвигаем его туда
            Если НачалоВыделения <> 17 Тогда
                ТекущийЭлементФормы.УстановитьГраницыВыделения(17, 17);
            КонецЕсли;
        КонецЕсли;
        
    КонецЕсли;
КонецПроцедуры

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


Вариант решения №3: Использование элемента «Поле HTML-документа»

Для веб-клиента и конфигураций со сложным UX наиболее технологичным решением является перенос логики ввода в поле HTML-документа. Вместо стандартного поля ввода 1С мы можем отобразить HTML-страницу с элементом <input>, к которому подключена специализированная библиотека маскирования на JavaScript (например, IMask или jQuery Mask Plugin).

Преимущества данного подхода:

Мы проанализировали три принципиально разных подхода к реализации позиционирования курсора в маскированном поле ввода 1С. Выбор конкретного метода зависит от требований к интерфейсу вашего прикладного решения и готовности усложнять программный код ради удобства пользователей.

← На главную