Как реализовать динамический подсчет символов в строке при вводе в 1С

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При разработке интерфейсов для отправки SMS или систем с жестким ограничением на длину ввода программисты часто сталкиваются с проблемой: в платформе 1С (особенно версии 7.7) содержимое текстового поля попадает в связанную переменную только после того, как поле потеряет фокус. Это делает невозможным «живой» подсчет знаков стандартными средствами. В этой статье мы разберем, как обойти это ограничение, используя ActiveX, внешние компоненты и механизмы платформы 8.x.

Проблема фокуса и способы её решения в 1С 7.7

Рассмотрим стандартную ситуацию: мы создаем реквизит формы «ТекстСообщения» и выводим его на форму. Если мы попробуем привязать к нему функцию для подсчета длины, мы обнаружим, что функция срабатывает только при нажатии Enter или переходе к другому элементу. Пока пользователь набирает текст, значение переменной ТекстСообщения остается старым. Проанализируем основные пути решения этой задачи в «семерке».

Решение №1: Использование ActiveX-элемента Microsoft Forms 2.0

Одним из самых эффективных способов является замена стандартного текстового поля 1С на внешний элемент управления (ActiveX). Для этого используется библиотека FM20.DLL, которая обычно устанавливается вместе с Microsoft Office. Посмотрим на правильный способ создания такого элемента.

Важный нюанс, который часто упускают разработчики: при создании объекта через метод СоздатьЭУ() (если используется компонента FormEx) или штатные средства, необходимо указывать полную версию программного идентификатора (ProgID). Если написать просто "Forms.TextBox", система выдаст ошибку. Правильный идентификатор — Forms.TextBox.1.


// Пример создания объекта в модуле формы 1С 7.7
Процедура ПриОткрытии()
    // Предполагаем, что на форме есть объект "АтрФормы" из FormEx
    ТекстБокс = АтрФормы.СоздатьЭУ("Forms.TextBox.1", "ПолеВводаТекста");
    // Теперь ТекстБокс доступен как объект ActiveX
КонецПроцедуры

У объекта Forms.TextBox.1 есть встроенное событие Change, которое срабатывает мгновенно при любом изменении текста. В отличие от стандартных полей 1С, это событие позволяет получать текст сразу. Выясним причину, почему это работает лучше: ActiveX-объекты работают в собственном потоке событий, и их свойства (например, Text) обновляются сразу после отрисовки символа операционной системой.

Решение №2: Использование перехвата клавиатуры через FormEx

Если внедрение ActiveX кажется избыточным, можно воспользоваться популярной внешней компонентой FormEx (или 1C++). Эти библиотеки позволяют «подписаться» на системные сообщения Windows. Проанализируем ситуацию: когда пользователь нажимает клавишу, форма получает сообщение от операционной системы.

Разберем по шагам, какие события нам доступны:

  1. ПриНажатииКнопкиКлавиатуры: Срабатывает в момент опускания клавиши. Особенность в том, что в этот микросекундный интервал символ еще не успевает добавиться в текстовый буфер поля ввода.
  2. ПриОтжатииКнопкиКлавиатуры: Это событие (KeyUp) более предпочтительно, так как к моменту его вызова символ уже фактически находится в поле ввода.

Посмотрим на пример кода, который позволяет перехватить ввод:


Процедура ПриОтжатииКнопкиКлавиатуры(КодКлавиши, Флаги, ФлагСтандартнойОбработки)
    // Метод работает через FormEx
    // Получаем текущее значение прямо из окна (через WinAPI или свойства компоненты)
    ТекущийТекст = Форма.АктивныйЭлемент().Текст; 
    Длина = СтрДлина(ТекущийТекст);
    Форма.ЗаголовокСчетчика.Заголовок("Символов: " + Длина);
КонецПроцедуры

Стоит отметить, что для гарантированного получения текста без потери фокуса профессионалы иногда используют функцию SendMessage с параметром WM_GETTEXT. Это позволяет «вытащить» строку напрямую из памяти окна (Edit control), игнорируя механизмы привязки данных 1С.

Особенности подсчета для SMS-сообщений

Рассмотрим подробнее прикладную задачу, упомянутую в обсуждении, — подсчет символов для SMS. Здесь важно не просто знать СтрДлина(), а учитывать правила сегментации сообщений операторами. Разберем логику вычислений:

Проанализируем пример функции для такого расчета:


Функция РассчитатьКоличествоSMS(Текст)
    Длина = СтрДлина(Текст);
    // Проверка на наличие кириллицы (упрощенно)
    ЕстьКириллица = 0;
    Для н = 1 По Длина Цикл
        Код = КодСимв(Сред(Текст, н, 1));
        Если (Код > 127) Тогда ЕстьКириллица = 1; Прервать; КонецЕсли;
    КонецЦикла;
    
    ЛимитПервой = ?(ЕстьКириллица = 1, 70, 160);
    ЛимитСегмента = ?(ЕстьКириллица = 1, 67, 153);
    
    Если Длина <= ЛимитПервой Тогда
        Возврат 1;
    Иначе
        Возврат Цел((Длина + ЛимитСегмента - 1) / ЛимитСегмента);
    КонецЕсли;
КонецФункции

Динамический подсчет в 1С 8.3 (Управляемые формы)

В современных версиях платформы (8.2 и 8.3) задача решается гораздо проще, так как разработчики платформы предусмотрели специальные события. Посмотрим на событие ИзменениеТекстаРедактирования. Оно специально предназначено для отслеживания ввода «на лету».

Рассмотрим, как это реализовать на клиенте:


&НаКлиенте
Процедура ТекстСообщенияИзменениеТекстаРедактирования(Элемент, Текст, СтандартнаяОбработка)
    // Параметр "Текст" содержит то, что пользователь видит в данный момент
    Длина = СтрДлина(Текст);
    Элементы.НадписьСчетчик.Заголовок = "Введено символов: " + Строка(Длина);
    
    // Можно также динамически менять цвет надписи, если лимит превышен
    Если Длина > 160 Тогда
        Элементы.НадписьСчетчик.ЦветТекста = ЦветаСтиля.ОсобыйТекст;
    КонецЕсли;
КонецПроцедуры

Также в свойствах поля ввода 8.3 можно установить свойство «Обновление текста редактирования» в значение При вводе текста. Это заставит платформу обновлять связанную переменную реквизита чаще, чем при потере фокуса, однако событие ИзменениеТекстаРедактирования все равно остается самым быстрым и точным способом для реализации мгновенного счетчика.

Альтернативный метод: ОбработкаОжидания

Если вы не хотите использовать внешние компоненты в 7.7, можно использовать ОбработкаОжидания. Разберем этот алгоритм: мы запускаем процедуру, которая раз в 0.5 или 1 секунду проверяет состояние формы. Однако, как было замечено в обсуждении, этот метод имеет серьезный недостаток в 1С 7.7: при попытке программного обращения к тексту активного поля ввода система может сбросить позицию курсора или выделить весь текст, что мешает пользователю печатать. Поэтому данный метод крайне не рекомендуется для полей с активным вводом.

Выводы и рекомендации

Подводя итог нашему анализу, можно выделить следующие рекомендации для разработчиков:

  1. Для 1С 7.7 лучшим выбором будет использование ActiveX Forms.TextBox.1, если в системе гарантированно установлен Office, либо перехват событий клавиатуры через FormEx (событие ПриОтжатииКнопкиКлавиатуры).
  2. Для 1С 8.x используйте штатное событие ИзменениеТекстаРедактирования, которое идеально подходит для этих целей.
  3. При реализации счетчика SMS всегда учитывайте наличие кириллических символов, так как это меняет размер сегмента более чем в два раза.

Используя эти методы, вы сможете создать современный и удобный интерфейс, который будет мгновенно реагировать на действия пользователя, обеспечивая качественный пользовательский опыт.

← На главную