При работе с табличными частями документов в 1С пользователи часто сталкиваются с необходимостью быстрого переноса данных между ячейками. В типовых конфигурациях на обычных формах, таких как Управление торговлей редакции 10.3, стандартный механизм копирования ячеек через буфер обмена не всегда очевиден или доступен из коробки. Разработчику приходится самостоятельно реализовывать этот функционал с помощью кнопок "Копировать" и "Вставить".
В этой статье мы подробно разберем, как правильно организовать процесс копирования значения активной ячейки и его последующей вставки в другую ячейку этой же табличной части. Мы детально проанализируем технические нюансы работы с обычными формами, рассмотрим особенности получения данных активной колонки, научимся обходить подводные камни с обработчиками событий в УТ 10.3, а также изучим способы работы с системным буфером обмена Windows.
---
Часто начинающие разработчики пытаются решить задачу получения значения активной ячейки простым обращением к свойству ТекущиеДанные табличного поля. Однако важно понимать ключевое различие:
ТекущиеДанные возвращает строку табличной части целиком (объект строки), содержащую все реквизиты.Для того чтобы получить значение конкретной выделенной ячейки, нам необходимо динамически определить не только активную строку, но и активную колонку табличного поля. Разберем по шагам, как это реализовать.
---
Для реализации этой логики мы будем использовать переменную модуля формы. Это позволит нам временно хранить скопированное значение на клиенте в рамках текущего сеанса работы с формой, не задействуя системный буфер обмена ОС и не создавая лишних реквизитов в самом документе.
Рассмотрим пример кода. В самом верху модуля формы (в разделе объявлений переменных) объявим переменную для хранения нашего скопированного значения:
Перем БуферЗначения; // Локальный буфер в рамках модуля формы
Теперь создадим процедуру-обработчик для кнопки "Копировать". Нам потребуется проверить корректность выделения строки и колонки, а затем программно определить имя реквизита, связанного с активной колонкой. Обратите внимание, что имя колонки на форме (свойство Имя) и имя реквизита в метаданных (свойство Данные) могут не совпадать. Поэтому мы будем использовать именно свойство Данные.
Проанализируем программный код:
Процедура КнопкаКопироватьНажатие(Кнопка)
// Получаем элемент управления табличного поля формы
ТабПоле = ЭлементыФормы.Товары; // Вместо "Товары" укажите имя вашего табличного поля
// Шаг 1. Проверяем, что в таблице выделена строка
Если ТабПоле.ТекущиеДанные = Неопределено Тогда
Предупреждение("Не выбрана строка для копирования значения!");
Возврат;
КонецЕсли;
// Шаг 2. Проверяем, что активна какая-то конкретная колонка
Если ТабПоле.ТекущаяКолонка = Неопределено Тогда
Предупреждение("Не выбрана ячейка для копирования!");
Возврат;
КонецЕсли;
// Шаг 3. Получаем имя реквизита, к которому привязана колонка
ИмяРеквизита = ТабПоле.ТекущаяКолонка.Данные;
// Проверяем, что ячейка действительно связана с данными объекта
Если ЗначениеЗаполнено(ИмяРеквизита) Тогда
// Записываем значение ячейки в переменную формы
БуферЗначения = ТабПоле.ТекущиеДанные[ИмяРеквизита];
Сообщить("Значение """ + СокрЛП(Строка(БуферЗначения)) + """ скопировано во внутренний буфер.");
Иначе
Предупреждение("Выделенная ячейка не связана с данными табличной части!");
КонецЕсли;
КонецПроцедуры
---
После того как значение успешно сохранено в переменной БуферЗначения, пользователь выбирает другую ячейку (строку или колонку) и нажимает кнопку "Вставить". Нам необходимо прочитать сохраненное значение, проверить доступность целевой колонки для изменения и записать данные.
Рассмотрим структуру процедуры вставки:
Процедура КнопкаВставитьНажатие(Кнопка)
ТабПоле = ЭлементыФормы.Товары;
// Проверяем, что выбрана строка-получатель
Если ТабПоле.ТекущиеДанные = Неопределено Тогда
Предупреждение("Не выбрана строка для вставки значения!");
Возврат;
КонецЕсли;
// Проверяем, что буфер не пуст
Если БуферЗначения = Неопределено Тогда
Предупреждение("Буфер обмена пуст! Сначала скопируйте значение.");
Return;
КонецЕсли;
// Проверяем, выбрана ли активная колонка-получатель
Если ТабПоле.ТекущаяКолонка = Неопределено Тогда
Предупреждение("Не выбрана целевая ячейка для вставки!");
Возврат;
КонецЕсли;
ИмяРеквизита = ТабПоле.ТекущаяКолонка.Данные;
Если Не ЗначениеЗаполнено(ИмяРеквизита) Тогда
Предупреждение("Целевая ячейка не связана с данными!");
Возврат;
КонецЕсли;
// Проверяем, доступна ли колонка на форме для изменения
Если ТабПоле.ТекущаяКолонка.ТолькоПросмотр ИЛИ ТабПоле.ТолькоПросмотр Тогда
Предупреждение("Выделенная ячейка недоступна для редактирования!");
Возврат;
КонецЕсли;
// Записываем значение в строку табличной части
ТабПоле.ТекущиеДанные[ИмяРеквизита] = БуферЗначения;
КонецПроцедуры
---
Если вы ограничитесь только кодом, описанным выше, то столкнетесь с серьезной проблемой. В конфигурации "Управление торговлей 10.3" изменение ключевых реквизитов (таких как "Номенклатура", "Склад", "ЕдиницаИзмерения", "Цена") запускает целый комплекс фоновых алгоритмов:
Когда мы изменяем значение через прямое присвоение в коде ТабПоле.ТекущиеДанные[ИмяРеквизита] = БуферЗначения;, стандартное интерактивное событие формы ПриИзменении для данной ячейки не вызывается автоматически. В результате данные в табличной части изменятся визуально, но пересчет сумм или перевыбор связанных параметров не произойдет, что приведет к логическим ошибкам в документе.
Решение: Нам необходимо принудительно запустить обработчик события изменения конкретной колонки после выполнения операции вставки. Модифицируем код вставки с учетом этой особенности:
// Записываем значение в строку табличной части
ТабПоле.ТекущиеДанные[ИмяРеквизита] = БуферЗначения;
// Принудительный вызов процедур пересчета УТ 10.3
Если ИмяРеквизита = "Склад" Тогда
// Имя процедуры-обработчика берем из свойств колонки "Склад" на форме
ТоварыСкладПриИзменении(ЭлементыФормы.Товары.Колонки.Склад);
ИначеЕсли ИмяРеквизита = "Номенклатура" Тогда
ТоварыНоменклатураПриИзменении(ЭлементыФормы.Товары.Колонки.Номенклатура);
ИначеЕсли ИмяРеквизита = "Цена" Тогда
ТоварыЦенаПриИзменении(ЭлементыФормы.Товары.Колонки.Цена);
КонецЕсли;
Перед внедрением обязательно откройте свойства нужной колонки в конфигураторе, перейдите на вкладку "События" и посмотрите точное название процедуры в поле "При изменении" (например, ТоварыСкладПриИзменении).
---
Иногда требуется скопировать данные не просто в рамках одной формы, но и передать их во внешнее приложение (например, вставить наименование товара или артикул в Excel или Блокнот). В обычных формах на платформе 1С:Предприятие 8.3 можно задействовать COM-объект htmlfile, который предоставляет доступ к буферу обмена операционной системы Windows.
Посмотрим на пример реализации копирования текстового представления ячейки в системный буфер Windows:
Попытка
ОбъектБуфера = Новый COMОбъект("htmlfile");
// Преобразуем значение ячейки в строковый формат и помещаем в буфер Windows
ОбъектБуфера.ParentWindow.ClipboardData.SetData("Text", Строка(БуферЗначения));
Исключение
Сообщить("Не удалось записать данные в системный буфер обмена Windows. Возможно, ограничены права доступа.");
КонецПопытки;
Для обратной операции — получения текстовых данных из системного буфера обмена Windows — используйте следующий код:
Попытка
ОбъектБуфера = Новый COMОбъект("htmlfile");
ТекстИзБуфера = ОбъектБуфера.ParentWindow.ClipboardData.GetData("Text");
Если ЗначениеЗаполнено(ТекстИзБуфера) Тогда
// Здесь можно реализовать логику поиска объекта по наименованию или коду
// Например: СкладСсылка = Справочники.Склады.НайтиПоНаименованию(ТекстИзБуфера);
КонецЕсли;
Исключение
Сообщить("Не удалось прочитать данные из системного буфера обмена Windows.");
КонецПопытки;
---
Если ваша база данных УТ 10.3 работает на современной версии технологической платформы 1С:Предприятие 8.3.24 или выше, вы можете использовать новый штатный механизм работы с буфером обмена. Он работает асинхронно, кроссплатформенно (поддерживает Linux и macOS) и не требует создания COM-объектов.
Рассмотрим пример современного синтаксиса для записи данных в системный буфер:
// Создаем элемент буфера обмена с текстовым форматом данных
ЭлементБуфера = Новый ЭлементБуфераОбмена(СтандартныйФорматДанныхБуфераОбмена.Текст, Строка(БуферЗначения));
// Асинхронно помещаем данные в буфер обмена операционной системы
СредстваБуфераОбмена.ПоместитьДанныеАсинх(ЭлементБуфера);
Такой подход обеспечивает максимальную стабильность решения и гарантирует корректную работу кода в терминальных сессиях и веб-клиенте.