Как скопировать содержимое и оформление одной таблицы в другую в 1С 7.7 без использования временных файлов?

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

При разработке отчетов и печатных форм в среде 1С:Предприятие 7.7 программисты часто сталкиваются с необходимостью динамического манипулирования табличными документами. Типичный сценарий: в модуле документа или отчета формируется печатная форма (объект Таблица), которую затем требуется передать в специализированную обработку для интерактивного редактирования пользователем. Однако попытка простого копирования объекта «в лоб» приводит либо к копированию ссылки вместо создания независимой копии, либо к ошибкам исполнения.

В этой статье мы подробно проанализируем, почему возникает эта проблема, разберем ограничения платформы 1С 7.7 и рассмотрим несколько изящных способов копирования таблиц — как с помощью штатных механизмов, так и с привлечением внешних компонент.

---

Выясняем причину: почему простое присвоение не работает?

Для начала разберем типичные ошибки, которые совершают разработчики при попытке скопировать одну таблицу в другую.

Ошибка 1: Копирование ссылки вместо объекта

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


Таб1 = СоздатьОбъект("Таблица");
// ... заполняем Таб1 ...
Таб2 = Таб1;

В этом случае физического копирования данных в памяти не происходит. Переменная Таб2 становится лишь еще одной ссылкой на тот же самый объект в оперативной памяти, что и Таб1. Любые изменения, внесенные в Таб2, моментально отразятся на Таб1, так как они указывают на одну и ту же область памяти.

Ошибка 2: Попытка перезаписать элемент управления на форме

Часто разработчики пытаются передать таблицу в форму внешней обработки через параметры открытия:


// В вызывающем коде:
ОткрытьФорму("Обработка.РедактированиеТаблицы", ТабИсходная);

// В вызываемой обработке (процедура ПриОткрытии):
ТабПараметр = Форма.Параметр; // Здесь ссылка получена успешно
Таблица = ТабПараметр; // Вызывает ошибку!

Почему возникает ошибка? Дело в том, что переменная Таблица, размещенная на форме (особенно в режиме ввода данных), является элементом диалога (агрегатным объектом формы). Платформа 1С 7.7 не позволяет напрямую перезаписать этот элемент управления другой объектной ссылкой из кода. Нам необходимо именно скопировать внутреннее содержимое одного объекта в другой.

---

Решение 1. Использование внешней компоненты «Йоксель» (самый изящный способ)

Если в вашей конфигурации допускается использование сторонних библиотек (или уже установлена популярная сборка 1С++), то наилучшим решением будет использование внешней компоненты Йоксель (Yoksel / SpreadSheet.dll). Это мощное расширение для работы с табличными документами, которое позволяет клонировать объекты непосредственно в оперативной памяти.

Для этого мы задействуем промежуточный объект ТабличныйДокумент из Йокселя, который умеет импортировать и экспортировать стандартные таблицы 1С:


// Создаем объект Йокселя в памяти
ЙоксДок = СоздатьОбъект("ТабличныйДокумент");

// Загружаем в него исходную таблицу 1С (переданную через параметр)
ИсходнаяТаб = Форма.Параметр;
ЙоксДок.ЗагрузитьИзТаблицы(ИсходнаяТаб);

// Выгружаем данные в целевую таблицу, расположенную на форме обработки
// При этом полностью сохраняется структура, шрифты, цвета и объединения ячеек
ЙоксДок.ВыгрузитьВТаблицу(Таблица);

Этот способ работает мгновенно, не затрагивает жесткий диск и корректно переносит любые сложные печатные формы, включая те, которые открыты в режиме ввода данных (РВД).

---

Решение 2. Перенос данных через «Список Значений» (для режима ввода данных)

Если вам не требуется переносить сложное графическое оформление, формулы и границы ячеек, а необходимо скопировать только данные, введенные пользователем в интерактивную таблицу, мы можем использовать штатные методы Выгрузить() и Загрузить().

Эти методы работают со стандартным объектом СписокЗначений и доступны для таблиц, находящихся в режиме ввода данных. Проанализируем, как это реализовать:

  1. Выгрузка данных из исходной таблицы:

    При выгрузке система формирует список значений, где в качестве представления элемента сохраняется адрес ячейки (или ее уникальное имя), а в качестве значения — ее содержимое.

    
    СписокДанных = СоздатьОбъект("СписокЗначений");
    // Выгружаем заполненные ячейки из исходной таблицы
    ТабИсходная.Выгрузить(СписокДанных);
    
  2. Загрузка данных в целевую таблицу на форме:

    На стороне принимающей формы мы можем заполнить пустую таблицу-шаблон, имеющую аналогичную структуру именования ячеек:

    
    // Загружаем значения в таблицу на форме по адресам/именам ячеек
    ТаблицаНаФорме.Загрузить(СписокДанных);
    

Важное примечание: Этот способ оптимален, когда структура (строки и колонки) обеих таблиц полностью идентична, и нужно лишь синхронизировать пользовательский ввод.

---

Решение 3. Недокументированный трюк с использованием массива

В платформе 1С:Предприятие 7.7 существует интересная архитектурная особенность, связанная со статическим выделением памяти под тип данных Массив. При попытке поместить объект (в данном случае Таблица) внутрь элемента массива платформа в ряде релизов осуществляет физическое клонирование этого объекта в памяти, разрывая связь с исходной ссылкой.

Рассмотрим, как выглядит этот трюк на практике:


// Объявляем массив из одного элемента
Перем Контейнер[1];

// Присваиваем элемент массива — это инициирует копирование объекта в памяти
Контейнер[1] = ИсходнаяТаблица;

// Теперь получаем независимую копию объекта
ТабКопия = Контейнер[1];

Внимание: Данный метод является недокументированным. Его стабильность может зависеть от конкретного релиза технологической платформы 1С 7.7 (SQL или DBF-версии), поэтому перед внедрением в рабочую базу обязательно проведите тестирование на вашем релизе платформы.

---

Решение 4. Оптимизированный штатный метод с временным файлом

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

Разберем по шагам правильный алгоритм работы с временным файлом:

  1. Получим путь к системному каталогу временных файлов пользователя, чтобы избежать проблем с правами записи в операционной системе.
  2. Сформируем уникальное имя файла, используя генерацию случайных чисел или текущее время с точностью до миллисекунд.
  3. Запишем исходную таблицу, откроем ее в целевом объекте и обязательно удалим временный файл с диска сразу после завершения операции.

Реализуем этот алгоритм на встроенном языке:


// Очистим целевую таблицу на форме
Таблица.Очистить();

// Определяем путь к уникальному временному файлу
ИмяВременногоФайла = КаталогВременныхФайлов() + "v7_tab_copy_" + Врап_ПолучитьУникальныйИД() + ".mxl";

Попытка
    // Записываем исходную таблицу во временный файл MXL
    ТабИсходная.Записать(ИмяВременногоФайла);
    
    // Загружаем данные в целевую таблицу
    Таблица.Открыть(ИмяВременногоФайла);
    
    // Удаляем файл с диска, чтобы не засорять систему
    ФС.УдалитьФайл(ИмяВременногоФайла);
Исключение
    // Обработка возможных ошибок доступа к файловой системе
    Сообщить("Ошибка при копировании таблицы: " + ОписаниеОшибки(), "!");
    Если ФС.СуществуетФайл(ИмяВременногоФайла) = 1 Тогда
        ФС.УдалитьФайл(ИмяВременногоФайла);
    КонецЕсли;
КонецПопытки;

Вспомогательная функция для генерации уникального постфикса имени файла:


Функция Врап_ПолучитьУникальныйИД()
    // Простейшая генерация на основе текущего времени
    ВремяСтр = ТекущееВремя(); // Формат "ЧЧ:ММ:СС"
    Возврат СтрЗаменить(ВремяСтр, ":", "");
КонецФункции

---

Важные ограничения режима ввода данных (РВД) в 1С 7.7

При реализации сложных динамических таблиц в режиме ввода данных обязательно учитывайте производительность встроенного движка отображения табличных документов 1С 7.7:

Мы подробно разобрали все возможные способы копирования табличных документов в 1С 7.7. Выбирайте наиболее подходящий вариант в зависимости от архитектурных требований вашего проекта и наличия внешних компонент в системе.

← На главную