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