При формировании печатных форм в формате Microsoft Word программисты 1С часто сталкиваются с ситуацией, когда стандартный механизм поиска и замены текста (через объект Content.Find) успешно обрабатывает основной массив текста, но полностью игнорирует данные, находящиеся внутри специальных объектов — «Надписей» (Text Boxes). Это происходит потому, что в объектной модели Word «Надписи» относятся к коллекции Shapes, которая существует отдельно от основного текстового слоя (Content).
В данной статье мы подробно разберем, как программно достучаться до содержимого этих элементов, проанализируем способы сохранения форматирования и рассмотрим альтернативные подходы к созданию сложных шаблонов.
Разберем самый распространенный способ решения задачи через COM-соединение. Если в вашем шаблоне Word уже созданы надписи, нам необходимо перебрать все фигуры в документе, найти среди них те, которые могут содержать текст, и произвести замену маркеров (например, [НомерДоговора]) на реальные данные из информационной базы.
Рассмотрим пример кода, который автоматизирует этот процесс:
// Инициализация приложения Word
мWord = Новый COMОбъект("Word.Application");
мWord.Visible = Ложь; // Скрываем окно для ускорения работы
// Открытие шаблона
мДок = мWord.Documents.Add(ПутьКШаблону);
// Получаем количество фигур в документе
КоличФигур = мДок.Shapes.Count;
Для й = 1 По КоличФигур Цикл
мДокФигура = мДок.Shapes.Item(й);
// Проверяем, есть ли у фигуры текстовая рамка
Попытка
Если мДокФигура.TextFrame.HasText <> 0 Тогда
// Получаем доступ к диапазону текста внутри надписи
ТекстНадписи = мДокФигура.TextFrame.TextRange.Text;
// Выполняем замену параметров
// Обратите внимание: прямая замена через .Text может сбросить форматирование
мДокФигура.TextFrame.TextRange.Text = СтрЗаменить(ТекстНадписи, "[НомерДКП]", НомерДок);
мДокФигура.TextFrame.TextRange.Text = СтрЗаменить(мДокФигура.TextFrame.TextRange.Text, "[Дата]", Формат(ДатаДок, "ДЛФ=DD"));
КонецЕсли;
Исключение
// Фигура может не поддерживать TextFrame (например, линия или простая картинка)
Продолжить;
КонецПопытки;
КонецЦикла;
мWord.Visible = Истина; // Показываем результат пользователю
Проанализируем этот код. Мы используем свойство HasText, чтобы убедиться, что фигура является контейнером для текста. Основной недостаток прямого присваивания TextRange.Text = "Новый текст" заключается в том, что если внутри надписи часть слов была выделена жирным шрифтом или имела другой цвет, это оформление может быть утеряно. Чтобы этого избежать, рекомендуется использовать метод Find.Execute непосредственно к объекту TextRange надписи.
Для того чтобы сохранить стили оформления внутри надписи, мы применим метод Execute к диапазону текста фигуры. Это позволит заменить только вхождение строкового маркера, не затрагивая параметры шрифта остального содержимого.
Рассмотрим улучшенный алгоритм:
Для й = 1 По мДок.Shapes.Count Цикл
мДокФигура = мДок.Shapes.Item(й);
Попытка
RangeНадписи = мДокФигура.TextFrame.TextRange;
// Настройка параметров поиска внутри конкретной надписи
RangeНадписи.Find.Execute("[НомерДКП]", , , , , , , , , НомерДок, 2); // 2 = wdReplaceAll
RangeНадписи.Find.Execute("[Дата]", , , , , , , , , Формат(ДатаДок, "ДЛФ=DD"), 2);
Исключение
// Пропускаем фигуры без текста
КонецПопытки;
КонецЦикла;
В данном примере использование метода Execute гарантирует, что структура документа останется неизменной, а замена произойдет максимально корректно.
Часто дизайнеры шаблонов группируют надписи с логотипами или другими элементами оформления. В этом случае цикл по мДок.Shapes не увидит вложенные надписи, так как группа для Word — это один объект типа msoGroup.
Выясним, как обработать такие ситуации. Нам потребуется проверить свойство Type объекта Shape. Если тип соответствует значению 6 (группа), необходимо запустить вложенный цикл по коллекции GroupItems.
Процедура ОбработатьФигуры(КоллекцияФигур)
Для Каждого Фигура Из КоллекцияФигур Цикл
Если Фигура.Type = 6 Тогда // msoGroup
ОбработатьФигуры(Фигура.GroupItems);
Иначе
Попытка
Если Фигура.TextFrame.HasText <> 0 Тогда
Фигура.TextFrame.TextRange.Find.Execute("[Параметр]", , , , , , , , , "Значение", 2);
КонецЕсли;
Исключение
КонецПопытки;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот рекурсивный метод позволяет гарантированно найти все текстовые блоки, независимо от глубины их вложенности в группы.
Если структура вашего документа стабильна, вместо перебора всех фигур можно использовать механизм «Закладок». Выделите текст внутри надписи в Word, перейдите в меню «Вставка» -> «Закладка» и присвойте ей уникальное имя (например, ИмяКлиента).
Преимущество этого метода в том, что нам не нужно знать, где находится текст (в основном теле, в надписи или в колонтитуле). Обращение происходит напрямую:
Если мДок.Bookmarks.Exists("ИмяКлиента") Тогда
мДок.Bookmarks.Item("ИмяКлиента").Range.Text = КонтрагентНазвание;
КонецЕсли;
Важный нюанс: при записи текста в Range.Text закладки, сама закладка в Word удаляется (заменяется текстом). Если вам нужно повторное заполнение, придется программно пересоздавать закладку вокруг вставленного текста.
Посмотрим на ситуацию, описанную в сообщении №16 форума: при заполнении табличной части данными, текст в Word смещается вниз, и «Надписи» начинают перекрывать текст или уезжать за границы страницы. Это происходит из-за неправильной привязки (Anchor) объекта Shape.
Чтобы избежать этой проблемы, проанализируем настройки привязки в Word:
Для высоконагруженных систем или серверов, где не установлен Microsoft Office, использование COMObject невозможно. В этом случае документ .docx рассматривается как ZIP-архив, содержащий XML-файлы. Текст надписей обычно хранится внутри word/document.xml в тегах <w:txbxContent>.
Хотя этот метод значительно сложнее в реализации (требует парсинга XML), он работает в десятки раз быстрее и не зависит от внешних приложений. Однако для простых задач автоматизации в 1С «Обычные формы» COM-соединение остается наиболее доступным и гибким инструментом.
Подводя итог, можно сказать, что работа с надписями в Word из 1С требует более детального подхода, чем работа с обычным текстом. Использование коллекции Shapes, проверка TextFrame и правильная обработка групп объектов позволяют создавать профессионально оформленные документы любой сложности.