Сегодня, в последний рабочий день недели, практически весь день провозился над передачей данных из Delphi в Word. Так как подозрение есть, что работа продолжится то решил кое-какие моменты по работе с Microsoft Word в Delphi запечатлеть и у себя в блоге. Написать такую мини-шпаргалку (тем более, что по Excel уже кое что есть).
Для начала, немного общих моментов по работе с MS Office в Delphi. И первое, что мы сделаем - это создадим объект Word.Application. Создается этот объект абсолютно также, как и объект Excel.Application:
uses ComObj; var Word: variant; [...] procedure CreateWord(const Visible: boolean); begin Word:=CreateOleObject('Word.Application'); Word.Visible:=Visible; end;
Всё достаточно просто. Далее мы можем работать с объектом следующим образом:
- Создавать документ Word с нуля
- Открыть уже существующий документ и изменить в нем текст для получения необходимой формы документа.
Рассмотрим оба варианта, т.к. оба они имеют как свои плюсы, так и недостатки.
1. Создание документа Microsoft Word в Delphi с нуля.
Чтобы создать новый документ необходимо выполнить метод Add у коллекции Documents, т.е.:
[...] Word.Documents.Add [...]
и после этой операции уже начинать работать с докуменам обращаясь к нему по индексу или имени в коллекции. Также, можно создать новый документ по шаблону (*.dot). Для этого необходимо выполнить тот же метод Add, но с одним входным параметром - путем к файлу-шаблону:
[...] Word.Documents.Add(TamplatePath:string); [...]
Чтобы получить список всех открытых в данный момент документов Word можно воспользоваться следующим листингом:
[...] var List: TStringList; i: integer; begin List:=TStringList.Create; for i:=1 to Word.Documents.Count do List.Add(Word.Documents.Item(i).Name); end; [...]
Обатите внимание, что нумерация начинается с 1, а не с нуля. Чтобы активировать любой документ из коллекции для работы, необходимо выполнить метод Activate:
Word.Documents.Item(index).Activate
где index - номер документа в коллекции.
Теперь можно приступать к записи и чтению документа. Для работы с текстов в документе Word, как и в Excel для работы с ячейками таблицы, определен обект Range. Именно методы этого объекта и дают нам возможность работы с текстом. Для начала рассмотрим работу двух основных методов: InsertBefore и InsertAfter.
Как следует из название - первый метод вставляет текст в начало содержимого Range, а второй - в конец. При этом сам объект Range может содержать как весть документ (Document) так и какую-либо его часть. Например, в следующем листинге я вставлю строку в начало документа и затем методом InsertAfter буду добавлять несколько строк текста в конец документа:
[...] Word.ActiveDocument.Range.InsertBefore('Hello World'); Word.ActiveDocument.Range.InsertAfter('текст после Hello World'); Word.ActiveDocument.Range.InsertAfter('окончание строки в окумента'); [...]
При выполнении этих трех операции Range содержал весь документ.
Если работать со всем документом неудобно, а необходимо, например выделить фрагмент с 50 по 100 символ и работать с ним, то можно воспользоваться функцией Range, которая вернет нам необходимый объект Range:
var MyRange: variant; begin MyRange:=WordActiveDocument.Range(50,100); MyRange.InsertBefore('Привет');//всё, что было после 50го символа сдвинулось вправо end;
Это что касается записи текста. Решение обратной задачи - чтения текста из документа ещё проще. Достаточновоспользоваться свойством Text у объекта Range:
[...] ShowMessage(Word.ActiveDocument.Range.Text) //весь текст в документе [...]
Также для чтениядокумента можно воспользоваться колеекцией документа Words (слова). За слово принимается непрерывный набор символов - цифр и букв, который оканчивается пробелом.
Перечисляются слова документа точно также как и при работе с коллекцией документов, т.е. первое слово имеет индекс 1 последнее - Word.Count.
[...] ShowMessage(Word.ActiveDocument.Words.Item(Word.ActiveDocument.Words.Count).Text) [...]
В данном случае я вывел на экран последнее слово в документе.
Очевидно, что приведенный выше способ работы с документам хорош в случае, когда требуется создать относительно простой документ Word и не требуется лишний раз рассчитывать фрагменты текста, правильно вставлять таблицы и т.д. Если же необходимо работать с документами, которые имеют сложное содержание, например текст в перемешку м рисунками, таблицами, а сам текст выводится различными шрифтами, то, на мой взгляд наиболее удобно использовать второй спосо работы с Word в Delphi - просто заменить текст в уже заранее заготовленном документа.
2. Работа с документами Word в Delphi. Открытие готового документа и замена текста.
Чтобы открыть заранее заготовленный документ Word в Delphi достаточно воспользоваться методом Open у коллекции Documents, например так:
var FilePath: string; [...] Word.Documents.Open(FilePath) [...]
Метод Open можно вызывать с несколькими аргументами:
FileName: string - путь и имя файла;
ConfirmConversions: boolean - False - не открывать диалоговое окно "Преобразование файла" при откытии файла, формат которого не соответствует формату Word (doc или docx)
ReadOnly:boolean - True - открыть документ в режиме "Только для чтения"
AddToRecentFiles: boolean - True, чтобы добавить документ в список недавно открытых документов.
PasswordDocument: string - пароль для открытия документа
PasswordTemplate: string - пароль для открытия шаблона
Revert : boolean - True, чтобы вернуться к сохраненному документу, если этот документ открывается повторно.
WritePasswordDocument: string - пароль для сохранения измененного документа в файле
WritePasswordTemplate:string - пароль для сохранения изменений в шаблоне
Format:integer - формат открываемого документа.
Обязательным параметром метода Open является только FileName, остальные - могут отсутствовать. Если же Вам необходимо воспользоваться несколькими параметрами, то их необходимо явно указывать при вызове метода, например:
[...] Word.Documents.Open(FileName:=FilePath, ReadOnly:=true) [...]
В этом случае документ открывается в режиме "Только для чтения". При таком способе вызова (с явным указанием аргументов) положение аргументов может быть произвольным.
Что касается последнего аргумента - Format, то он может принимать целочисленные значения (применительно к версиям Microsoft Word 2007 и выше) от 0 до 13. При этом, для того, чтобы открыть "родные" вордовские документы (doc) достаточно использовать значения 0 или 6.
Теперь, когда документ открыт его необходимо преобразовать. Обчыно я делаю следующим образом: в тех местах документа, в которые необходимо вставить текст я расставляю либо закладки, либо простые строки текста, например, обрамленные символом $ или #. И затем просто выполняю поиск и замену подстрок следующим образом:
function FindAndReplace(const FindText,ReplaceText:string):boolean; const wdReplaceAll = 2; begin Word.Selection.Find.MatchSoundsLike := False; Word.Selection.Find.MatchAllWordForms := False; Word.Selection.Find.MatchWholeWord := False; Word.Selection.Find.Format := False; Word.Selection.Find.Forward := True; Word.Selection.Find.ClearFormatting; Word.Selection.Find.Text:=FindText; Word.Selection.Find.Replacement.Text:=ReplaceText; FindAndReplace:=Word.Selection.Find.Execute(Replace:=wdReplaceAll); end;
Приведенная выше функция позволяет провести поиск и замену текстового фрагмента во всём документе. Для того, чтобы ограничить возможности пользователя при работе с шаблоном документа я обычно ставлю на необработанный файл пароль, а после обработки - паротль снимаю и сохраняю документ с другим названием в необходимую директорию.
Вот, наверное, самые-самые простые методы работы с Word в Delphi. Кстати, пишу пост и, думаю, что у кого-то из читателей может возникнуть вопрос: причём тут Delphi в Internet и Word в Delphi? :) Честно говоря, приведенныый выше фрагменты кода можно использовать для нужд в Internet с натяжкой, например, при автосоставлении небольших отчётов по чему-либо. А вобще, в недалеком будущем, есть в планах поразбираться с Тезаурусом Word и попробовать составить небольшой синонимайзер для собственных нужд - он-то и пригодится нам в Internet :)
Надоели волосы, торчащие из всех частей тела? Не проблема - лазерная эпиляция поможет Вам навсегда избавится от волосяного покрова в любом месте тела :)
----------------------
| Делись! | Загружай! | Плюсуй! |
| | |









27 Фев 2010 в 11:50 пп
Спасибо, попробую сегодня. А для чего тебе вообще из программы в Word пересылку делать? Отчеты что ли там формируют? Просто для этого вроде более удобные способы есть. Хотя заказчикам все подряд нужно. :-)
28 Фев 2010 в 12:51 дп
А не проще ли использовать юниты с ранним связываеним.
Например word2000.pas,wordxp.pas и т.п.
Все продукты офиса имеют обратную совместимость, т.е. word2000.pas отлично отработает на msword2007.
У них есть только 1 недостаток — почему-то параметры нужно передавать через var, а это затрудняет использование констант, зато в результате мы сразу можем пользоваться всеми прелестями синтаксис-помощника
28 Фев 2010 в 9:23 дп
DimaBy, Низнаю, может и проще, но мне превычнее работать сразу с OLE-объектом…да и интереснее :)
Алексей, там не столько отчёт, сколько пояснительная записка формируется по расчётам. Мог бы и FastReport использовать или чего-нибудь наподобие, но с Вордом как-то «роднее» :)
28 Фев 2010 в 9:47 пп
Еще можно было бы упомянуть о такой маленькой хитрости, как макросы. Когда мы не знаем нужных нам команд для работы с Excel или Word — открываем документ, делаем запись макроса и смотрим его исходники. Код на Visual Basic практически не будет отличаться от того, который нам нужен в Delphi.
28 Фев 2010 в 11:34 пп
Да как бы тут и макросов не надо особо — есть msdn и справка по объектной модели. Я обычно этими истониками и пользуюсь при разработках программ. Пробовал как-то с макросами возиться — не понравилось :)
01 Мар 2010 в 3:33 пп
Интересует формирование отчётов не через OLE в ворд, а через создание XML документа, который ворд откроет.
01 Мар 2010 в 3:37 пп
Меня тоже интересует :) Попробую чего-нибудь написать по тому поводу
02 Мар 2010 в 9:58 пп
Использовать в серьезных проектах привязку к Word не правильно.
Как системный администратор я перевел целое предприятие на лицензионный софт. Word был куплен только для секретаря. У остальных, в том числе и у бухгалтерии, был поставлен OpenOffice.org, на всякий случай. Когда выяснилось, что одна из бухгалтерских программ требует для своей печати Microsoft Office, то пришлось воспользоваться менее качественной, но более самостоятельной программой. К первоначальному варианту мы вернулись лишь тогда, когда программа научилась печатать генерируя PDF-файлы.
Если задача нашей программы лишь красиво напечатать, то пусть генерирует PDF.
А если нужна возможность редактирования, то пусть работает через OpenOffice. Благо, что библиотека для этого имеется http://yuri.elmeh.ru, а чего не хватает можно найти на форуме http://www.sql.ru/forum/actualthread.aspx?bid=20&tid=405083&pg=20 Правда, такой подход многим не нравиться, но убедить людей пользоваться OppenOffice не так уж и сложно, даже в дополнение к Word.
Другими словами, серьёзная программа может быть привязана лишь к тем программам, установка которых не вызовет финансовых затрат и других проблем мирового значения.
02 Мар 2010 в 10:38 пп
Согласен с вами, Наиль. И всегда стараюсь как раз минимизировать лишние затраты при разработке программ. Убедить человека можно, особенно, когда в руках есть «убеждалка» в виде прайс-листа :) Но могу если сам по себе заказчик программы никак не зависит от закупки софта — убедить практически нереально. Простой пример — университет. В универе все закупки софа проходят централизовано, и отдельно взятой кафедре по барабану сколько чего стоит — она просто регулярно отчисляет в фонд универа фиксированный процент с дохода и всегда имеет свежий софт и никому не важно надо кафедре этот софт или нет — всучили балванку и иди устанавливай. Кафедре требуется нестандартная программка, например, генерирующая списки студентов по определенным признакам (не обязательно половым) и должна формировать документ, скажем для секретаря кафедры, учебных мастеров и т.д., чтоб они его дальше перерабатывали, вносили чего-нибудь и т.д.. Как думаете какое первое требование в этом случае? отчет в файле Word/Excel. И только заикнись по Оо — задушат :).
З.Ы. За ссылку на библиотеку — спасибо огроменное, т.к. параллельно как раз в Лазарусе пытаюсь подружиться с оО — может часть библиотеки и пригодиться как раз
04 Мар 2010 в 6:27 пп
Очень интересный подход, а я в дельфи так и не смог этого сделать
12 мая 2010 в 10:11 дп
Здравствуйте. Подскажите, пожалуйста, как подавить диалоговое окно на сохранение документа? Пол дня уже не могу сделать.
12 мая 2010 в 10:26 дп
Про которое окно идет речь? Если про то, что выскакивает, когда Вы пытаетесь закрыть Ворд из своей программы, то при создании объекта надо написать так:
var Word: OLEVariantbegin
[...]//создаем объект
Word.DisplayAlerts:=wdAlertsNone
end;
DisplayAlerts может принимать одно из следующих значений:
wdAlertsAll -1
wdAlertsMessageBox -2
wdAlertsNone 0
12 мая 2010 в 8:20 пп
Подскажите, как вставить таблицу в Word программно, не нарисовать таблицу, а именно вставить. Я выделяю весь текст и мне нужно на него «надеть» таблицу. Через меню управления в Worde, это делается так: Таблица — Вставить — Таблица, а как это сделать программно? Заранее спасибо.
12 мая 2010 в 8:22 пп
Вот привожу листинг из макроса, для вставки таблицы, то ничего не понятно.
Selection.WholeStory
Selection.ConvertToTable Separator:=wdSeparateByParagraphs, NumColumns:=1, _
NumRows:=8, AutoFitBehavior:=wdAutoFitFixed
With Selection.Tables(1)
If .Style «Сетка таблицы» Then
.Style = «Сетка таблицы»
End If
.ApplyStyleHeadingRows = True
.ApplyStyleLastRow = True
.ApplyStyleFirstColumn = True
.ApplyStyleLastColumn = True
End With
End Sub
03 Авг 2010 в 5:21 пп
Спасибо, через компоннеты не помогло, а тут все так просто)
12 Авг 2010 в 12:03 пп
Подскажите пожалуйста кто нить, как можно установить курсор в Ворде в заданную позицию? Т.е. я вставляю из шаблона в новый документ небольшую табличку и рядом(именно рядом) мне надо вставить еще одну, но после первой вставки курсор встает вниз таблицы и, соответсвенно, следующая табличка помещается ниже :(…Всем заранее спасибо
30 Авг 2010 в 12:27 пп
А как программно закрыть новую копию Word’а, запущенного таким образом?
30 Авг 2010 в 1:26 пп
srg91,
Word.Quit;UnAssigned(Word)
30 Авг 2010 в 3:15 пп
Спасибо
18 Окт 2010 в 10:06 пп
Подскажите, как можно открыть DOC-файл в Delphi приложении?
Компонент нужен какой-то для этого?
Я использую RxRichEdit для открытия RTF-файлов с картинками, но ссылки почему-то из http://www.webdelphi.ru превращаются в <http://www.webdelphi.ru>, с е-мейлами еще хуже… :(
19 Окт 2010 в 2:18 дп
В Delphi-приложении вроде бы никак. Или я просто не встречал программ, способных такое сделать.
19 Окт 2010 в 10:21 дп
Понял, спасибо.
Еще вопрос есть.
RichEdit и RxRichEdit как-то странно ссылки в тексте отображают.
В открываемом RTF ссылки нормальные:
например:
http://www.webdelphi.ru
delphi@yandex.ru
а когда открываю RTF в своей программке, ссылки имеют такой вид:
<http://www.webdelphi.ru>
delphi@yandex.ru <mailto:delphi@yandex.ru>
Почему так? И можно ли привести их в нормальный вид?
28 Окт 2010 в 12:49 пп
Подскажите пожалуйтса.
У меня в программе нужно открыть Word на определенной закладке.
Когда работал в Delphi 7 я это сделал с помощью Ole,
Перешел на 2010 и не могу это сделать. И вообще нет компонентов с Word.
Подскажите плиз!
28 Окт 2010 в 6:41 пп
Как это нет компонентов с Word? Есть. Просто их надо импортировать через «Components — Import Component — Type Library».
19 Ноя 2010 в 12:22 дп
to Vlad
слушай подсади нубу как в ворде через делфи вставить ТАБ
такая команда не работает, а точнее компилятор не пропускает, команду взял из макроса:
var
word_stud:Variant;<cite></cite>
<cite>word_stud.Selection.TypeText Text:=vbTab;</cite>
За ранее спасибо!
11 Мар 2011 в 5:58 дп
подскажите пожалуйста:
мне необходимо записать из поля edit информацию в word при том, чтобы word он не открывался.
спасибо
15 Мар 2011 в 4:35 пп
можно просто не показывать видимость документа:
w.visible:=false;
16 Мар 2011 в 9:47 пп
Word.Visible = false
где Word — объект MS Word
28 мая 2011 в 3:18 пп
Подскажите как вообще мне вставить в документ word значение из программы, вот так пишет «Ошибка на сервере»
MSWord.Selection.TypeText(znach1,’Текст’);
MSWord.Selection.TypeText(‘Текст’);
а вот так все нормально записывает…
16 Июн 2011 в 8:55 пп
В один документ надо вставить с определенной позиции весь текст другого документа. Как это сделать? Пишет слишком длинная строка.
05 Сен 2011 в 6:56 пп
НЕ подскажете можно ли из дельфи вставить и редактировать формулы в Word Т.е. работа с редактором формул. Или это не реально?
05 Сен 2011 в 7:03 пп
Через OLE-контейнеры вроде бы можно было, но сам никогда над такими вещами не работал
16 Сен 2011 в 3:29 пп
Понятно. Спасибо за отклик. Придется тогда шаблон использовать. А хотелось конечно все программно сделать
18 Сен 2011 в 11:45 пп
Подскажите, как можно создать базу данных, состоящую из документов word в delphi?
19 Сен 2011 в 3:42 пп
Ну видимо можно, если только все документы будут хранится в blob’ах…только зачем?
20 Сен 2011 в 2:04 дп
преподаватель задал вот такую задачку)
27 Окт 2011 в 1:57 дп
Помогите, не могу создать путь чтобы открыть документ
27 Окт 2011 в 1:59 дп
Word.Documents.Open(D:\Âñå äëÿ Äèïëîì\äàííûå äëÿ ñïðàâî÷íèêà.docx:=FilePath, ReadOnly:=true) Что тут не так?????????
27 Окт 2011 в 2:47 дп
Серега, всё не так. Во-первых почему первый параметр задом наперед стоит? Во-вторых, почему в пути к файлу кодировка сбита?
24 Ноя 2011 в 11:21 пп
нахожу в документе нужное слово с помощью метода FIND объекта SELECTION. Как теперь перед найденным словом перевести каретку (аналогично нажатию клавиши ENTER)?
И ещё, как после нахождения искомого слова выделить следующий за ним фрагмент текста?
Заранее благодраю!
25 Ноя 2011 в 3:01 дп
Антон, каретка всегда и везде переводится одинаково — двумя символами — #10#13. Для выделения следующего слова смотрите методы и свойства объекта Words…по-моему так называлась коллекция, содержащая слова документа.
26 Ноя 2011 в 12:43 дп
Спасибо!! Однако в инете никак не могу найти как работать с коллекцией Words (свойства, методы). Смотрел в книге Василия Корнякова «Программирование приложений под Office…», но там тоже ни слухом ни духом. А между тем, вопрос выделения текста за найденным куском по методу Find остается открытым. В принципе, если знать координаты положения курсора, то можно использовать свойства W.Selection.Start и W.Selection.Start. Возможно есть более простой способ, не знаю…
А возникла такая задача при написании проги, которая сканирует документ в поисках флага ‘[#’, а затем считывает временный номер, стоящий сразу за ним.
Я пока у истоков автоматизации процессов обработки документов, так сказать ещё не волшебник, а только учусь. Может подскажите более менее стоящий источник или ряд источников для лик.беза?
26 Ноя 2011 в 11:14 пп
Спасибо! Я только только начал заниматься вопросами автоматизации обработки документов и сразу же встретился с массой трудностей. В инете ничего конкретного. Я был бы вам признателен, если бы вы подсказали мне какой-нибудь ресурс или ссылку на источник, где более или менее освещен данный вопрос (к слову, известная многим книга В.Корнякова мне не очень помогла).
27 Ноя 2011 в 6:13 пп
Антон, может покажется странным, но САМЫЙ стоящий источник по данной теме — это MSDN.com.. Ну нет ничего более побробного, кроме MSDN — это ИХ разработка, ИХ документация, ИХ пордукт. А Корняков просто показал КАК использовать правильно справку MSDN и с какой стороны её надо читать. Ну, а чтобы не теряться в догадках «а как сделать….?» первое, что необходимо для нормальной работы — это 1 раз сесть и уделить время на изучение вопроса использования OLE и понять, что такое раннее связывание, что такое позднее связывание, чем они отличаются. Поймете — напишите любую программу для автоматизации, не поймете — никакой эксперт вам не поможет =) Вы поймите, что нельзя написать что-либо стОящее, не поняв основы работы. Понятно, что может у вас время поджимает, заказчик торопит, но забейте вы на спешку 1 (один) раз и почитайте того же Корнякова С НАЧАЛА и до конца он ведь довольно толково расписывает там что такое контроллер автоматизации, какие принципы разработки применять и т.д.