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