При разработке интерфейсов на управляемых формах 1С часто возникает задача реализовать удобный ввод текста с подсказками. Типичный сценарий: пользователь вводит часть слова, система предлагает список вариантов, пользователь выбирает нужный, и этот вариант добавляется в конец существующего текста. Однако разработчики сталкиваются с неприятной особенностью платформы — после выбора значения из списка 1С автоматически выделяет весь текст в поле ввода. Это заставляет пользователя совершать лишние действия (нажимать кнопку End или кликать мышью), что критически снижает эргономику ввода. В этой статье мы подробно разберем, как победить стандартное поведение платформы и заставить курсор встать точно в конец строки.
Проанализируем ситуацию. Когда мы используем событие АвтоПодборТекста, платформа ожидает, что выбранное значение полностью заменит введенный текст. Если мы пытаемся вмешаться в процесс через событие ОбработкаВыбора, возникают следующие сложности:
СтандартнаяОбработка = Ложь мы берем управление на себя, но платформа все равно выполняет внутренние алгоритмы отрисовки фокуса после завершения кода обработчика.УстановитьГраницыВыделения часто игнорируется, так как вызывается слишком рано — до того, как платформа окончательно «успокоит» элемент управления после выбора из списка.ОбновлениеТекстаРедактирования по умолчанию стоит в значении Авто, что заставляет систему принудительно синхронизировать визуальное отображение с реквизитом, вызывая выделение всего содержимого.Рассмотрим по шагам несколько эффективных способов решения этой задачи.
Этот метод считается наиболее корректным с точки зрения логики работы управляемого приложения. Суть заключается в том, чтобы запретить платформе самостоятельно обновлять текст в поле ввода в те моменты, когда она считает это нужным. Рассмотрим реализацию:
ОбновлениеТекстаРедактирования в значение Не использовать.В модуле формы при открытии пропишем следующий код:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Элементы.ИмяВашегоПоляВвода.ОбновитьТекстРедактирования();
КонецПроцедуры
Это позволит платформе «забыть» о необходимости выделять текст при каждом изменении реквизита, так как автоматическая синхронизация отключена.
Выясним интересную особенность: выполнение контекстного серверного вызова внутри обработчика события ИзменениеТекстаРедактирования или ОбработкаВыбора заставляет клиентское приложение «перерисовать» состояние элементов формы. Это часто приводит к тому, что нежелательное выделение текста пропадает само собой.
Посмотрим на пример реализации в событии ИзменениеТекстаРедактирования:
&НаКлиенте
Процедура ИмяПоляИзменениеТекстаРедактирования(Элемент, Текст, СтандартнаяОбработка)
// Ваша логика формирования подсказок или изменения данных
// ...
// Выполняем "пустой" серверный вызов
СброситьВыделениеНаСервере();
КонецПроцедуры
&НаСервере
Процедура СброситьВыделениеНаСервере()
// Здесь может быть пусто, сам факт вызова контекста формы решает проблему
КонецПроцедуры
Несмотря на то, что лишние серверные вызовы обычно не приветствуются, в задачах со сложным поведением полей ввода этот «костыль» является штатным средством платформы и работает стабильно.
Если нам нужно именно добавлять текст из подсказки в конец существующей строки, разберем самый эффективный код для события ОбработкаВыбора. Здесь важно правильно рассчитать позицию курсора и установить её после изменения реквизита.
&НаКлиенте
Процедура ИмяПоляОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
// Отменяем стандартное поведение, чтобы текст не затерся целиком
СтандартнаяОбработка = Ложь;
Если ЗначениеЗаполнено(ВыбранноеЗначение) Тогда
// Добавляем выбранное значение к текущему тексту реквизита
// Предположим, реквизит называется "ТекстВвода"
ТекстВвода = ТекстВвода + " " + ВыбранноеЗначение;
// Устанавливаем длину для позиционирования курсора
НоваяДлина = СтрДлина(ТекстВвода);
// Устанавливаем курсор в самый конец (начало и конец выделения совпадают)
Элемент.УстановитьГраницыВыделения(НоваяДлина + 1, НоваяДлина + 1);
КонецЕсли;
КонецПроцедуры
Важный нюанс: В некоторых версиях платформы УстановитьГраницыВыделения сработает только в том случае, если реквизит формы был изменен на сервере. Поэтому в ряде случаев присвоение ТекстВвода = ТекстВвода + ... лучше вынести в серверную процедуру.
Если ни один из вышеперечисленных способов не помогает (например, в веб-клиенте), проанализируем асинхронный подход. Проблема в том, что 1С выделяет текст сразу после завершения кода ОбработкаВыбора. Мы можем обмануть систему, вызвав установку курсора через ничтожно малый промежуток времени.
&НаКлиенте
Процедура ИмяПоляОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ТекстВвода = ТекстВвода + ВыбранноеЗначение;
// Запускаем процедуру установки курсора через 0.1 секунды
ПодключитьОбработчикОжидания("УстановитьКурсорВКонецПоля", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура УстановитьКурсорВКонецПоля()
Элемент = Элементы.ИмяПоляВвода;
Позиция = СтрДлина(ТекстВвода) + 1;
Элемент.УстановитьГраницыВыделения(Позиция, Позиция);
КонецПроцедуры
Этот метод гарантирует, что визуальное выделение, наложенное платформой, будет «перекрыто» вашей командой установки границ, так как она выполнится в следующем такте работы клиентского приложения.
Для достижения комфортного ввода текста без «прыгающего» выделения мы рекомендуем комбинировать подходы. Начните с установки ОбновлениеТекстаРедактирования в значение Не использовать. Если этого недостаточно, используйте метод с СтандартнаяОбработка = Ложь в событии ОбработкаВыбора совместно с явной установкой границ выделения. Помните, что поведение элементов управления может незначительно отличаться между тонким и веб-клиентом, поэтому всегда тестируйте интерфейсные решения в обоих режимах.