При разработке управляемых форм в 1С:Предприятие 8.3 часто возникает необходимость в создании удобных пользовательских интерфейсов. Одной из таких задач является автоматическое изменение высоты многострочного поля ввода в зависимости от объема введенного текста. Это позволяет эффективно использовать пространство формы и улучшает визуальное восприятие информации. Однако, при попытке реализовать такую функциональность, разработчики сталкиваются с проблемой: при динамическом изменении высоты поля во время редактирования введенный текст сбрасывается, и теряется позиция курсора.
В этом руководстве мы подробно рассмотрим, как решить эту проблему, используя комбинацию событий и свойств элементов формы 1С, чтобы добиться желаемого поведения без потери данных.
Изначально, разработчик предпринял попытку реализовать автоподбор высоты поля с помощью события ПриИзменении, как показано в исходном коде:
&НаКлиенте
Процедура НаименованиеПриИзменении(Элемент)
ОбновитьВысоту;
КонецПроцедуры
&НаКлиенте
Процедура ОписаниеПриИзменении(Элемент)
ОбновитьВысоту;
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьВысоту
ОбновитьВысотуПоля("Наименование", Объект.Наименование);
ОбновитьВысотуПоля("Описание", Объект.Описание);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьВысотуПоля(ИмяПоля, ТекстПоля)
К = 0.8; // Коэффициент для расчета высоты
ЧС = СтрЧислоСтрок(ТекстПоля); // Получаем количество строк
ЧС = Мин(ЧС, 10); // Ограничиваем максимальную высоту 10 строками
ЧС = Макс(ЧС, 1); // Минимальная высота - 1 строка
БС_ЗадачиКС.ПрисвоитьБезопасно(Элементы[ИмяПоля].Высота, Окр(ЧС * К));
КонецПроцедуры
В этом примере функция ОбновитьВысотуПоля рассчитывает необходимую высоту на основе количества строк в тексте, ограничивая ее от 1 до 10 строк, и присваивает ее свойству Высота соответствующего элемента формы. Метод БС_ЗадачиКС.ПрисвоитьБезопасно, вероятно, является вспомогательной функцией для безопасного присвоения значения, но для большинства задач можно использовать прямое присвоение Элементы[ИмяПоля].Высота = Окр(ЧС * К);.
Этот подход работает, когда текст уже зафиксирован в реквизите формы (например, после ухода курсора из поля или нажатия Enter). Однако, когда пользователь активно вводит текст, событие ПриИзменении срабатывает не всегда, или срабатывает уже после фиксации значения, что не позволяет динамически изменять высоту *во время* набора. Попытки использовать событие АвтоПодбор привели к сбросу введенного текста, поскольку это событие запускало обновление формы, которое не было учтено для незафиксированных данных.
Выясним причину такого поведения. Когда мы изменяем свойства элементов формы (например, Высота) в то время, как в поле ввода находятся данные, не зафиксированные в связанном реквизите формы (т.е., пользователь еще не закончил ввод), система 1С может выполнить нежелательное обновление данных. Это происходит из-за внутренней логики работы управляемых форм: если в обработчике какого-либо события изменяются данные формы или состав ее элементов, а поле ввода при этом содержит незафиксированный текст, то этот текст будет заменен представлением тех данных, которые находятся в связанном реквизите формы после завершения контекстного вызова. Таким образом, теряется введенный текст и положение курсора.
Для того чтобы успешно изменять высоту многострочного поля во время редактирования, не теряя при этом введенный текст и позицию курсора, нам необходимо выполнить два ключевых шага:
ИзменениеТекстаРедактирования, которое срабатывает при каждом изменении текста в поле ввода, вызванном различными действиями пользователя (набор текста, вставка из буфера, отмена действия и т.д.).ОбновлениеТекстаРедактирования для поля ввода, чтобы предотвратить нежелательный сброс текста.Событие ИзменениеТекстаРедактирования идеально подходит для нашей задачи, поскольку оно вызывается сразу же, как только текст в поле изменяется, еще до фиксации значения в реквизите формы. Оно срабатывает даже раньше, чем АвтоПодбор. В обработчике этого события мы можем получить текущий текст, который пользователь вводит, и использовать его для расчета новой высоты.
Это критически важный шаг. Как мы уже выяснили, проблема сброса текста связана с механизмом обновления отображаемых данных в поле ввода. Свойство ОбновлениеТекстаРедактирования элемента формы типа ПолеВвода позволяет нам управлять этим поведением. Это свойство может принимать следующие значения:
Авто (значение по умолчанию): Система сама определяет, когда нужно обновить текст. Часто это приводит к нежелательному сбросу текста при динамических изменениях формы.ПриИзмененииЗначения: Содержимое поля ввода будет обновляться только в том случае, когда в связанный реквизит формы будет помещено значение, отличающееся от текущего значения реквизита. Это уменьшает количество обновлений, но может быть недостаточно в нашем случае.Никогда: Текст в поле ввода не будет изменяться даже при изменении значения связанного реквизита или обновлении формы. Именно это значение нам нужно, чтобы предотвратить потерю введенного текста.Установив свойство ОбновлениеТекстаРедактирования поля ввода в значение Никогда, мы сообщаем системе, что во время активного редактирования поле ввода должно полностью игнорировать любые попытки обновить его текст из реквизита формы. Это позволяет нам безопасно изменять другие свойства элемента, такие как его Высота, не беспокоясь о сбросе пользовательского ввода.
Давайте рассмотрим подробный алгоритм действий для реализации динамического изменения высоты поля ввода.
Изменим свойство поля ввода: Откройте форму, содержащую ваше многострочное поле (например, "Наименование" или "Описание"). Перейдите к свойствам этого поля. Найдите свойство ОбновлениеТекстаРедактирования и установите его значение в Никогда (или "Не использовать" в конфигураторе, что эквивалентно программному значению ОбновлениеТекстаРедактирования.Никогда).
Важно: Это необходимо сделать для каждого поля ввода, для которого вы хотите реализовать динамическое изменение высоты.
Создадим обработчик события ИзменениеТекстаРедактирования: Для каждого поля, высоту которого мы хотим динамически изменять, создадим обработчик события ИзменениеТекстаРедактирования. В этом обработчике мы будем вызывать нашу функцию для обновления высоты.
&НаКлиенте
Процедура НаименованиеИзменениеТекстаРедактирования(Элемент, Текст, СтандартнаяОбработка)
ОбновитьВысотуПоля("Наименование", Текст);
КонецПроцедуры
&НаКлиенте
Процедура ОписаниеИзменениеТекстаРедактирования(Элемент, Текст, СтандартнаяОбработка)
ОбновитьВысотуПоля("Описание", Текст);
КонецПроцедуры
Обратите внимание, что мы передаем параметр Текст из события в нашу функцию ОбновитьВысотуПоля. Это ключевой момент, так как Текст содержит актуальное содержимое поля ввода, которое вводит пользователь, в отличие от Объект.Наименование, которое может быть еще не обновлено.
Отредактируем функцию ОбновитьВысотуПоля: Функция, которая рассчитывает и присваивает высоту, остается практически такой же, как и в исходном примере. Единственное изменение — мы можем использовать прямое присвоение значения вместо вызова вспомогательной функции, если это не противоречит вашей архитектуре.
&НаКлиенте
Процедура ОбновитьВысотуПоля(ИмяПоля, ТекстПоля)
К = 0.8; // Коэффициент для расчета высоты, можно настроить под свои нужды
ЧС = СтрЧислоСтрок(ТекстПоля); // Получаем количество строк на основе текущего текста
ЧС = Мин(ЧС, 10); // Ограничиваем максимальную высоту, например, 10 строками
ЧС = Макс(ЧС, 1); // Минимальная высота - 1 строка
// Присваиваем новую высоту элементу формы
Элементы[ИмяПоля].Высота = Окр(ЧС * К);
// Если вы используете вспомогательную функцию для безопасного присвоения,
// как в исходном коде, то используйте ее:
// БС_ЗадачиКС.ПрисвоитьБезопасно(Элементы[ИмяПоля].Высота, Окр(ЧС * К));
КонецПроцедуры
В этой функции СтрЧислоСтрок(ТекстПоля) вычисляет количество строк, которое займет ТекстПоля. Коэффициент К позволяет немного скорректировать высоту, так как высота одной строки может варьироваться в зависимости от шрифта и масштабирования. Ограничения Мин и Макс позволяют избежать слишком большой или слишком маленькой высоты поля, делая его более предсказуемым для пользователя.
Мы успешно реализовали динамическое изменение высоты поля ввода. Однако, есть несколько дополнительных моментов, которые стоит рассмотреть:
Производительность: Событие ИзменениеТекстаРедактирования срабатывает очень часто (на каждое нажатие клавиши). Если расчет высоты сложный или таких полей очень много, это может повлиять на производительность. В большинстве случаев для простой функции СтрЧислоСтрок это не будет проблемой. Если же у вас возникают задержки, можно рассмотреть возможность использования таймера (например, УстановитьТаймер), чтобы обновлять высоту не на каждое нажатие, а с небольшой задержкой, скажем, 200-300 мс после последнего изменения.
Расчет высоты для переносов строк: Функция СтрЧислоСтрок считает именно количество строк, разделенных символами конца строки. Если текст переносится по ширине поля, но не содержит символов конца строки, СтрЧислоСтрок вернет 1. Чтобы учесть такие переносы, потребуется более сложная логика, которая учитывает ширину поля, размер шрифта и максимальную ширину строки, что выходит за рамки текущего решения.
Совместимость с табличными полями: Для табличных полей в 1С есть встроенные механизмы управления высотой ячеек: свойства ВысотаЯчейки и АвтовысотаЯчейки колонки табличного поля. Программное управление высотой ячеек табличного поля возможно при обработке события ПриВыводеСтроки() с помощью свойств ВысотаЯчейки и АвтоВысотаЯчейки объекта ОформлениеЯчейки. Однако, для обычных многострочных полей ввода на форме, описанный выше подход является основным.
Расширенный режим ввода: Для многострочного поля ввода может быть установлен расширенный режим ввода. В этом режиме допускается использование символа табуляции и стандартный поиск текста. Однако, при этом становится недоступным переход к следующему элементу формы по клавише Tab, что может повлиять на юзабилити, если пользователи привыкли к быстрому перемещению между полями.
Синтакс-Помощник: Как метко подметили участники обсуждения на форуме, многие особенности поведения элементов форм подробно описаны в Синтакс-Помощнике 1С. Всегда полезно обращаться к этому инструменту для глубокого понимания функциональности платформы и ее элементов.
Решение проблемы сброса текста при динамическом изменении высоты многострочного поля в 1С при редактировании сводится к правильному использованию события ИзменениеТекстаРедактирования и установке свойства ОбновлениеТекстаРедактирования в значение Никогда для предотвращения нежелательных обновлений. Этот подход позволяет создать более интерактивный и удобный интерфейс, где поля ввода адаптируются к объему контента, сохраняя при этом введенные пользователем данные и позицию курсора. Мы выяснили причину возникновения проблемы, проанализировали существующие механизмы и предложили эффективное решение, которое вы можете применять в своих разработках.