Доброго времени суток! Я бы хотел поднять скорее идейный вопрос: Как правильно заполнять шаблон Word? Я знаю как минимум 5 способов заполнения Word шаблона, и все 4 имеют свои недостатки, пятый же настолько ужасен, что я его даже приводить не буду. Но крови он мне попил изрядно, т.к. приходится работать с чужим кодом. И так, давайте я перечислю то что знаю и плюсы и минусы этих подходов, а вы может быть подкините ещё способов для размышления, а может быть даже посоветуете единственно верный! Думаю тема будет многим полезна. Описываю всё по русской версии Word.
1. DocVariable Можно вставлять в шаблон поля с типом DocVariable, давать им имена, а потом в коде обращаться к ним примерно так:
В конце надо обязательно вызвать WordDoc.Fields.Update(); Плюсы: можно включить или выключить (Alt+F9) отображение этих переменных в шаблоне. Имена переменных видны прямо в шаблоне. Можно в разные места вставлять одну и ту же переменную. Минусы: если вдруг по какой-причине вы не присвоили в коде значение такой переменной, то в результате в документе на месте переменной будет красоваться такая ошибка: «Ошибка! Переменная документа не указана.»
2-3 FormText или Bookmarks Эти 2 способа я объединю, т.к. они по сути одинаковы и второй полностью перекрывает третий. Второй и опишу. В шаблон вставляется Поле FORMTEXT, ему присваивается Закладка, по которой мы и будет обращаться к полю в коде. Примерно так:
Ну и тоже самое с закладками, т.е. можно вставить в документ Закладку и почти так же к ней обращаться, только закладки не видны в Шаблоне в отличии от FormText, что не очень удобно. Плюсы: в Шаблоне видны места вставок их отображение можно включать и отключать (Alt+F9). Если в коде мы ей ничего не присваиваем, ничего не происходит. Минусы: что бы увидеть имя Закладки, нужно лезть в свойства Поля. Одно и тоже Поле (т.е. с одинаковой Закладкой) нельзя использовать в разных местах.
4. Replace Text Можно из кода воссоздать вызов всем знакомой функции «Найти и заменить». В коде это всё выглядит немного громоздко, благо один раз метод написали и забыли. Но суть следующая. В Word вставляются текстовые «метки», т.е. такие сочетания, которые вы будете искать в коде и заменять. Кто-то используется для меток угловые скобки, кто-то фигурные. Не суть, главное что бы метки уникальной выделялись из текста. Т.е. вы можете вставить в документ такую метку , а в коде искать текст «» и заменять на то, что вам надо. Плюсы: в Шаблоне явно видны как сами метки, так их имена. Можно использовать одну и ту же метку в разных местах. Если вы из кода попытаете заменить не существующую метку, ничего не произойдёт. В предыдущих случаях этот момент идёт в минус, т.к. попытка обратиться к не существующему полю вызовет ошибку, но минус так себе, поэтому я его там и не указал. Минусы: если в коде вы по какой-то причине пропустили какую либо метку, она очень не красиво будет смотреться в результирующем документе. Сам подход архитектурно кривоват, т.е. какие-то сепец. символы для выделения меток, да и после замены какой-либо метки вы уже ничего не можете с ней сделать в Шаблоне, что тоже не очень хорошо.
А какой способ используете вы и почему? Может быть я не правильно использую какой-либо из вышеперечисленных способов и можно исключить перечисленные в нём минусы? Я лично пользуюсь первым способом, т.к. его единственный минус наиболее безобидный на мой взгляд.
Ошибка переменная документа не указана
Давайте еще раз, правильная последовательность действий: Открываем на редактирование стандартный (работающий) шаблон, удаляем из него все лишнее, вставляем переменные (кстати удобно копировать переменную и менять ее название), сохраняем в виде шаблона (.dot), загружаем в администраторе. Копируем «переменную» из похожего отчета, заменяем нужные нам селекты и переменные. Все должно работать.
. Может вы новый шаблон (с макросами) в босс не загрузили?
Столкнулась с проблемой при заполнении документа .dot. Может кто-нибудь знает, как ее обойти? Подскажите, пожалуйста.
В word передаю значения переменных (коды полей DocVariable). На месте тех переменных, которым ничего не было передано (0-ые значения) пишет «Ошибка! Переменная документа не указана.» При этом смотрю аналогичные шаблоны: в такой же ситуации поле остается просто незаполненным, без этой надписи об ошибке. Логично, что отличие где-то в настройках Word.
Читайте выше по тексту: wordApp.Run(«DocVarUpdate»);
В вашем случае просто видимо либо в dot нету макроса, либо он не запускается при формировании документа.
Текст макроса там примерно такой: . Dim fld as Fields for each fld in activedocument.fields x = fld.update if not x then fld.delete next . Собственно макрос вам просто эти «пустые» переменные и удалит после формирования текста документа.
ЗЫ: Еще проще в макросе сделать: ActiveDocument.fields.unlink
Вернуться к началу
Часовой пояс: GMT + 4
Страница 1 из 1
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете голосовать в опросах
Язык программирования самого высокого уровня содержит всего несколько команд для управления программистами
15 мар. 2010 г.
Использование полей и закладок при работе с MS Word из Delphi
В предыдущей заметке «Поиск и замена текста в документе MS Word из Delphi» я рассказывал, как дорабатывал старый модуль, который генерирует клиентам компании письма в формате MS Word с помощью поиска и замены текста. Сдав модуль заказчикам, я в свободное от работы время, переделал его. Вместо поиска и замены использовал поля с переменными (DocVariable). В шаблон письма с помощью макроса добавил переменные
Sub AddFields() ThisDocument.Variables.Add «FIO», «FIO» ThisDocument.Variables.Add «ADDRESS», «ADDRESS» . End Sub
и расставил поля по тексту шаблона. В макросе у метода Add первый параметр – название переменной, а второй – ее значение. Я специально сделал их одинаковыми, чтобы пользователям было проще и нагляднее редактировать шаблоны. Затем внес изменения в методы модуля работающие с MS Word. Если опустить все детали и различную логику, то упрощенно работа с MS Word выглядит так:
Var wa: WordApplication; ovDotName, ovFileName: OleVariant; i: Integer; q: TSDQuery; . begin . wa := CreateComObject(CLASS_WordApplication) as _Application; ovDotName := ‘какой то шаблон.dot’; wa.Documents.Add(ovDotName, EmptyParam, EmptyParam, EmptyParam);
For i := 0 to q.FieldCount-1 do MSWordSetVariable(q.Fields[i].FieldName, q.Fields[i].AsString); . ovFileName := ‘письмо любимому клиенту.doc’; wa.ActiveDocument.SaveAs(ovFileName, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam); .
Вот такая логика у индусов, писавших этот кусок MS Word.
После присвоения значений всем переменным, осталось только дать команду полям обновиться новыми значениями переменных. Для этого в VBA у коллекции объектов полей (Fields) есть метод Update:
А для того, чтобы избежать дальнейшего обновления полей, избавимся от их связи с переменными:
У каждого структурного элемента документа (заметки, колонтитула, сноски и т.д.) своя коллекция объектов полей, поэтому, если документ, как у меня, состоит из разных структурных элементов, то методы Update и Unlink необходимо вызвать для каждого из этих элементов. Для этого перебираем все элементы коллекции StoryRanges.
procedure MSWordUpdateStoryRanges; Var StoryRanges: Word2000.StoryRanges; StoryRange: Word2000.Range; iStoryIndex: integer; Begin StoryRanges := wa.ActiveDocument.StoryRanges; For iStoryIndex := wdMainTextStory to wdFirstPageFooterStory do Try StoryRange := StoryRanges.Item(iStoryIndex); If StoryRange <> nil then begin StoryRange.Fields.Update; StoryRange.Fields.Unlink;
While (StoryRange.NextStoryRange <> nil) do begin StoryRange := StoryRange.NextStoryRange; StoryRange.Fields.Update; StoryRange.Fields.Unlink; end; end; Except StoryRange := nil; End; End;
И вызываю ее перед сохранением документа.
Все бы ничего, но часть текста передаваемого из программы в MS Word необходимо было выводить жирным шрифтом. А это через переменные не сделать 🙁 В подобном случае «поиск и замену текста» можно заменить на «переход к закладке и вывод текста». Например, в шаблон вставляем закладку с именем ‘писать текст сюда’, а в программе пишем:
Вот и все 🙂 Раннее связывание и использование полей/закладок дало существенный рост скорости генерации писем. Если на 500-х различных документах этого было почти не заметно, то при генерации 15 000 документов, прирост скорости составил 30% (специально проверил несколько раз на одних и тех же исходных данных).