При разработке печатных форм в среде «1С:Предприятие» программисты часто сталкиваются с необходимостью выгрузки данных во внешние редакторы, такие как Microsoft Word. Заполнение табличной части макета Word — стандартная задача, однако в процессе её реализации могут возникать неожиданные проблемы с визуальным форматированием. Одна из наиболее частых неприятностей — текст в ячейках таблицы начинает отображаться вертикально, затрудняя чтение документа.
В этой статье мы подробно разберем причины этой проблемы, найдем простое и элегантное решение с использованием COM-объектов, а также рассмотрим современные альтернативные подходы, которые позволят значительно ускорить генерацию документов Word и сделать код более стабильным и кроссплатформенным.
Рассмотрим ситуацию, с которой столкнулся автор темы. При заполнении таблицы Word данными из табличной части документа 1С текст в ячейках разворачивается вертикально. Посмотрим на исходный код, который использовался для формирования таблицы:
//Заполняем ТЧ.
НомерСтроки = 4;
НомерКолонкиТовар = 2;
НомерМассаНетто = 6;
НумерацияСтроки = 1;
НомерКолонкиНомерСтр = 1;
ТЧПартия = 5;
ТЧЖирнность = 9;
ТЧВлажность = 10;
Для Каждого ТекСтр ИЗ ТЧ Цикл
ВордТаблица = Документ.Tables(1);
ВордТаблица.Rows.Add();
ЗаполнениеНумерацияСтрок = ВордТаблица.Cell(НомерСтроки,НомерКолонкиНомерСтр).Range;
ЗаполнениеНумерацияСтрок.Text = НумерацияСтроки;
ЗаполнениеНоменклатуры = ВордТаблица.Cell(НомерСтроки,НомерКолонкиТовар).Range;
ЗаполнениеНоменклатуры.Text = ТекСтр.Номенклатура.Наименование;
ЗаполнениеКоличество = ВордТаблица.Cell(НомерСтроки,НомерМассаНетто).Range;
ЗаполнениеКоличество.Text = ТекСтр.Количество;
ЗаполнениеКоличество = ВордТаблица.Cell(НомерСтроки,ТЧПартия).Range;
ЗаполнениеКоличество.Text = Основание.Номер;
ЗаполнениеКоличество = ВордТаблица.Cell(НомерСтроки,ТЧЖирнность).Range;
ЗаполнениеКоличество.Text = "8,5";
ЗаполнениеКоличество = ВордТаблица.Cell(НомерСтроки,ТЧВлажность).Range;
ЗаполнениеКоличество.Text = "26,5";
НомерСтроки = НомерСтроки+1;
НумерацияСтроки = НумерацияСтроки+1;
КонецЦикла;
Проанализируем этот алгоритм. В цикле Для Каждого программа обращается к первой таблице документа Word через Документ.Tables(1), динамически добавляет новую строку методом Rows.Add(), а затем последовательно заполняет ячейки (Cell), извлекая их текстовую область Range. Однако при добавлении строк или из-за специфических настроек шаблона Word текст в создаваемых ячейках принимает вертикальное положение.
Для управления направлением текста в ячейках MS Word используется специальное свойство Orientation, принадлежащее объекту Range (или непосредственно ячейке). Это свойство принимает значения из системного перечисления Microsoft Word WdTextOrientation. Выясним, какие значения может принимать это свойство и как они влияют на отображение данных:
Таким образом, для исправления вертикального текста достаточно явно установить свойство Orientation в значение 0 для заполняемого диапазона (Range) ячейки. Давайте посмотрим, как изменится код заполнения:
//Заполняем ТЧ с явным указанием ориентации текста
НомерСтроки = 4;
НомерКолонкиТовар = 2;
НомерМассаНетто = 6;
НумерацияСтроки = 1;
НомерКолонкиНомерСтр = 1;
ТЧПартия = 5;
ТЧЖирнность = 9;
ТЧВлажность = 10;
Для Каждого ТекСтр ИЗ ТЧ Цикл
ВордТаблица = Документ.Tables(1);
ВордТаблица.Rows.Add();
ЗаполнениеНумерацияСтрок = ВордТаблица.Cell(НомерСтроки,НомерКолонкиНомерСтр).Range;
ЗаполнениеНумерацияСтрок.Text = НумерацияСтроки;
ЗаполнениеНумерацияСтрок.Orientation = 0; // Устанавливаем горизонтальную ориентацию
ЗаполнениеНоменклатуры = ВордТаблица.Cell(НомерСтроки,НомерКолонкиТовар).Range;
ЗаполнениеНоменклатуры.Text = ТекСтр.Номенклатура.Наименование;
ЗаполнениеНоменклатуры.Orientation = 0;
ЗаполнениеКоличество = ВордТаблица.Cell(НомерСтроки,НомерМассаНетто).Range;
ЗаполнениеКоличество.Text = ТекСтр.Количество;
ЗаполнениеКоличество.Orientation = 0;
ЗаполнениеКоличество = ВордТаблица.Cell(НомерСтроки,ТЧПартия).Range;
ЗаполнениеКоличество.Text = Основание.Номер;
ЗаполнениеКоличество.Orientation = 0;
ЗаполнениеКоличество = ВордТаблица.Cell(НомерСтроки,ТЧЖирнность).Range;
ЗаполнениеКоличество.Text = "8,5";
ЗаполнениеКоличество.Orientation = 0;
ЗаполнениеКоличество = ВордТаблица.Cell(НомерСтроки,ТЧВлажность).Range;
ЗаполнениеКоличество.Text = "26,5";
ЗаполнениеКоличество.Orientation = 0;
НомерСтроки = НомерСтроки+1;
НумерацияСтроки = НумерацияСтроки+1;
КонецЦикла;
Этот шаг мгновенно возвращает текст в стандартное горизонтальное положение и решает проблему визуализации.
Хотя предложенное решение полностью исправляет проблему, сам подход с использованием COM-соединения (Новый COMОбъект("Word.Application")) имеет ряд существенных недостатков, о которых важно помнить разработчику 1С. Рассмотрим их подробнее:
Cell() или свойству Text в цикле представляет собой отдельный межпроцессный вызов (out-of-process COM-вызов). Если в табличной части документа будет более 100 строк по 6 колонок в каждой, программа выполнит сотни медленных обращений к Word. Это приводит к заметным задержкам (формирование документа может занимать минуты) и зависанию интерфейса 1С у пользователя.WINWORD.EXE на сервере 1С крайне не рекомендуется. В случае возникновения ошибок процессы Word могут зависать в оперативной памяти сервера, блокируя ресурсы и приводя к критическим сбоям серверного кластера.Для минимизации этих проблем и повышения производительности рассмотрим альтернативные подходы к заполнению документов.
Если отказаться от технологии COM невозможно, мы можем кардинально ускорить работу алгоритма. Вместо построчного заполнения ячеек в цикле мы сформируем единый текстовый блок со специальными разделителями и преобразуем его в готовую таблицу Word за одно обращение.
Разберем этот алгоритм по шагам:
Символы.Таб), а строки — символом перевода строки (Символы.ПС).ConvertToTable() для мгновенного превращения текста в полноценную таблицу с нужным количеством колонок.Посмотрим на практический пример реализации этого метода:
// Пример быстрого формирования таблицы методом ConvertToTable
ТекстДляВставки = "";
Для Каждого ТекСтр Из ТЧ Цикл
ТекстДляВставки = ТекстДляВставки
+ ТекСтр.НомерСтроки + Символы.Таб
+ ТекСтр.Номенклатура.Наименование + Символы.Таб
+ ТекСтр.Количество + Символы.Таб
+ Основание.Номер + Символы.Таб
+ "8,5" + Символы.Таб
+ "26,5" + Символы.ПС;
КонецЦикла;
// Вставляем текст в определенное место документа (например, в закладку)
Закладка = Документ.Bookmarks("ТабличнаяЧасть").Range;
Закладка.Text = ТекстДляВставки;
// Преобразуем текст в таблицу (разделитель - знак табуляции)
НоваяТаблица = Закладка.ConvertToTable(1, , 6); // 1 - разделитель Tab, 6 - количество колонок
НоваяТаблица.Range.Orientation = 0; // Сразу задаем горизонтальную ориентацию для всей таблицы
Этот метод работает в десятки раз быстрее классического построчного заполнения, так как количество COM-вызовов сокращается до минимума.
Современным стандартом разработки в среде 1С является использование встроенных механизмов БСП для работы с файлами формата DOCX. Этот подход полностью лишен недостатков COM-технологии.
Файл DOCX по своей сути является ZIP-архивом, содержащим XML-файлы разметки документа. БСП позволяет манипулировать этим архивом напрямую на сервере (включая Linux) без запуска Microsoft Word. Разберем основные преимущества этого метода:
Для реализации этого подхода в макете Word создаются специальные области и параметры в формате БСП (например, {v8 ИмяПараметра} для одиночных значений и области {v8 Область.СтрокаТаблицы} для строк табличной части). Программа заменяет эти маркеры реальными данными из 1С на лету без открытия MS Word на сервере.
Если задача состоит в том, чтобы выдать пользователю готовый файл формата Word, самым простым и надежным обходным путем является использование встроенного табличного документа 1С:
.mxl) в конфигураторе 1С. Сверстайте печатную форму так, как должен выглядеть итоговый документ.ТабличныйДокумент.ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт.Посмотрим на пример кода, реализующего данный подход:
ТабДок = Новый ТабличныйДокумент;
// Код заполнения Табличного Документа макетом 1С
// ...
ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;
ПутьКФайлу = ПолучитьИмяВременногоФайла("docx");
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.DOCX);
Этот способ является наиболее стабильным, простым в отладке и полностью поддерживается платформой «1С:Предприятие» на любых операционных системах.