Как определить активное поле ввода на форме 1С и вставить спецсимволы без потери фокуса?

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

При проектировании интерфейсов в «1С:Предприятии 8.3» на управляемых формах разработчики часто сталкиваются с задачей ввода спецсимволов (например, знака градуса °, надстрочных индексов ², ³ и других технических знаков). Попытка создать удобную экранную панель с кнопками для клика мышкой приводит к стандартной проблеме платформы: при нажатии на любую кнопку формы фокус ввода мгновенно переходит на саму кнопку. В результате платформа «забывает», в каком именно текстовом поле находился курсор пользователя, что делает невозможным простое определение целевого поля через свойство формы ТекущийЭлемент.

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

Причина проблемы и особенности поведения платформы

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

Попытки программно возвращать фокус назад и позиционировать курсор с помощью метода УстановитьГраницыВыделения часто сталкиваются с задержками отрисовки. Платформа синхронизирует данные между сервером и клиентом асинхронно, из-за чего визуальный фокус и каретка (курсор) могут «прыгать» или сбрасываться в начало строки. Выясним, как обойти эти ограничения.

---

Решение 1. Использование горячих клавиш (Hotkeys)

Это самый простой, быстрореализуемый и производительный способ. Если список необходимых спецсимволов невелик (до 5–10 штук), мы можем привязать их ввод к сочетаниям клавиш. Для ввода спецсимволов без доработки форм конфигурации можно использовать скрипт для печати спецсимволов в любой раскладке.

Преимущество метода: при вызове команды через сочетание клавиш (например, Ctrl+Alt+1) фокус ввода с текстового поля не теряется. Нам не нужно предварительно сохранять активный элемент — свойство ТекущийЭлемент формы продолжает указывать на то текстовое поле, где мигает курсор.

Рассмотрим пошагово реализацию этого механизма:

  1. Создадим на форме команду, например, ВставитьСимволГрадуса.
  2. В свойствах команды в поле «Сочетание клавиш» назначим комбинацию (например, Ctrl+Shift+D).
  3. Напишем обработчик команды, используя свойство элемента ВыделенныйТекст.

Посмотрим на пример кода:


&НаКлиенте
Процедура ВставитьСимволГрадуса(Команда)
    
    // Получаем элемент формы, на котором сейчас сфокусирован пользователь
    АктивныйЭлемент = ЭтаФорма.ТекущийЭлемент;
    
    // Проверяем, что активный элемент действительно является полем ввода текста
    Если ТипЗнч(АктивныйЭлемент) = Тип("ПолеФормы") 
        И АктивныйЭлемент.Вид = ВидПоляФормы.ПолеВвода Тогда
        
        // Вставляем символ точно в позицию курсора (каретки)
        АктивныйЭлемент.ВыделенныйТекст = "°";
        
    КонецЕсли;
    
КонецПроцедуры

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

---

Решение 2. Отслеживание фокуса через обработчик ожидания

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

Проанализируем этот алгоритм:

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

Разберем программную реализацию:


&НаКлиенте
Перем ИмяПоследнегоАктивногоПоля; // Переменная для хранения имени элемента

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Запускаем фоновый мониторинг активного элемента
    ПодключитьОбработчикОжидания("МониторингАктивногоЭлемента", 0.1, Истина);
КонецПроцедуры

&НаКлиенте
Процедура МониторингАктивногоЭлемента()
    
    ТекущийЭлементФормы = ЭтаФорма.ТекущийЭлемент;
    
    // Фиксируем только поля ввода, игнорируя кнопки и прочие элементы управления
    Если ТекущийЭлементФормы <> Неопределено 
        И ТипЗнч(ТекущийЭлементФормы) = Тип("ПолеФормы") 
        И ТекущийЭлементФормы.Вид = ВидПоляФормы.ПолеВвода Тогда
        
        ИмяПоследнегоАктивногоПоля = ТекущийЭлементФормы.Имя;
        
    КонецЕсли;
    
    // Переподключаем обработчик ожидания для следующей итерации
    ПодключитьОбработчикОжидания("МониторингАктивногоЭлемента", 0.1, Истина);
    
КонецПроцедуры

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


&НаКлиенте
Процедура НажатиеКнопкиСпецсимвола(Кнопка)
    
    Если ЗначениеЗаполнено(ИмяПоследнегоАктивногоПоля) Тогда
        
        ЦелевоеПоле = Элементы[ИмяПоследнегоАктивногоПоля];
        
        // Возвращаем фокус на поле ввода, чтобы восстановить каретку
        ЭтаФорма.ТекущийЭлемент = ЦелевоеПоле;
        
        // Вставляем требуемый символ (например, знак диаметра)
        ЦелевоеПоле.ВыделенныйТекст = "Ø";
        
    КонецЕсли;
    
КонецПроцедуры

---

Решение 3. Интеграция панели символов через «Поле HTML-документа» (без потери фокуса)

Наиболее изящное и профессиональное решение, полностью исключающее дергание фокуса, базируется на использовании HTML и JavaScript. Если мы выведем панель спецсимволов в виде HTML-страницы внутри элемента формы ПолеHTMLДокумента, мы сможем заблокировать переход фокуса средствами браузера. В качестве примера подобного интерфейса с HTML-кнопками можно использовать встраиваемый редактор форматированного текста.

Для этого на кнопки спецсимволов в HTML вешается событие onmousedown, в котором вызывается метод event.preventDefault(). Это предотвращает переход фокуса операционной системы с текстового поля 1С на элемент HTML, но при этом позволяет отработать клику.

Рассмотрим пошагово реализацию:

  1. Добавим на форму реквизит с типом «Строка» (например, АдресПанелиHTML) и свяжем его с элементом формы типа «Поле HTML-документа».
  2. Сформируем HTML-код панели с кнопками при создании формы.

Посмотрим на пример генерации HTML-кода на сервере:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Формируем HTML-код панели с блокировкой потери фокуса preventDefault()
    ТекстHTML = 
    "<html>
    |<head>
    |<style>
    |  body { margin: 0; padding: 5px; background-color: #f0f0f0; font-family: sans-serif; }
    |  .btn { display: inline-block; min-width: 30px; height: 30px; line-height: 30px; 
    |         text-align: center; margin: 3px; border: 1px solid #ccc; background: #fff; 
    |         cursor: pointer; font-size: 16px; user-select: none; }
    |  .btn:hover { background: #e0e0e0; }
    |</style>
    |</head>
    |<body>
    |  <!-- Используем event.preventDefault() для предотвращения потери фокуса в 1С -->
    |  <div class='btn' onmousedown='event.preventDefault(); sendSymbol(""°"")'>°</div>
    |  <div class='btn' onmousedown='event.preventDefault(); sendSymbol(""²"")'>²</div>
    |  <div class='btn' onmousedown='event.preventDefault(); sendSymbol(""³"")'>³</div>
    |  <div class='btn' onmousedown='event.preventDefault(); sendSymbol(""±"")'>±</div>
    |
    |  <script>
    |    function sendSymbol(symbol) {
    |      // Передаем выбранный символ обратно в платформу 1С
    |      window.postMessage(symbol, '*');
    |    }
    |  </script>
    |</body>
    |</html>";
    
    // Записываем HTML-код в реквизит, связанный с Полем HTML-документа
    АдресПанелиHTML = ТекстHTML;
    
    // В современных версиях платформы можно использовать временные файлы или напрямую строку данных
КонецПроцедуры

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


&НаКлиенте
Процедура ПанельHTMLДокументаСообщениеИзHTML(Элемент, ДанныеУведомления, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    ПолученныйСимвол = ДанныеУведомления.Данные;
    ТекущийЭлементФормы = ЭтаФорма.ТекущийЭлемент;
    
    // Фокус оставался на поле ввода, поэтому просто вставляем символ в позицию курсора
    Если ТекущийЭлементФормы <> Неопределено 
        И ТипЗнч(ТекущийЭлементФормы) = Тип("ПолеФормы") 
        И ТекущийЭлементФормы.Вид = ВидПоляФормы.ПолеВвода Тогда
        
        ТекущийЭлементФормы.ВыделенныйТекст = ПолученныйСимвол;
        
    КонецЕсли;
    
КонецПроцедуры

---

Решение 4. Стандартная кнопка списка выбора для каждого поля

Если внешняя панель не является обязательным требованием дизайна, можно использовать стандартные возможности платформы «1С:Предприятие», встроив выбор спецсимволов непосредственно в сами поля ввода. Это избавит интерфейс от лишних нагромождений.

Выполним следующие настройки для каждого текстового поля формы:

  1. Установим свойство поля ввода КнопкаСпискаВыбора = Истина.
  2. Установим свойство поля ввода РежимВыбораИзСписка = Ложь (чтобы пользователь мог вводить свой текст, а не только выбирать из списка).
  3. В обработчике события формы ПриОткрытии программно заполним списки выбора для наших полей.

Пример программного заполнения списка выбора:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    
    // Заполняем спецсимволами список выбора конкретного поля формы
    НовыйСписок = Элементы.ИмяТекстовогоПоля.СписокВыбора;
    НовыйСписок.Добавить("°", "Градус (°)");
    НовыйСписок.Добавить("²", "Квадрат (²)");
    НовыйСписок.Добавить("³", "Куб (³)");
    НовыйСписок.Добавить("±", "Плюс-минус (±)");
    
КонецПроцедуры

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

---

Резюме и рекомендации

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

← На главную