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