Работа с табличным документом в 1С часто вызывает у пользователей ассоциации с Excel. Они ожидают привычного поведения: скопировал область, вставил, и все работает. Однако стандартный механизм вставки в 1С (Ctrl+V) копирует не только значения, но и форматирование (рамки, шрифты, цвета), что часто разрушает макет отчета или печатной формы. Более того, иногда требуется валидировать вставляемые данные или вставлять только значения в защищенные области.
В этой статье мы подробно разберем, почему стандартные события формы не всегда помогают, и рассмотрим несколько работающих стратегий перехвата клавиатурных сокращений и программной обработки буфера обмена.
Первое, что приходит в голову разработчику — использовать штатное событие управляемой формы или табличного документа. Давайте проанализируем ситуацию с событием ПриВставкеИзБуфераОбмена.
Согласно документации и опыту сообщества, это событие действительно существует. Однако, как верно замечено в обсуждении, оно имеет существенное ограничение:
Событие срабатывает только при вставке специфических объектов, таких как картинки или файлы.
Если пользователь копирует текст (или ячейки Excel, которые по сути являются текстом в буфере) и нажимает Ctrl+V, находясь в табличном документе или текстовом поле, платформа 1С выполняет стандартную вставку, минуя этот обработчик. Следовательно, полагаться на него для перехвата текстовых данных мы не можем.
Самый эффективный способ перехватить нажатие клавиш без использования внешних компонент (Native API) — это использование приоритета команд формы (в некоторых случаях может потребоваться программное изменение форм).
Суть метода: Мы создаем собственную команду на форме и назначаем ей сочетание клавиш Ctrl+V. В этом случае, когда пользователь нажмет эту комбинацию, платформа не будет выполнять стандартную вставку, а запустит наш программный код.
В редакторе формы перейдем на вкладку «Команды». Создадим новую команду, назовем ее, например, ВставитьИзБуфераСпециальная. В свойствах этой команды найдем поле Сочетание клавиш и установим там Ctrl+V.
Здесь кроется главная сложность: перехватить нажатие мы смогли, но 1С не передает содержимое буфера в обработчик команды автоматически. Нам нужно извлечь его самостоятельно.
Для операционных систем Windows (клиентское приложение) мы можем использовать COM-объект htmlfile. Это позволяет обратиться к системному буферу обмена через механизм Internet Explorer, который есть в системе. В более сложных сценариях можно даже реализовать свой COM объект на Python.
Рассмотрим пример кода обработчика команды:
&НаКлиенте
Процедура ВставитьИзБуфераСпециальная(Команда)
// Пытаемся получить текст из буфера обмена
ТекстБуфера = "";
Попытка
// Создаем легковесный COM-объект для доступа к буферу
HTMLОбертка = Новый COMОбъект("htmlfile");
// Получаем текст. Метод getData("Text") вернет содержимое буфера
ТекстБуфера = HTMLОбертка.parentWindow.clipboardData.getData("Text");
Исключение
Сообщить("Не удалось прочитать буфер обмена: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
Если ЗначениеЗаполнено(ТекстБуфера) Тогда
ОбработатьВставкуТекста(ТекстБуфера);
КонецЕсли;
КонецПроцедуры
Данные из Excel или другой таблицы приходят в буфер обмена в виде текста, где строки разделены символом переноса строки (Символы.ПС), а колонки — знаком табуляции (Символы.Таб).
Разберем алгоритм обработки такой строки:
&НаКлиенте
Процедура ОбработатьВставкуТекста(Знач ТекстВставки)
// Определяем текущую активную область, куда пользователь хочет вставить данные
ТекущаяОбласть = Элементы.ТабличныйДокумент.ТекущаяОбласть;
Если ТекущаяОбласть.ТипОбласти <> ТипОбластиЯчеекТабличногоДокумента.Прямоугольник Тогда
Возврат; // Вставка возможна только в ячейки
КонецЕсли;
Верх = ТекущаяОбласть.Верх;
Лево = ТекущаяОбласть.Лево;
// Разбиваем текст на строки
МассивСтрок = СтрРазделить(ТекстВставки, Символы.ПС, Ложь);
Для ИндексСтр = 0 По МассивСтрок.Количество() - 1 Цикл
ТекущаяСтрокаТекста = МассивСтрок[ИндексСтр];
// Разбиваем строку на колонки по табуляции
МассивКолонок = СтрРазделить(ТекущаяСтрокаТекста, Символы.Таб, Ложь);
Для ИндексКол = 0 По МассивКолонок.Количество() - 1 Цикл
ЗначениеЯчейки = МассивКолонок[ИндексКол];
// Вычисляем координаты целевой ячейки
ЦелеваяСтрока = Верх + ИндексСтр;
ЦелеваяКолонка = Лево + ИндексКол;
// Получаем область одной ячейки
ОбластьПриемник = Элементы.ТабличныйДокумент.Область(ЦелеваяСтрока, ЦелеваяКолонка, ЦелеваяСтрока, ЦелеваяКолонка);
// Вставляем ТОЛЬКО ЗНАЧЕНИЕ, не трогая форматирование
// Здесь можно добавить проверки: число ли это, входит ли в допустимый диапазон и т.д.
ОбластьПриемник.Текст = ЗначениеЯчейки;
// Или ОбластьПриемник.Значение = ..., если нужно типизированное значение
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Важное примечание: Данный метод через htmlfile работает только в тонком клиенте под Windows. Для веб-клиента потребуется иной подход.
Если мы хотим, чтобы решение работало не только в Windows или если политики безопасности блокируют COM-объекты, можно использовать "мостик" через поле HTML-документа.
Строка с видом Поле HTML документа. Делаем его невидимым (или минимального размера), но он должен присутствовать в DOM-дереве формы.navigator.clipboard.readText() (современный стандарт) или через создание скрытого textarea.Это более сложный путь, требующий знания JavaScript, но он наиболее надежен для веб-клиента.
Если перехватить нажатие клавиш не удается (например, из-за специфики RDP или ограничений прав), можно пойти другим путем: позволить 1С вставить данные "как есть", а затем мгновенно исправить результат.
Используем событие табличного документа ПриИзмененииСодержимогоОбласти.
Проблема: Когда это событие срабатывает, форматирование уже может быть испорчено (вставка с рамками из Excel). В 1С программно нет функции "Отменить" (Undo) для возврата форматирования.
Решение: Хранить эталон.
ПриИзмененииСодержимогоОбласти:
Пример логики:
&НаКлиенте
Процедура ТабличныйДокументПриИзмененииСодержимогоОбласти(Элемент, Область)
// Внимание: событие может зациклиться, если мы будем менять данные внутри него.
// Нужен флаг блокировки.
Если БлокировкаСобытия Тогда Возврат; КонецЕсли;
БлокировкаСобытия = Истина;
// Анализируем вставленные данные
// Если видим, что сбилось форматирование (например, появились рамки),
// применяем стиль "по умолчанию" для этой области.
// Пример упрощенный: просто сбрасываем рамку
Область.ГраницаСверху = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.НетЛинии);
// ... и так далее для других свойств
БлокировкаСобытия = Ложь;
КонецПроцедуры
Для реализации задачи "Вставить только значения" в табличный документ 1С:
Ctrl+V. Это заблокирует стандартную вставку.Символы.ПС и Символы.Таб) и программно заполните свойства Текст или Значение ячеек, не затрагивая их оформление.Ctrl+C (копирования) аналогично создайте команду с этим сочетанием и оставьте ее пустой или реализуйте свою логику копирования в буфер через тот же COM-объект (метод setData).Этот подход позволяет гибко управлять процессом, проверять данные перед вставкой (например, запрещать вставку текста в числовые поля) и сохранять красивый внешний вид ваших таблиц.