Работа с Ворд через СОМ-Объект

Публикация № 1382473

Разработка - Практика программирования

Word Ворд COM

Статья представляет собой еще один велосипед на тему формирования документов на основе шаблонов через СОМ-Объект. Как и все другие велосипеды, этот написан потому, что другие велосипеды - плохие. В действительности, если погуглить, мы получим огромное количество ссылок на советы в стиле "сделай так и будет тебе счастье". Но почему "так", зачем "так", какие есть альтернативы - авторы советов не раскрывают. Хуже того, половина найденных таким способом рецептов окажутся откровенно вредными. Судя по тому, как вредные рецепты копируются из совета в совет, большинство разработчиков, из тех, что переписываются на форумах, просто воспроизводят то, что когда-то нагуглили сами. Ну да, работает - не трогай :-)

Цель статьи - собрать в одном месте необходимый и достаточный набор рецептов по заполнению документов Ворд на основании шаблонов с помощью СОМ-Объекта

Оглавление:

Зачем и почему нужны файлы Ворд?

Что значит сформировать файл Ворд?

Способы формирования файла Ворд

Объектная модель Ворд

Запуск Ворд, открытие файла

Закрытие файла, завершение работы с СОМ-Объектом

Заполнение шаблона с помощью именованных полей (свойств документа)

Заполнение шаблона через поиск и замену

Особенности работы с колонтитулами

Заполнение шаблона с помощью закладок

Удаление фрагментов текста

Вставка картинок

Работа с таблицами

 

Зачем и почему нужны файлы Ворд?

Немного философии. В действительности, зачем нужно формировать из информационной базы текстовые файлы, и почему обязательно в формате Ворд?

Потому, что пользователю нужны файлы. Не распечатанные из информационной системы листочки, а именно текстовые файлы, которые можно отправить клиенту по эл. почте или мессенджеру, которые можно отредактировать, подправить, получить по эл. почте и переслать дальше с комментариями, сохранить в качестве образца и распечатать. Конечно, пользователь пользователю рознь. В некоторых корпоративных структурах тратятся огромные силы и средства на то, чтобы убрать у пользователя возможность что-то сделать с файлом, а еще лучше убрать сами файлы. Пользователь из лучших побуждений подправит документ, внесет в него ошибку, которую потом разгребать будут десятки людей. Но мы на них равняться не будем. Всегда будут процессы не дошедшие до стадии "делать по регламенту или никак", и всегда будут пользователи которые хотят работать с файлами.

Потому, что пользователь для работы с текстом использует текстовый процессор. Строго говоря, кроме Ворда всегда существовали альтернативные программы, не уступающие по функционалу. Сейчас 2021 год и пользователи давно привыкли к таким вещам как жесткий пробел, запрет висящих строк, абзац, начинающийся с новой страницы, межстрочный интервал, колонтитулы и абзацные отступы. Довольно часто можно столкнуться с заявлением "наша разработка может формировать документы в формате Ворд". При дальнейшем рассмотрении оказывается, что "шаблон" хранится непосредственно в информационной базе либо в виде текста, либо в виде форматированного текста, либо в виде набора абзацев и так далее. Как бы ни старались разработчики платформы и приложения, полученный файл это не тот "Ворд", которого ожидает пользователь. Этот эрзац всегда является компромиссом между полноценным файлом Ворда и возможностями системы автоматизации. Для того, чтобы формировать полноценный файл Ворда, со всеми возможностями форматирования, которыми пользователи привыкли пользоваться, требуется пересоздать Ворд внутри информационной системы, что практически недостижимо.

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

Что значит сформировать файл Ворд?

В связи с неоднозначностью сложившейся терминологии, считаю нужным пояснить. Под формированием файла Ворд по пользовательскому шаблону я подразумеваю следующий процесс. Пользователь передает разработчику файл с образцом документа, который хочет получать из информационной системы в автоматизированном режиме. Разработчик дорабатывает информационную систему таким образом, чтобы она позволяла формировать файлы, точно соответствующие первоначальному образцу. Точно, значит без явных указаний пользователя разработчик не меняет по своему усмотрению ни одного элемента форматирования, ни шрифт, ни размер, ни поля, ни колонтитулы. НИЧЕГО не меняет. Совершенно ничего. На выходе пользователь должен получить документ неотличимый от документа, созданного собственноручно.

Способы формирования файла Ворд

Работа программы по формированию файла сводится к модификации образца, предоставленного пользователем. К счастью, пользователи приложений, построенных на базе 1С-Предприятия, люди скучные. И их запросы к формированию файлов невелики. Им не требуются информационные буклеты или рекламные плакаты. Им нужны документы. Договоры, акты, письма, исковые заявления, и т.д. Потому обработка файла программой сводится к замене (вставке) текста на полученный из базы данных, удаление каких-то блоков текста и, быть может, вставке небольших картинок, например, логотипа или штрих-кода.

Существует два популярных способа работы с файлами Ворд:

1. Через СОМ-Объект Ворд.

2. Через непосредственную модификацию файлов docx

Главное отличие между ними заключается в том, что первый способ предоставляет разработчику инструмент - полнофункциональный API, позволяющий делать с документом все то же самое, что может делает пользователь, непосредственно работая в редакторе. Второй же способ предполагает собственную разработку инструмента, на основании документации по формату хранения файла. Если функциональность разработанного инструмента перестанет удовлетворять возникающим потребностям - придется разрабатывать (или искать) новый инструмент. В то время как модернизация кода основанного на API СОМ-объектов не представляет сложностей.

Есть еще и третий способ - через API для работы с файлами формата docx (он же формат Open XML) платформы .NET Framework (набор средств для работы с файлами docx Майкрософт продвигает под названием Open XML SDK). Для мира 1С этот путь совсем уж экзотический, нужно создать собственный интерфейсный слой (на другом языке программирования) между приложением 1С и API платформы .NET.

Второй способ основан на том, что любой файл .docx представляет собой архив zip с содержимым документа в виде файлов xml и, в некоторых случаях, графических файлов. Работа с zip, текстовыми и xml файлами штатно поддерживается языком 1С, поэтому, если разбираться в формате файла, то создавать или модифицировать их можно быстро и просто. Ключевое слово, как обычно, "если" :-) Этот путь в статье не рассматривается. Всем желающим рекомендую готовое решение, которое перекрывает большую часть потребностей пользователей: //infostart.ru/public/675307/

Первый способ предполагает, что на том компьютере, где будет исполняться код приложения и формироваться файл, установлен Майкрософт Офис. При установке, Офис регистрирует в Виндоус СОМ-объекты для каждого из приложений входящих в пакет. Таким образом, другие приложения, запущенные на компьютере, могут через интерфейс СОМ-объектов выполнять любые действия с документами офисных приложений, возможности предоставленного программного интерфейса, как минимум, не уступают возможностям пользователя, редактирующего документ непосредственно в приложении.

Строго говоря, работать с СОМ-объектами Ворд можно как на сервере, так и на клиенте. Но Макрософт не считает компоненты Офиса серверной технологией: http://support.microsoft.com/ru-ru/topic/%.... Как следует из статьи, работать с СОМ-Объектами Ворд на сервере не рекомендуется, работать это начнет только после танцев с бубном и работа будет нестабильной. Хотя в интернете и есть множество примеров работы с СОМ-объектами именно из серверного кода, я буду исходить из того, что СОМ-Объект исполняется на клиентском компьютере.

Главная проблема примеров из интернета по рассматриваемой теме - игнорируется тот факт, что за компьютером сидит живой пользователь. Видимо, предполагается, что после нажатия кнопки "сформировать файл", пользователь должен замереть, не дышать, не дотрагиваться до мыши и клавиатуры в течение всего времени создания файла. А ведь формирование каждого файла может занимать заметное время, в некоторых случаях - больше минуты. И ладно бы вопрос стоял "или так или никак". Но ведь на самом деле, нет. Можно работать с СОМ-Объектом параллельно с работой пользователя, код чувствительный действиям пользователя не имеет никаких преимуществ перед кодом, не мешающим пользователю. Единственная причина, по которой он используется - нежелание разработчика вникнуть в проблему и рассмотреть альтернативные варианты решения.

Код языка 1С для работы с СОМ-Объектами на сервере и на клиенте ничем не отличается. Единственное, за сервером не работает реальный пользователь, поэтому проблема неудачного кода не выплывает с такой остротой. Повторюсь, преимуществ у такого кода все равно нет. Тем более, что код нужно отлаживать, часто это удобнее делать на клиенте, вот и появился пользователь. А еще, может потребоваться перенос работающего кода с сервера на клиент, например, в рамках рефакторинга и изменения архитектуры приложения. А еще, код может работать в файловой базе, где "сервер" очень условен - программный слой, запускаемый на машине каждого пользователя. Таким образом, лучше всего исходить из того, что пользователь за компьютером есть всегда.

Объектная модель Ворд

Ворд, запущенный в качестве СОМ-Объекта, предоставляет доступ к множеству объектов приложения. Понятие "объект" такое же как везде - программная абстракция, имеющая методы и свойства. Методы могут быть как процедурами, так и функциями, при этом функции можно вызывать как процедуры, игнорируя возвращаемое значение. Свойства могут быть либо объектами, либо обычными (скалярными, примитивными) данными, такими как число, строка, логический тип.

Среди объектов особо выделяются специальные объекты-контейнеры, называемые коллекциями. Каждая коллекция предназначена для хранения ссылок на группу однотипных объектов. Например, коллекция Documents хранит ссылки на объекты Document, коллекция Tables хранит ссылки на объекты Table и т.д. Все коллекции именованы во множественном числе, а обычные объекты в единственном. Нумерация объектов в коллекции начинается с единицы. Коллекции Ворд можно перебирать циклом "Для каждого" языка программирования 1С.

Полный список объектов можно, и нужно, смотреть в справочной системе Ворд (раздел справки по Вижуал Бейсику (VBA)). Для старых версий справка откроется локально на компьютере пользователя. Новые версии отправят на сайт Майкрософт: https://docs.microsoft.com/ru-ru/office/vba/api/overview/word/object-model Текст переведен с английского автоматически и местами понять написанное невозможно. Переключение на английский оригинал делается очень просто, достаточно нажать кнопочку "почитать на английском" в правом верхнем углу страницы. Или в адресе ссылки "ru-ru" заменить на "en-us": https://docs.microsoft.com/en-us/office/vba/api/overview/word/object-model

Многие методы объектов Ворда в качестве параметров принимают числовые значения. Для того, чтобы не путаться в числовых значениях, в Вижуал Бейсике предусмотрены именованные константы. Например, константа wdFormatRTF соответствует числу 6. В Вижуал Бейсике можно писать код так:

Document.SaveAs ("имя файла", wdFormatRTF)

Вне VBA именованные константы недоступны, поэтому код 1С будет таким:

Document.SaveAs ("имя файла", 6)

Или, без “магических” чисел, таким:

wdFormatRTF = 6;
Document.SaveAs ("имя файла", wdFormatRTF);

Я предпочитают последний вариант, терпеть не могу непонятных чисел в коде.

Значения всех констант нужно смотреть в справочной системе, там они объединены в смысловые группы, называемые "перечисления" (Enumerations): https://docs.microsoft.com/ru-ru/office/vba/api/word(enumerations)

Запуск Ворд, открытие файла

Традиционно, первые три строчки работы СОМ-Объектом Ворд выглядят так:

Word = Новый COMОбъект ("Word.Application");
Word.Visible = Ложь;
Word.Documents.Open ("C:\готовые документы\файл.docx");

… и это уже неправильно! Третья строчка сразу говорит о том, что перед вами бездумная копипаста. Справедливости ради, бывают и толковые примеры, начинающиеся именно так, но, это лишь подтверждает, что даже в толковых примерах присутствует копипаста, не осмысленная автором. Что неправильно с третьей командой будет объяснено ниже, сначала разберем первые две строки.

Word = Новый COMОбъект("Word.Application");

Запускает приложение Ворд и возвращает на него ссылку. Теперь по ссылке Word мы можем обращаться к СОМ-объекту. Возникает закономерный вопрос, влияет ли как-то окружение, в момент выполнения команды, на результат её работы? Из окружения нас интересует в первую очередь интерактивная работа пользователя с Вордом. Возможны два варианта:

- в момент выполнения Ворд запущен (имеются открытые пользователем файлы)

- в момент вызова Ворд не запущен

Так вот, нет, не влияет. Ворд запускается как новый экземпляр приложения, коллекция Documents запущенного приложения не содержит ни одной ссылки, т.е. доступа к ранее открытым документам через ссылку Word не получить.
Но, после запуска СОМ-Объекта, новые, открываемые пользователем, файлы могут открыться именно в этом экземпляре Ворда. Для пользователя разницы нет, но нам это следует, на всякий случай, учитывать.

Word.Visible = Ложь; // (или Word.Visible = Истина;)

Скрывает Ворд. Т.е. пользователь не будет видеть обрабатываемый файл в отдельном окне. Никакой особой пользы скрытие окна Ворд не несет. Если программа написана корректно, то пользователь не будет мешать программе, а программа не будет мешать пользователю, вне зависимости от того, видимо ли окно обрабатываемого файла. Естественно, при условии, что пользователь не начнет редактировать открытый документ.

Свойству Visible желательно присвоить одно из значений. В противном случае, СОМ-Объект Ворд откроется в скрытом режиме. Но если пользователь откроет какой-нибудь файл, то наш редактируемый файл может неожиданно стать видимым. С другой стороны, если пользователь успеет открыть свой файл после запуска СОМ-Объекта, но перед тем, как будет выполнено присвоение свойству значения Ложь, то открытый файл станет невидимым и недоступным для редактирования пользователем.

В общем, лично я предпочитаю оставлять редактируемый документ в видимом окне.

Перейдем к неправильной части примера

Word.Documents.Open ("C:\готовые документы\файл.docx");

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

Word.Documents.Open ("C:\готовые документы\файл.docx");
Документ = Word.Documents (1);

Ну что ж, разумно. Предполагаем, что открыт только наш документ, соответственно в коллекции Documents есть единственный элемент, значит этот элемент имеет индекс равный единице. Это работает, вероятность того, что пользователь успеет открыть файл в промежуток времени, между запуском СОМ-Объекта и этим присваиванием, ничтожно мала.

Или так:

Word.Documents.Open ("C:\готовые документы\файл.docx");
Документ = Word.ActiveDocument;

Ну что ж, разумно. Последний открытый в Ворде документ становится активным, можно получить на него ссылку и так. Это работает, вероятность того, что пользователь успеет открыть еще один документ после открытия нашего и до получения ссылки на него ничтожно мала.

Примеры чуточку безумные:

Word.Documents.Open ("C:\готовые документы\файл.docx");
Word.Documents(1).Activate();
Документ = Word.ActiveDocument;

WTF? Хотя, безусловно, работает. С теми же оговорками, что и выше.

Самые безумные примеры, которые вы сможете найти на просторах Интернета, сводятся к тому, что ссылку на документ не сохраняют в отдельной переменной, а каждый раз обращаются к документу через свойство ActiveDocument. И это, безусловно и неизбежно, порождает проблемы при одновременной работе пользователя и программы. Если пользователь кликнет мышью в другой файл, то значение свойства ActiveDocument перестанет соответствовать нашему файлу и произойдет ошибка времени исполнения. Это в лучшем случае. В худшем - будет “отредактирован”, читай поврежден, файл пользователя. Вот, посмотрите на код, это оно и есть: https://www.cyberforum.ru/1c-custom/thread2724654.html

Как программировать неправильно, выяснили, теперь о том, как открывать документы правильно.

Для открытия документа можно использовать два метода коллекции Documents. Первый -  Open() приведен выше, второй - Add().

Метод Open() открывает файл для редактирования в Ворде, документ остается связанным с этим файлом - в заголовке окна Ворд указывается имя файла. Открыть можно любой файл, поддерживаемый Вордом, формат файла при редактировании не меняется. Например, открыли файл .rtf, отредактировали, сохранили, файл остался .rtf. Открывать непосредственно шаблон из папки, в которой хранятся шаблоны таким способом не стоит. Если что-то произойдет не так, например, сработает автосохранение в Ворде, шаблон будет испорчен. Сначала файл шаблона следует скопировать (при работе в клиент-серверном варианте это само собой разумеющиеся действие), а потом можно открывать.

Метод Add() создает новый документ на основании указанного шаблона. Шаблоном может быть любой файл, не обязательно родные для Ворда .doc или .docx или .dot. Открытый документ с файлом-шаблоном не связывается, в заголовке окна Ворд будет надпись "Документ1 - Word". При этом информация о формате исходного файла не сохраняется. Открывается просто документ Ворд, содержащий в себе всю информацию из указанного файла. При сохранении без явного указания типа файла он будет сохранен как .docx. Единственное исключение - документ, открытый на основе файла .doc, такие документы по умолчанию сохраняются в файлы .doc. Метод Add() можно использовать для создания документов на основании оригинала шаблона, шаблон повредить невозможно даже случайно.

Методы Open() и Add() являются функциями, т.е. возвращают значение. Причем возвращают они ссылку на новый документ. И ловить потом этот документ в коллекции Documents нам не нужно, ссылку можно сразу сохранить в переменной для дальнейшего использования. Таким образом, для открытия используются следующие команды:

Документ = Word.Documents.Open ("C:\готовые документы\файл.docx");

Или

Документ = Word.Documents.Add ("C:\шаблоны\файл.docx");

Закрытие файла, завершение работы с СОМ-Объектом

Когда шаблон заполнен требуемым образом его необходимо сохранить. Самый простой вариант, если файл открыли методом Open(), для сохранения достаточно вызвать метод Save():

Документ.Save();

Если же документ еще не связан с файлом, нужно вызвать метод SaveAs():

Документ.SaveAs ("C:\готовые документы\файл");

Если формат по умолчанию нас не устраивает, вторым параметром метода можно явно задать тип файла:

wdFormatRTF = 6;
Документ.SaveAs ("C:\готовые документы\файл", wdFormatRTF);

Обратите внимание, не стоит указывать расширение файла. Ошибки не будет, если расширение будет указано явно, например так:

Документ = Word.Documents.Add ("C:\шаблоны\файл.doc");
//...
Документ.SaveAs ("C:\готовые документы\файл.doc");

Имеется в виду, что не будет ошибки времени выполнения. Однако, приведенный выше пример идеологически неверен. Допустим, через некоторое время шаблон был заменен и файл шаблона получил расширение .docx. Для внесения изменений в программу нам потребуется две правки, первая в методе Add(), вторая в методе SaveAs(). В этом и проблема, код дублируется, одно изменение должно вносится в одном месте программы, а не в разных. Если расширение файла не будет указано, при сохранении будет добавлено расширение, соответствующее типу сохраняемого файла. Если же расширение будет указано неверно, т.е. не будет соответствовать типу файла, то... либо получаем ошибку времени исполнения, либо файл сохранится в формате, не соответствующем расширению (в зависимости от комбинации тип/расширение возможно и то и другое). Обе ситуации ненормальны. Ошибка времени выполнения, конечно, будет отловлена на этапе тестирования. А ошибка несоответствия расширения фактическому типу данных выйдет потом боком пользователю.

Иногда после сохранения файла нужно узнать его полное имя, т.е. включая путь и расширение. Например, чтобы отправить файл по электронной почте или записать в базу. Если мы сохранили файл методом SaveAs(), то полного имени мы не знаем, ведь расширение к имени файла добавил Ворд. Ну так из Ворда же полное имя можно получить, у документа есть доступное для чтения свойство FullName:

ПолноеИмяФайла = Документ.FullName;

Завершение работы с СОМ-Объектом рекомендуют (неправильно) делать так:

Документ.Close();
Word.Quit(0);

На первый взгляд, можно и не заметить нолик в параметре метода Quit(). А он важен. Это просто константа wdDoNotSaveChanges :-). Закрыться-то Ворд закроется, вместе со всеми файлами, которые пользователь, возможно, открыл и редактирует.

Если мы исходим из предположения, а мы из него исходим, что пользователь может работать интерактивно со своими собственными файлами, которые могут быть открыты в том же экземпляре Ворда, что и наш СОМ-Объект, то торопиться принудительно выгонять пользователей и закрывать экземпляр приложения не стоит. Можно проверить, есть ли еще открытые документы, кроме нашего. Если есть, не закрывать экземпляр Ворда, пусть пользователь спокойно работает, если других документов нет - закрыть:

Документ.Close();
Если (Word.Documents.Count = 0) Тогда
    Word.Quit();
КонецЕсли;

Заполнение шаблона с помощью именованных полей (свойств документа)

Не очень популярный, но иногда встречающийся способ.

Сначала в документ добавляются пользовательские свойства. Для Ворда 2016 это делается так:

- открыть документ

- вкладка "Файл"

- Сведения /Свойства / Дополнительные свойства

 

- вкладка "Прочие"

 

- ввести название (имя) свойства и какое-нибудь значение

- нажать "Добавить"

- и т.д. создать все необходимые для заполнения шаблона свойства.

Имя свойства вводим разумное, по нему будем обращаться к свойству из программы, значение - произвольный текст, для того чтобы видеть, как свойство отображается в документе.

Если у файла .doc уже есть хотя бы одно дополнительное свойство, то в свойствах файла появляется соответствующая закладка и работать со свойствами (добавлять, удалять) можно прямо из проводника, не запуская Ворд

 

Забавно, что для файлов .docx это не работает. Наличие дополнительных свойств никак не отображается в свойствах файла.

Для того чтобы удобнее было работать с текстом документа включим выделение полей:

- вкладка "Файл"

- Параметры

- Дополнительно

- Затенение полей установить "Всегда"

 

В результате поля в тексте документа будут выделены серой заливкой. Серая заливка отображается только при просмотре документа на экране. При печати же никакой заливки не будет.

Для вставки созданных свойств документа в качестве полей необходимо проделать следующие действия:

- Вкладка "Вставка"

- Раздел "Текст"

- Кнопка "Экспресс-блоки"

- "Поле..."

 

- выбрать вид поля "DocProperty"

- в списке "Свойства поля" будут все добавленные нами свойства документа. Если имена свойств давались русскими символами, то искать их надо внизу списка:

 

- "Ок"

Для того чтобы быстро посмотреть, какому свойству документа соответствует то или иное вставленное в текст поле можно кликнуть правой мышью по полю, в контекстном меню выбрать либо пункт "Изменить поле...", тогда вернемся к окну отображенному на скриншоте выше. Либо выбрать пункт "Коды/значения полей", тогда вместо значения поля будет отображена служебная информация, в которой указано имя свойства:

Получить доступ к свойствам можно через коллекцию CustomDocumentProperties документа:

Документ.CustomDocumentProperties("ЗаказчикДолжностьПодписантаРП").Value = "директора";

Важный момент, который стоит учитывать, заключается в том, что присвоение свойствам новых значений никак не отображается в тексте документа. Свойство само по себе, поле, отображающее значение свойства в тексте документа, само по себе. Для того чтобы поле отобразило актуальное значение свойства, поле необходимо обновить. Обновить все поля документа можно командой:

Документ.Fields.Update();

Такой метод заполнения шаблонов обладает рядом недостатков, поэтому используется редко.

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

Во-вторых, поддержка и сопровождение шаблонов, построенных на свойствах документа очень трудоемка. Нужно сначала создать все требуемые свойства в файле, предоставленном пользователем. Затем вручную каждое свойство вставить в текст документа. Для того чтобы посмотреть или изменить имя свойства требуется множество лишних действий мышью.

Наконец, в результате пользователь получает не совсем такой файл, который передал разработчику. При редактировании поля себя ведут не так как простой текст. Если удалять или вставлять текст внутри поля, то никаких аномалий не проявляется. Если же попытаться удалить текст с переходом через границу поля (клавишами <Delete> или <BackSpace>), то при достижении границы поля оно норовит удалиться целиком. Это очень неудобно и раздражает.

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

Если пользователь скопирует фрагмент заполненного документа, содержащего поля, то поля скопируются вместе со значениями, т.е. пользователь не увидит никаких изъянов после копирования. Но свойства документа вслед за текстом не копируются. Если в новом документе по каким-то причинам будут обновлены значения полей, то вместо разумного текста в документе появятся надписи "Ошибка! Неизвестное имя свойства документа".

Заполнение шаблона через поиск и замену

В основе метода лежит размещение в тексте шаблона специально выделенных с помощью редко встречающихся символов блоков текста:

В данном случае для выделения блоков использованы символы "$(" и ")$". Затем средствами поиска и замены Ворда каждый такой блок заменяется на соответствующее значение из базы. Эти заменяемые блоки можно называть полями, параметрами, закладками, реквизитами, но все эти термины уже используются в обсуждаемой предметной области. Чтобы не создавать дополнительной путаницы, далее по тексту я буду называть такие блоки якорями.

Внутри метода существуют два подхода. Первый (неправильный и при этом наиболее распространенный) основан на использовании объектов Selection, второй на использовании объектов Range.

Объект Selection представляет текущий выделенный фрагмент. Выделенный фрагмент представляет выбранную (или выделенную) область в документе или представляет точку вставки, если в документе ничего не выбрано. Каждый раз, когда пользователь выделяет фрагмент мышью или удерживая <Shift> - создается объект Selection. В каждом документе может быть одновременно не более одного объекта Selection.

Использовать объекты Selection при обращении к документу - плохая практика. Если пользователь откроет редактируемый документ и кликнет по тексту мышью, текущее выделение сместиться, объект Selection будет соответствовать точке вставки в позиции курсора, это с огромной вероятностью приведет к неверной работе с заполняемым шаблоном. Более того, можно найти множество примеров обращения к объекту Word.Selection, который соответствует выделению в том окне приложения Ворд, которое сейчас активно. В этом случае, для того, чтобы вызвать сбой в работе программы, пользователю достаточно развернуть окно другого документа, открытого в том же экземпляре Ворда, что и обрабатываемый шаблон.

Для редактирования документа без интерактивного взаимодействия с пользователем наиболее удобны объекты Range. В одном документе может быть сколько угодно объектов Range. Каждый документ Range представляет собой ссылку на фрагмент документа, определяемый номерами начального и конечного символов. Свойства Range.Start (номер первого символа диапазона) и Range.End (номер последнего символа диапазона) доступны для записи. Записывая новые значения в эти свойства, можно перемещать объект Range в документе.

У объектов Selection и Range есть свойство Text доступное для записи. Присвоение этому свойству нового значения эквивалентно замене текста в документе.

У объектов Selection и Range есть объектное свойство Find, с помощью которого доступен функционал поиска и замены Ворда. Для выполнения поиска нужно вызвать метод Execute() объекта Find. Поиск осуществляется внутри выделения Selection или внутри диапазона Range . После вызова Execute() соответствующий объект Selection или Range изменяется и соответствует найденному фрагменту:

Документ.Select();
Word.Selection.Find.Execute("$(ЗаказчикДолжностьПодписантаРП)$");
Word.Selection.Text = "директора";

или

Range = Документ.Content;
Range.Find.Execute("$(ЗаказчикДолжностьПодписантаРП)$");
Range.Text = "директора";

В этих примерах если текст (якорь) "$(ЗаказчикДолжностьПодписантаРП)$" есть в тексте шаблона, он будет заменен на текст "директора". Если же искомого фрагмента в тексте документа нет, то весь текст документа будет заменен единственным словом, т.к. размеры объектов Selection и Range не изменятся. Если мы предполагаем, что в шаблоне может и не содержаться какого-то якоря, то нужно проверять значение, возвращаемое функцией Execute(). Если поиск успешен, то возвращается Истина, иначе Ложь.

Range = Документ.Content;
Если Range.Find.Execute("$(ЗаказчикДолжностьПодписантаРП)$") Тогда
    Range.Text = "директора";
КонецЕсли;

Опять же, в тексте может быть и несколько одинаковых якорей, тогда нужно организовать цикл.... Но так никто не делает, т.к., во-первых, метод Execute(), может сразу выполнять замену найденного элемента. Для этого десятым(!) параметром в него нужно передать строку, на которую будет заменен найденный фрагмент. Во-вторых, метод Execute() может заменить сразу все вхождения строки поиска, для этого одиннадцатым параметром в метод нужно передать значение константы wdReplaceAll

Range = Документ.Content;
WdReplaceAll = 2;
Range.Find.Execute("$(ЗаказчикДолжностьПодписантаРП)$",,,,,,,,, "директора", wdReplaceAll);

За кадром остался вопрос, если обращение к выделению через Word.Selection - вселенское зло, то как следует правильно обращаться к объекту Selection? Конечно, правильно к нему вообще не обращаться и пользоваться только объектами Range.

Но если все-таки почему-то нужен именно объект Selection, то для минимизации интерактивного взаимодействия с пользователем обращаться нужно именно к объекту Selection нашего документа, а не всего приложения. Но у объекта Document нет свойства Selection! Это потому, что активный документ может состоять не из одного окна, а из нескольких. Например, открыли вы окно свойств абзаца у документа, документ тот же, а окна у документа уже два - одно с текстом документа, второе с параметрами абзаца. Так вот, Selection, это свойство именно окна. Поэтому для работы с объектами Selection нужно сразу сохранить ссылку на главное окно документа. Сделать это разумнее всего сразу после открытия документа методами Add() или Open():

Документ = Word.Documents.Add ("C:\шаблоны\файл.docx");
ОкноДокумента = Документ.Windows(1);
//...
Документ.Select();
ОкноДокумента.Selection.Find.Execute("$(ЗаказчикДолжностьПодписантаРП)$");
ОкноДокумента.Selection.Text = "директора";

Особенности работы с колонтитулами

На самом деле, указанные выше приемы поиска и замены текста работают только в основном тексте документа и не затрагивают колонтитулы. Вообще, в Ворде колонтитулы очень обособлены и даже в простом документе их может быть несколько. Во-первых, есть нижние и верхние колонтитулы, во-вторых, колонтитулы первой и последующей страниц могут быть различными, наконец, у каждого раздела документа могут быть собственные колонтитулы. Для того, чтобы получить доступ ко всем колонтитулам документа нужно перебрать коллекции Headers и Footers, затем в каждом колонтитуле выполнить поиск и замену якорей. Но в документе нет этих коллекций. В документе есть коллекция Sections (разделы), в каждом разделе есть свои коллекции Headers и Footers. Таким образом, перебор всех колонтитулов выполняется так:

WdReplaceAll = 2;
Для Каждого Section Из Документ.Sections Цикл
    Для Каждого Header Из Section.Headers Цикл
        Range = Header.Range;
        Range.Find.Execute("$(якорь)$",,,,,,,,, "значение", wdReplaceAll);
    КонецЦикла;
    Для Каждого Footer Из Section.Footers Цикл
        Range = Footer.Range;
        Range.Find.Execute("$(якорь)$",,,,,,,,, "значение", wdReplaceAll);
    КонецЦикла
КонецЦикла;

Более лаконичное решение заключается в использовании коллекции StoryRanges. Эта коллекция содержит диапазоны (range) всех блоков(?), частей(?) (в справке используется термин story) документа. Тело документа, это главный блок (main story), тоже есть в этой коллекции. Т.е. необязательно искать якоря отдельно в теле документа, отдельно в колонтитулах, все можно сделать одним циклом:

Для Каждого Range Из Документ.StoryRanges Цикл
    Range.Find.Execute("$(якорь)$",,,,,,,,, "значение", wdReplaceAll);
КонецЦикла;

Заполнение шаблона с помощью закладок

Технология неплохо описана в этой статье: http://blagin.ru/ispolzovanie-shablonov-word-v-1s/

Только вместо

ШаблонВорд.Bookmarks("Закладка1").Select();
ШаблонВорд.Application.Selection.TypeText("Текст для закладки №1.");

Нужно использовать

Range = ШаблонВорд.Bookmarks("Закладка1").Range;
Range.Text = "Текст для закладки №1.";

Теперь вы знаете почему и, вообще, готовы к статьям из Интернета :-)

Замечу, оба варианта удаляют закладку, на место которой вставляется текст. В большинстве случаев это удобно: пользователь получает полностью чистый документ, без остаточных следов шаблона. Да и программу можно писать через цикл "пока в документе есть закладки повторять..." 

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

ШаблонВорд.Bookmarks.Add("Закладка1", Range);

Вариант с Selection.TypeText() придется немного переделать, т.к. после метода TypeText() объект Selection будет указывать на точку ввода после последнего добавленного символа. Чтобы выделение не схлопнулось в точку ввода, а соответствовало добавленному тексту, можно воспользоваться обращением к свойству Text объекта Selection

ШаблонВорд.Bookmarks("Закладка1").Select(); 
ШаблонВорд.Application.Selection.Text = "Текст для закладки №1."; 
ШаблонВорд.Bookmarks.Add("Закладка1", ШаблонВорд.Application.Selection.Range); 

На первый взгляд может показаться, что решение с закладками - вариация решения со свойствами документа. Но это совсем не так, закладки позволяют делать то же самое, что и поиск - установить объект Range на нужный фрагмент в тексте. Далее найденную позицию можно использовать как угодно - заменить текст, вставить в эту точку картинку, удалить большой блок текста между двумя найденными позициями и т.д. Со свойствами, отображаемыми с помощью полей, ничего подобного организовать не получится.

У закладок есть особенность, которой не обладают якоря для поиска и замены - имя закладки уникально. В этом основной смысл закладок - однозначно определить участок текста. Но при заполнении закладок реквизитами из базы это может вызвать некоторое неудобство. Вот, к примеру, статья: //infostart.ru/1c/articles/1122573/

Главная проблема у автора не в закладках, а в сакральности кода движка, осуществляющего заполнение шаблона Ворд. Да, если возможности подправить движок нет, то приходится мириться и с автозапуском макросов в документах и с добавлением в документы полей. Если же контроль над движком у нас есть, то проблема и не проблема вовсе. Вот ключевая фраза из обсуждаемой статьи:

Действительно, для решения проблемы, закладку "Ответственный" не надо создавать вообще. Нужно сразу создавать закладки вида "Ответственный0" или "Ответственный_". Последний символ не важен, лишь бы требованиям к именам закладок удовлетворял.

При заполнении шаблона, перебираем все закладки, отбрасываем последний символ имени закладки и по оставшейся смысловой части имени ищем значение в заранее подготовленной структуре данных:

Пока Документ.Bookmarks.Count > 0 Цикл	 
	Закладка = Документ.Bookmarks(1); 
	ИстинноеИмяЗакладки = Лев(Закладка.Name, СтрДлина(Закладка.Name) - 1); 
	Range = Закладка.Range; 
	Range.Text = СтруктураСДанными[ИстинноеИмяЗакладки]; 
КонецЦикла;

Удаление фрагментов текста

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

RangeBegin = Документ.Range();
RangeBegin.Find.Execute("#(Блок1_begin)#");
Range = Документ.Range();
Range.Find.Execute("#(Блок1_end)#");
Range.Start = RangeBegin.Start - 1;
Range.Text = "";

Range = Документ.Range();
Range.Find.Execute("#(Блок2_begin)#");
Range.Start = Range.Start - 1;
Range.Text = "";

Range = Документ.Range();
Range.Find.Execute("#(Блок2_end)#");
Range.Start = Range.Start - 1;
Range.Text = "";

Может вызвать удивление, что за таинственные константы "1" используются для расчета начального символа удаляемого диапазона. Дело в том, что якорь всегда будет отделен от остального текста либо пробелом, либо символом конца абзаца, т.е. будет находится на отдельной строке. Если удалить только якорь, то в точке, где он находился, останется либо двойной пробел, либо пустая строка (абзац). Чтобы этого избежать, удаляется один дополнительный символ перед удаляемым блоком, это всегда будет либо пробел, либо "энтер".

Вставка картинок

Все картинки в документе Ворд делятся на два вида - вставленные как символ в текст и произвольно расположенные в графическом слое документа (текст их может либо обтекать, либо нет, зависит от параметров каждого объекта). Первый вид картинок представляется объектом InlineShape и доступен в коллекции InlineShapes.  Второй вид - объектом Shape и доступен в коллекции Shapes документа. Для деловых документов возиться с размещением картинок в графическом слое нет смысла, достаточно объектов InlineShape.

Принцип прост, находим соответствующий якорь и заменяем его картинкой:

Range = Документ.Range();
Range.Find.Execute("$[ЯкорьКартинки]$");
Range.Text = "";
Документ.InlineShapes.AddPicture (ИмяФайлаКартинки,,, Range);

Работа с таблицами

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

В статье http://blagin.ru/1s-word-shablon-zapolnenie-tablic-v-shablone-word/ описан один из подходов к заполнению таблиц. Вы можете увидеть следующие этапы:

- поиск таблицы в документе с помощью размещенной внутри таблицы закладки.

- знание о структуре таблицы видно в применении команды MoveDown(), для таблиц с другой структурой шапки или другом расположении закладки, набор команд для перемещения выделения может быть другим. Также знание о структуре таблицы проявляется в знании о том, какие якоря нужно заменять, т.е. программа знает, что после вставки строки в документе появятся три якоря и какие именно тоже знает.

- копирование строки и вставка через буфер обмена

- заполнение вставленной строки через поиск и замену якорей

- удаление строки-образца перед завершением алгоритма

Однако, метод, предложенный автором статьи, совсем плох с точки зрения интерактивного воздействия на окружение пользователя. Если у пользователя что-то было помещено в буфер обмена до начала формирования файла, то это что-то будет тут же утеряно, вместо этого в буфере пользователь найдет строку таблицы с якорями. Во время работы приложения нельзя работать не только с Вордом, нельзя вообще ничего делать. Ведь при работе пользователю буфер обмена нужен очень часто. Даже при копировании файлов, многие им пользуются. Как только пользователь поместит что-то в буфер обмена, строка-образец из буфера исчезнет и программа не сможет закончить работу.

Заполнение таблицы по фен-шую:

- размещаем якорь в любой ячейке строки-образца

- средствами поиска устанавливаем объект Range на якорь. Теперь через свойства этого объекта Range у нас есть ссылки на таблицу, строку, столбец и ячейку.

- вставляем строку над строкой-образцом. Вставленная строка копирует все параметры (шрифт, цвет, заливка) строки-образца.

- заполняем каждую вставленную строку требуемым текстом, затем вставляем следующую строку и т.д. Каждая новая вставленная строка вставляется между уже заполненными строками и строкой-образцом

- удаляем строку-образец (как раз вместе с якорем, так что отдельно якорь удалять не нужно)

Range = Документ.Range();
Range.Find.Execute("#[ЯкорьТаблицы]#");
Table = Range.Tables(1);
СтрокаОбразец = Range.Rows(1);
Для Счетчик = 1 По 10 Цикл
    НоваяСтрока = Table.Rows.Add(СтрокаОбразец);
    НоваяСтрока.Cells(1).Range.Text = Счетчик;
    НоваяСтрока.Cells(2).Range.Text = Счетчик + 10;
    НоваяСтрока.Cells(3).Range.Text = Счетчик + 100;
КонецЦикла;
СтрокаОбразец.Delete();

 

 

Специальные предложения

Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. gubanoff 51 15.02.21 12:25 Сейчас в теме
(0) С СОМ объектом все хорошо. Только работает нестабильно, тормозит, зависит от версии Word, требует наличия Word на машине, не работает на Linux.
Лис Р; +1 Ответить
2. Spektr 765 15.02.21 20:09 Сейчас в теме
Недавно видел еще один способ - Variables https://infostart.ru/public/669785/
3. biimmap 111 16.02.21 17:18 Сейчас в теме
Хорошая статья. Недавно долбался с опен офисом... Который не требует наличия офиса))) Не хватало подобного материала. Пришлось самому писать). В профиле можно увидеть если интересно кому.
4. moff 6 16.02.21 20:58 Сейчас в теме
А популярный кроссплатформенный способ формирования .docx с помощью БСП почему проигнорирован?
5. Yashazz 3740 17.02.21 09:05 Сейчас в теме
(4) Потому что не надо связываться с БСП, граблей не оберёшься.
10. moff 6 17.02.21 12:40 Сейчас в теме
(5) о каких именно граблях идет речь? зачем строить свои грабли, когда 95% потребностей по формированию печатных форм по шаблонам .docx легко закрываются функционалом БСП?
19. Yashazz 3740 17.02.21 18:03 Сейчас в теме
(10) Затем, что свои грабли с очередным релизом, который главбух вечерком грузанул через сервис 1С, внезапно не сломаются. А в БСП любят менять смысл, состав и порядок параметров, переименовывать и переносить функции и модули) Словом, встанете пару раз на оные грабли - познаете дзен))
11. Sindbad_M 26 17.02.21 15:19 Сейчас в теме
(4)
Потому, что БСП работает не через COM, а непосредственно модифицирует .docx. А это совсем за рамками заявленной в статье темы.

БСП - пример готового решения, а не инструмента. Об этом в статье упоминание есть. По сути, БСП предоставляет широкий, но ограниченный функционал по заполнению шаблона с помощью подстановочных полей-параметров. Если потребуется выйти за рамки возможностей этого функционала -- тупик. Можно начинать разработку собственного инструмента с нуля. И на данный момент широта функционала лишь повторяет функционал встроенных в конфигурацию макетов печатных форм. Из мануала даже не понять, можно ли использовать предопределенное оформление разных столбцов при заполнении таблицы: https://its.1c.ru/db/bsp314doc#content:4:1:issogl3_%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%­BA%D0%B0_%D0%BF%D0%B5%D1%87%D0%B0%D1%82%D0%BD%D1%8B%D1%85_%D­1%84%D0%BE%D1%80%D0%BC_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB­%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%B­C%D0%B0%D0%BA%D0%B5%D1%82%D0%BE%D0%B2_%D0%B2_%D1%84%D0%BE%D1­%80%D0%BC%D0%B0%D1%82%D0%B5_%D0%BE%D1%84%D0%B8%D1%81%D0%BD%D­1%8B%D1%85_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%­D0%BE%D0%B2_office_open_xml
18. Sindbad_M 26 17.02.21 16:47 Сейчас в теме
(4)
Потому, что БСП работает не через COM, а непосредственно модифицирует .docx. А это совсем за рамками заявленной в статье темы.

БСП - пример готового решения, а не инструмента. Об этом в статье упоминание есть. По сути, БСП предоставляет широкий, но ограниченный функционал по заполнению шаблона с помощью подстановочных полей-параметров. Если потребуется выйти за рамки возможностей этого функционала -- тупик. Можно начинать разработку собственного инструмента с нуля. И на данный момент широта функционала лишь повторяет функционал встроенных в конфигурацию макетов печатных форм. Из мануала даже не понять, можно ли использовать предопределенное оформление разных столбцов при заполнении таблицы: https://its.1c.ru/db/bsp314doc#content:4:1:issogl3_%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%­BA%D0%B0_%D0%BF%D0%B5%D1%87%D0%B0%D1%82%D0%BD%D1%8B%D1%85_%D­1%84%D0%BE%D1%80%D0%BC_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB­%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%B­C%D0%B0%D0%BA%D0%B5%D1%82%D0%BE%D0%B2_%D0%B2_%D1%84%D0%BE%D1­%80%D0%BC%D0%B0%D1%82%D0%B5_%D0%BE%D1%84%D0%B8%D1%81%D0%BD%D­1%8B%D1%85_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%­D0%BE%D0%B2_office_open_xml
6. Yashazz 3740 17.02.21 09:07 Сейчас в теме
Предпочитаю обходиться без шаблонов, так оно более предсказуемо. https://infostart.ru/1c/articles/391493/
7. Yashazz 3740 17.02.21 09:08 Сейчас в теме
А вообще, неплохой обзор, и вовсе даже не велосипед. Некоторые неочевидные моменты хорошо разъяснены.
8. DmitryKSL 155 17.02.21 09:25 Сейчас в теме
Только вместо

ШаблонВорд.Bookmarks("Закладка1").Select();
ШаблонВорд.Application.Selection.TypeText("Текст для закладки №1.");
Нужно использовать

Range = ШаблонВорд.Bookmarks("Закладка1").Range;
Range.Text = "Текст для закладки №1.";
Теперь вы знаете почему и, вообще, готовы к статьям из Интернета :-)

Так и не понял почему?
Замечу, оба варианта удаляют закладку, на место которой вставляется текст

Не удаляют. Можно повторно вставить текст в закладку.
12. Sindbad_M 26 17.02.21 15:29 Сейчас в теме
(8)
Так и не понял почему?

Потому, что использование объектов Selection делает невозможной работу пользователя с Вордом во время заполнения шаблона. А объекты Range пользователю не мешают.
(8)
Не удаляют. Можно повторно вставить текст в закладку.

Удаляют. НО можно повторно вставить закладку в текст. И в статье как раз это написано.
13. DmitryKSL 155 17.02.21 15:43 Сейчас в теме
(12) Возможно нюанс в чем-то другом. Т.к.
использование объектов Selection делает невозможной работу пользователя с Вордом во время заполнения
не проявляется.
Например могу формировать для документа с табличной частью десятки документов word (для каждой строки по одному), и это не мешает мне работать с открытым документом.
Удаляют

У меня это не так, все закладки остаются.
16. Sindbad_M 26 17.02.21 16:14 Сейчас в теме
(13)
Дальше надо смотреть код. Это касается и Selection и закладок.
В статье описано, опасность работы с Selection проявляется тогда, когда пользовательский документ открыт в том же экземпляре Ворда, что и СОМ-Объект. Она выше, если обращаться к свойству ActiveSelection приложения и почти не заметна, если обращаться к свойству Selection окна документа.

Фразу про количество документов, связанных с количеством строк, честно говоря, не понял.
9. DmitryKSL 155 17.02.21 09:47 Сейчас в теме
Пользователь передает разработчику файл с образцом документа, который хочет получать из информационной системы в автоматизированном режиме. Точно, значит без явных указаний пользователя разработчик не меняет по своему усмотрению ни одного элемента форматирования, ни шрифт, ни размер, ни поля, ни колонтитулы. НИЧЕГО не меняет. Совершенно ничего. На выходе пользователь должен получить документ неотличимый от документа, созданного собственноручно.

Т.е. я просто должен вставить в нужные места текст и рассчитывать что ничего на странице не разъедется? Это так не работает, практически никогда.
14. Sindbad_M 26 17.02.21 15:44 Сейчас в теме
(9)
вставить в нужные места текст и рассчитывать что ничего на странице не разъедется? Это так не работает, практически никогда.

Это так работает практически всегда. Просто потому, что повторяет действия пользователя при ручном заполнении шаблонов -- пользователь стирает неактуальный текст, заменяя его новым, актуальным. Зависит, конечно, от качества шаблона. Если пользователь зашлифовал шаблон для себя любимого, то и автоматическое заполнение пройдет как по маслу.
Да и что может "разъехаться"? Это же Ворд, текст перенесется на новую строку и/или страницу с учетом заданного форматирования абзацев.
15. DmitryKSL 155 17.02.21 16:09 Сейчас в теме
(14)
Да и что может "разъехаться"? Это же Ворд, текст перенесется на новую строку и/или страницу с учетом заданного форматирования абзацев

Вот простейший пример. Если заполнять город автоматически, то например, Санкт-Петербург сильно длинее чем Москва и блок под дату сдвинется на строку ниже, что по мнению пользователя означает разъедется. Я то знаю что надо вставить таблицу, настроить выравнивание в ячейках, убрать видимость границ и тогда это будет заполняться как надо. Но ни один пользователь еще ни разу не дал такой шаблон, чтобы ничего не переделывать самому.
Прикрепленные файлы:
17. Sindbad_M 26 17.02.21 16:41 Сейчас в теме
(15)
Но ни один пользователь еще ни разу не дал такой шаблон, чтобы ничего не переделывать самому.

А зачем это пользователю? Ведь вы же за них это делаете.
Впрочем, я не имел в виду такую степень занудства.
Имелось в виду, что разработчик, вместо того чтобы взять и сделать, начинает диктовать пользователю что и как теперь будет в шаблоне. Вроде такого:
- ну и что, что в образце написано "А.С. Пушкин", теперь будет "Пушкин А.С."
- ну и что, что средний столбец был выделен курсивом, теперь вся таблица будет одним шрифтом
- ну и что, что в образце "уважаемый/ая" с привязкой к полу. Переделайте образец на унисекс.
20. DmitryKSL 155 17.02.21 18:38 Сейчас в теме
(17)Т.е по существу сказать нечего?
21. Sindbad_M 26 17.02.21 20:21 Сейчас в теме
(20) По существу я раскрыл мысль с "ничего не менять". В конечном итоге, самый лучший вариант - запросить у пользователя, действительно ли он хочет, чтобы при подстановке "Санкт-Петербург" съезжала дата на новую строчку? Если съезжающая дата - не лучший для пользователя вариант, подсказать способы улучшения шаблона (таблица, символ табуляции), но за пользователя правки не вносить.
22. user747134 19.02.21 20:05 Сейчас в теме
У объекта Fields есть метод Unlink(), который заменяет каждое поле на его последний результат, https://docs.microsoft.com/ru-ru/office/vba/api/word.fields.unlink.
Можно делать так:
Документ.Fields.Update();
Документ.Fields.Unlink(); // для каждого из полей документа заменить вхождение поля на значение этого поля
Sindbad_M; +1 Ответить
Оставьте свое сообщение

См. также

Звуковое управление в 1С 8.3 Промо

Практика программирования v8 1cv8.cf Бесплатно (free)

В данной статье описано создание библиотеки для звукового управления (выполнение команд голосом) для платформы 1С 8.3. Задача была поставлена так, чтобы модуль функционировал непосредственно на клиенте 1С, осуществляя управление формами, и взаимодействовал с интерфейсом.

16.03.2021    2760    velemir    30    

Полезные примеры СКД, ч.2

Практика программирования v8 v8::СКД Бесплатно (free)

Еще несколько примеров решения задач в СКД.

06.04.2021    3167    Neti    7    

Обзор полезных методов БСП 3.1.4

Практика программирования БСП (Библиотека стандартных подсистем) v8 1cv8.cf Бесплатно (free)

Библиотека стандартных подсистем (далее - БСП) является частью любой типовой конфигурации, поэтому умение применять готовые процедуры и функции повышает качество разработки и избавляет от написания лишнего кода. К сожалению, не у всех есть время и упорство овладеть всей документацией, поэтому я собрал воедино наиболее популярный функционал.

25.03.2021    12075    rayastar    45    

Базовые вещи БСП, которые облегчат жизнь программисту 1С

Практика программирования БСП (Библиотека стандартных подсистем) v8 1cv8.cf Россия Бесплатно (free)

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

30.08.2020    12627    quazare    34    

Serverless (Faas) в 1С. Создание и вызов Yandex Cloud Functions Промо

Универсальные функции Практика программирования v8 Бесплатно (free)

"Я не могу просто взять и скопировать код с гитхаба", "у нас 1С микросервисами окружена", "возможностей мало" - частые фразы 1С разработчиков. которым не хватает возможностей платформы в современном мире. Faas, конечно, история не новая, но нас сдерживало 152ФЗ и задержки по пингам. Для того, чтобы действительно использовать в 1С код, к примеру, на Python, надо было приложить усилия. Теперь всё намного проще - берём и используем.

28.12.2020    5162    comol    31    

Форма выбора (подбор) в управляемых формах

Практика программирования v8 v8::УФ 1cv8.cf Россия Бесплатно (free)

Разбор небольших примеров того, как правильно открывать форму выбора (подбора) в управляемых формах, не прибегая к модальным окнам.

08.05.2020    42374    user5300    17    

Программная работа с настройками СКД

Практика программирования v8 v8::СКД 1cv8.cf Бесплатно (free)

Нюансы программной работы с настройками системы компоновки данных в отчетах и динамических списках. Обзор всех видов настроек компоновки. Что в каких случаях правильно применять. В качестве примера рассмотрена работа с отборами и группировками.

27.01.2020    43558    ids79    26    

[СКД] Программное создание схемы компоновки данных

Практика программирования v8 v8::СКД 1cv8.cf Бесплатно (free)

Сделаем отчет на СКД полностью программно, без использования макета "схема компоновки данных".

15.01.2020    32692    John_d    22    

Использование программных перечислений, ч.1: строковые константы Промо

Практика программирования v8 1cv8.cf Бесплатно (free)

Часто ли у вас возникает необходимость в коде выполнять сравнение на строку?

10.12.2016    38881    unichkin    74    

Последовательности событий при проведении документа 1С. Шпаргалка + про формы + про расширения

Практика программирования v8 Россия Бесплатно (free)

Собрал информацию о событиях/подписках/расширениях в одном месте.

30.12.2019    25167    kuzyara    38    

30 задач. Странных и не очень

Практика программирования v8 Бесплатно (free)

30 задач на знание языка программирования 1С и некоторого поведения платформы. Маленьких. Странных и не очень.

02.12.2019    19665    YPermitin    60    

Как передать IP адрес, который вызвал HTTP запрос в 1C (для веб-сервера Apache)

Практика программирования v8 Бесплатно (free)

Столкнулся с задачей получения IP адреса, который вызывает http сервис 1С. Итак, решение:

22.11.2019    10250    Sibars    19    

Вспомогательные инструкции в коде 1С Промо

Практика программирования v8 1cv8.cf Бесплатно (free)

Помогаем редактору кода 1С помогать нам писать и анализировать код.

15.10.2018    32657    tormozit    105    

Полезные процедуры и функции для программиста

Практика программирования Универсальные функции v8 1cv8.cf Россия Бесплатно (free)

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

07.10.2019    34317    HostHost    41    

Таблица значений. Нюансы

Практика программирования v8 Бесплатно (free)

Обзор некоторых аспектов использования общеизвестного инструмента 1С.

01.10.2019    42791    Yashazz    50    

О программе Postman для тестирования API и для чего она нужна 1С-нику

Практика программирования Программное обеспечение (software) v8 Бесплатно (free)

Для чего нужна программа Postman для тестирования API и какая от него польза для 1С-программиста.

24.09.2019    15518    budidich    28    

Оформление и рефакторинг сложных логических выражений Промо

Практика программирования v8 Россия Бесплатно (free)

В сложных логических выражениях нередко самому автору спустя какое-то время тяжело разобраться, не говоря уже о других программистах. Предлагаемая методика позволяет повысить наглядность таких выражений путем оформления в виде И-ИЛИ дерева и одновременно выполнять их рефакторинг.

20.09.2012    79761    tormozit    131    

[Шпаргалка] Программное создание элементов формы

Практика программирования Работа с интерфейсом v8 1cv8.cf Бесплатно (free)

Программное создание практически всех популярных элементов формы.

06.09.2019    73080    rpgshnik    70    

Агрегатные функции СКД, о которых мало кто знает

Практика программирования v8 v8::СКД 1cv8.cf Бесплатно (free)

Пользуетесь ли Вы всеми возможными агрегатными функциями, которые предоставляет система компоновки данных? Если Вы используете только: СУММА, КОЛИЧЕСТВО, МИНИМУМ, МАКСИМУМ, СРЕДНЕЕ, то эта статья для Вас.

05.09.2019    61403    ids79    55    

Регистры бухгалтерии. Общая информация

Практика программирования Математика и алгоритмы v8 v8::БУ БУ Бесплатно (free)

Общая информация о внутреннем устройстве регистров бухгалтерии.

05.09.2019    34963    YPermitin    25    

Запись значения в поле ввода/формы со срабатыванием события ПриИзменении Промо

Практика программирования v8 1cv8.cf Россия Бесплатно (free)

Иногда возникает необходимость после записи значения в какое либо поле ввода/формы вызвать для него обработчик события ПриИзменении, а о вызове самого события приходится только мечтать. В этой статье приводится программный способ вызова этого события.

11.07.2007    50687    tormozit    49    

Три костыля. Сказ про фокусы в коде

Практика программирования v8 Бесплатно (free)

Три интересных (или странных) костыля в коде, которые могут помочь в повседневных и не очень задачах.

03.09.2019    27590    YPermitin    81    

Отслеживание выполнения фонового задания

Практика программирования Универсальные функции Разработка v8 1cv8.cf Бесплатно (free)

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

17.08.2019    37977    ids79    16    

Функции СКД: ВычислитьВыражение, ВычислитьВыражениеСГруппировкойМассив

Практика программирования v8 v8::СКД 1cv8.cf Бесплатно (free)

Подробное описание и использование внутренних функций системы компоновки данных: Вычислить, ВычислитьВыражение, ВычислитьВыражениеСГруппировкойМассив, ВычислитьВыражениеСГруппировкойТаблицаЗначений.

08.08.2019    115216    ids79    69    

Как сделать из &НаКлиентеНаСервереБезКонтекста почти &НаКлиентеНаСервере Промо

Практика программирования v8 1cv8.cf Россия Бесплатно (free)

Как сделать метод формы, доступный на клиенте и на сервере одновременно, и сохранить при этом удобство разработки

10.09.2017    47543    tormozit    74    

Фоновое выполнение кода в 1С - это просто

Практика программирования v8 1cv8.cf Бесплатно (free)

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

02.08.2019    47008    avalakh    26    

Разбираемся с параметрами редактирования СКД

Практика программирования v8 v8::СКД 1cv8.cf Бесплатно (free)

Связь по типу, Параметры выбора, Связи параметров выбора

31.07.2019    31471    json    15    

СКД - наборы данных и связи между ними, создание собственной иерархии, вложенные отчеты

Практика программирования v8 v8::СКД 1cv8.cf Бесплатно (free)

Набор данных объект. Использование в схеме компоновки нескольких наборов данных. Различные варианты связи наборов: объединение, соединение. Использование иерархии в отчетах на СКД. Создание собственной иерархии, иерархия детальных записей. Использование вложенных схем в отчетах на СКД.

26.07.2019    81682    ids79    14    

Выгрузка документа по условию Промо

Практика программирования Разработка v8 Бесплатно (free)

Что делать, если документы нужно выгружать не все подряд, а по какому-то фильтру: статусу, дате, набору условий... А что если он соответствовал этим условиям, а потом перестал? А если потом опять начал? Такие ситуации заставили попотеть не одного программиста.

25.04.2019    16622    m-rv    2    

СКД - использование расширений языка запросов, секция ХАРАКТЕРИСТИКИ

Инструментарий разработчика Практика программирования v8 v8::СКД Бесплатно (free)

Автоматическое и не автоматическое заполнение полей компоновки данных. Использование расширений языка запросов для СКД «{…}», секция ВЫБРАТЬ, секция ГДЕ, параметры виртуальных таблиц. Автоматизированное использование дополнительных данных в запросе: секция ХАРАКТЕРИСТИКИ.

17.07.2019    41421    ids79    27    

Регистры сведений. За кулисами

Практика программирования Разработка v8 1cv8.cf Бесплатно (free)

Небольшие заметки по внутреннему устройству регистров сведений.

09.07.2019    29340    YPermitin    14    

"Меньше копипаста!", или как Вася универсальную процедуру писал

Практика программирования Разработка v8 v8::СКД 1cv8.cf Бесплатно (free)

Программист Вася разбирает подход создания универсальных методов на примере программного вывода СКД.

04.07.2019    20647    SeiOkami    50    

Как прикрутить ГУИД к регистру сведений Промо

Практика программирования Перенос данных из 1C8 в 1C8 Разработка v8 Бесплатно (free)

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

16.04.2019    21233    m-rv    17    

Работа с настройками системы компоновки данных

Практика программирования v8 v8::СКД 1cv8.cf Бесплатно (free)

Варианты отчетов, работа с настройками вариантов: структура группировок, поля отчета, отборы, сортировка, условное оформление, другие настройки, настройки отображения диаграмм.

02.07.2019    63909    ids79    17    

Создание отчетов с помощью СКД - основные понятия и элементы

Практика программирования Математика и алгоритмы v8 v8::СКД Бесплатно (free)

Основные принципы работы СКД. Понятия схемы компоновки и макета компоновки. Описание основных элементов схемы компоновки: наборы данных, поля, вычисляемые поля, ресурсы, параметры.

25.06.2019    63105    ids79    26    

Многопоточное ускорение однопользовательских нагрузок в 1С + Microsoft SQL Server 2017

Практика программирования Производительность и оптимизация (HighLoad) v8 v8::Запросы Бесплатно (free)

Взаимодействие с Microsoft SQL Server нередко вызывает трудности у 1С-ников, а потому интересны любые моменты, связанные с его использованием. О своем опыте работы с новым SQL Server 2017 участникам конференции Infostart-2018 рассказал директор ООО «Аналитика софт» Дмитрий Дудин.

11.06.2019    27778    dmurk    146    

Как сделать запрос на изменение данных Промо

Практика программирования v8 v8::Запросы 1cv8.cf Бесплатно (free)

В статье приведены особенности внутренней архитектуры и примеры работы с расширением языка запросов 1С.

01.06.2018    33031    m-rv    22    

Регистры накопления. Виртуальные таблицы. Часть №2: "Остатки" и "Остатки и обороты"

Практика программирования v8 1cv8.cf Бесплатно (free)

Описание работы платформы 1С:Предприятие 8.2 с виртуальными таблицами регистров накопления "Остатки" и "Остатки и обороты". Анализ SQL-запрос при работе с виртуальными таблицами

22.05.2019    34203    YPermitin    7    

Регистры накопления. Структура хранения в базе данных

Практика программирования Разработка v8 1cv8.cf Бесплатно (free)

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

16.05.2019    52000    YPermitin    30    

О расширениях замолвите слово...

Практика программирования Разработка v8 Бесплатно (free)

О чём стоит задуматься при принятии решения о создании расширения конфигурации…

07.04.2019    38836    ellavs    127    

Метод формирования движений в типовых регистрах нетиповыми регистраторами Промо

Практика программирования v8 1cv8.cf Бесплатно (free)

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

05.12.2017    29028    itriot11    34    

Git-репозитории для 1С-кода (опыт использования при небольших проектах)

Практика программирования v8 Бесплатно (free)

Инструкции по взаимодействию с Git-репозиторием, которые писались для тех наших программистов, которые вообще никогда не работали с Git (руководства в духе "Как получить код из git-репозитория?", "Как отправить код в git-репозиторий")...

28.03.2019    29039    ellavs    90    

Трюки с внешними источниками данных

Практика программирования Разработка v8 1cv8.cf Бесплатно (free)

Некоторые трюки для преодоления ограничений внешних источников данных.

14.03.2019    35676    YPermitin    53    

Ошибки при работе с хранилищем конфигурации и способы их решения

Практика программирования v8 Бесплатно (free)

В статье собраны наиболее распространенные ошибки при работе с хранилищем конфигурации и способы их обхода и решения.

01.03.2019    51978    Смешной 1С    31    

Использование классов .Net в 1С для новичков Промо

Практика программирования Разработка внешних компонент Универсальные функции v7.7 v8 Бесплатно (free)

Руководство для новичков. Написав статью http://infostart.ru/public/238584/, я понял, что многие не понимают того, что написано. Поэтому в этой статье постараюсь более подробно остановиться на азах и без кода на вражеском языке (C#)

27.01.2016    79107    Serginio    113    

Разработка и сценарное тестирование с Vanessa-ADD. Отчетность Allure. Автоматизация запуска сценариев

Практика программирования Vanessa Automation v8 Россия Бесплатно (free)

Формируем отчетность о результатах выполнения сценариев. Автоматизируем запуск.

26.02.2019    24983    Vladimir Litvinenko    28    

Автоматические и управляемые блокировки применительно к типовым конфигурациям 1С Промо

Математика и алгоритмы Практика программирования v8 v8::blocking 1cv8.cf Бесплатно (free)

Основные принципы работы с режимами автоматических и управляемых блокировок в 1С Предприятие 8. Теория и применение в типовых конфигурациях: БП, УТ, ЕРП

10.11.2018    38688    ids79    40