При формировании печатных форм часто возникает задача вывода не просто одиночного документа, а целого реестра или набора однотипных блоков. Например, когда для каждого сотрудника нужно вывести его персональные данные, а следом — таблицу с его начислениями или списком выполненных работ. Стандартный метод «Поиска и замены», который часто используют новички, здесь не подходит, так как он рассчитан на фиксированную структуру шаблона.
В этой статье мы подробно разберем, как реализовать динамическое формирование документа Microsoft Word, используя механизмы COM-соединения, копирование областей и программное управление таблицами.
Проанализируем наиболее гибкий подход. Его суть заключается в том, что в вашем макете Word создается один эталонный блок (например, ФИО и пустая таблица под ним). Программа находит этот блок, копирует его в память, а затем в цикле вставляет в конец документа необходимое количество раз, заменяя параметры на реальные данные.
Рассмотрим пошагово, как это реализовать в коде 1С:
// 1. Инициализация приложения и получение макета
МакетОбъект = ПолучитьМакет("МойМакетWord");
MSWord = МакетОбъект.Получить();
Документ = MSWord.Application.Documents(1);
MSWord.Application.Visible = Ложь; // Отключаем видимость для ускорения
// 2. Определяем область-образец (например, первый абзац и первая таблица)
// Можно использовать закладку, чтобы точно выделить нужный кусок
RangeОбразец = Документ.Content;
RangeОбразец.Copy(); // Копируем эталонный блок в буфер обмена
// 3. Основной цикл по данным (например, по сотрудникам)
Для Каждого СтрокаСотрудник Из СписокСотрудников Цикл
// Переходим в конец документа для вставки нового блока
КонецДокумента = Документ.Range();
КонецДокумента.Collapse(0); // 0 соответствует константе wdCollapseEnd
КонецДокумента.Paste();
// Теперь работаем с только что вставленным фрагментом
// Выполняем замену параметров (ФИО, Должность и т.д.)
Замена = КонецДокумента.Find;
Замена.Execute("[ФИО]", , , , , , , , , СтрокаСотрудник.ФИО, 2);
// Работа с таблицей внутри вставленного блока
// Обычно это будет последняя таблица в документе
ТекущаяТаблица = Документ.Tables(Документ.Tables.Count);
// Заполняем таблицу данными по конкретному сотруднику
Для Каждого СтрокаДанных Из СтрокаСотрудник.ТаблицаДанных Цикл
НоваяСтрока = ТекущаяТаблица.Rows.Add();
НоваяСтрока.Cells(1).Range.Text = СтрокаДанных.Номер;
НоваяСтрока.Cells(2).Range.Text = СтрокаДанных.Описание;
КонецЦикла;
// Удаляем пустую первую строку, если она была создана в макете как заголовок
// Или просто начинаем заполнение со второй строки
КонецЦикла;
// 4. Удаляем самый первый (эталонный) блок, если он остался в начале
// Либо очищаем его в самом начале работы.
Выясним причину, по которой обычная замена текста Execute не всегда удобна для таблиц. В Word таблица — это сложный объект со своей иерархией. Если количество строк заранее неизвестно, нам нужно программно добавлять их. Рассмотрим, как управлять ячейками и строками напрямую.
Для обращения к конкретной ячейке используется конструкция Таблица.Cell(НомерСтроки, НомерКолонки). Важно помнить, что нумерация в Word начинается с 1, а не с 0.
Пример программного создания и заполнения таблицы:
// Предположим, мы нашли нужную таблицу по индексу или через закладку
Попытка
Таблица = Документ.Tables(1);
Исключение
Сообщить("Таблица не найдена в макете!");
Возврат;
КонецПопытки;
// Обойдем выборку данных
НомерСтрокиВорд = 2; // Допустим, первая строка - шапка
Для Каждого Данные Из Выборка Цикл
Если НомерСтрокиВорд > 2 Тогда
Таблица.Rows.Add(); // Добавляем новую строку, если данных больше, чем одна
КонецЕсли;
// Заполняем ячейки
Таблица.Cell(НомерСтрокиВорд, 1).Range.Text = Данные.Артикул;
Таблица.Cell(НомерСтрокиВорд, 2).Range.Text = Данные.Номенклатура;
Таблица.Cell(НомерСтрокиВорд, 3).Range.Text = Данные.Количество;
НомерСтрокиВорд = НомерСтрокиВорд + 1;
КонецЦикла;
Разберем ситуацию, когда данных много и они разбросаны по документу. Использование простого поиска текста (например, <Организация>) может быть ненадежным, если это сочетание символов случайно встретится в основном тексте. Профессиональнее использовать «Закладки».
ПодписьДиректора.Посмотрим на пример кода:
// Запись значения в место закладки
Если Документ.Bookmarks.Exists("ПодписьДиректора") Тогда
Закладка = Документ.Bookmarks("ПодписьДиректора");
Закладка.Range.Text = "Иванов И.И.";
КонецЕсли;
Важный нюанс: при записи текста в закладку через свойство Range.Text сама закладка удаляется (заменяется текстом). Если вам нужно сохранить закладку для повторного обращения, потребуется более сложная манипуляция с сохранением диапазона Range.
Работа с COM-объектами MS Word через 1С — процесс довольно медленный. Проанализируем несколько советов, которые помогут ускорить формирование отчета и избежать зависания системы:
MSWord.Application.ScreenUpdating = Ложь;. Это предотвратит перерисовку окна Word при каждом добавлении строки в таблицу.Visible = Ложь до самого конца формирования. Только когда документ полностью готов, можно сделать его видимым для пользователя.WINWORD.EXE может остаться в памяти сервера или ПК. Со временем это приведет к нехватке ресурсов.Всегда используйте конструкцию Попытка...Исключение для корректного закрытия приложения:
Попытка
// Основной код заполнения...
MSWord.Application.Visible = Истина;
Исключение
Сообщить("Ошибка при печати: " + ОписаниеОшибки());
// Если произошла ошибка, принудительно закрываем Word без сохранения
MSWord.Application.Quit(0); // 0 = wdDoNotSaveChanges
КонецПопытки;
Мы рассмотрели три основных способа решения задачи автора. Для вывода списка сотрудников с персональными таблицами лучше всего подходит комбинированный метод: копирование блока-образца в цикле и последующее динамическое добавление строк в таблицу этого блока. Это позволяет сохранить сложное форматирование шаблона и при этом выводить неограниченный объем данных.
Используя объектную модель Tables, Rows и Cells, вы получаете полный контроль над структурой документа, что недоступно при использовании только функции «Найти и заменить».