© Терехов А В. 2003
Как быть? Вот тут-то и приходит на помощь Microsoft Word Visial Basic.
var Word: Variant; begin Word := CreateOleObject('Word.Basic'); Word.FileNew('Normal'); Word.Insert('This is the first line'#13); Word.Insert('This is the second line'#13); Word.FileSaveAs('c:\temp\test.txt', 3); end;Затем в MS Word появился Visial Basic. Этот язык является объектно-ориентированным, т.е. отличается от WordBasic'а также как Delphi отличается от Pascal'я.
Объект Application является одним из ключевых объектов MS Word Visial Basic'а. Для нашей задачи именно этот объект
подходит наиболее всего. Вот им и займемся.
Чтобы начать работать с Word.Application первым делом надо получить к нему
доступ. Для этого воспользуемся функцией
CreateOleObject.
Создание объекта Word.Application - это первый шаг.
Так как мы планируем использовать документы Word'а в качестве шаблонов,
то нам надо получить доступ к дочернему объекту Word.Application.Documents, который,
так сказать, и будет управлять всем процессом.
Но прежде, чем пытаться получить к нему доступ, надо или создать новый документ или открыть
существующий.
WordApp.Documents.Open('название_документа'); - открыть документ
WordApp.Documents.Add; - создать документ
Метод Add имеет два параметра по управлению файлом шаблонов MS Word, но мы их рассматривать не станем.
Три способа получения доступа к дочерним объектам Documents на примере объекта Tables (таблицы).
Почему таблицы? Потому что для создания шаблонов отчетов использование таблиц - наиудобнейшее
решение. Расставил в нужных местах страницы таблицы и обращайся к их ячейкам по номеру таблицы,
номеру строки и номеру столбца - очень удобно.
Способ первый.
Обращаемся к объектам активного документа через свойство Word.Application ActiveDocument:
WordApp.ActiveDocument.Tables - обращаемся к объекту "Таблицы" активного документаСпособ второй.
WordApp.Documents.Item(1).Tables - обращаемся к объекту "Таблицы" выбранного документаЗдесь надо иметь ввиду две особенности.
WordApp.Document.Item(1).Activate; - даст ошибку, надо писать: WordApp.Documents.Item(1).Activate;2. В файле справке указано, что к объектам можно обращаться по номеру. Например, к третьему документу объекта Application можно обращаться Documents(3).
2. Создано два документа
Документ1 - номер 2
Документ2 - номер 1
3. Создано три документа
Документ1 - номер 3
Документ2 - номер 2
Документ3 - номер 1
Способ третий.
Var WordTables:OleVariant; Begin WordTables:=WordApp.ActiveDocument.Tables; WordTables.Item(2).Cell(1,2).Range:='Hi Word!'; End;Еще один способ.
Var WordDoc:OleVariant; WordTables:OleVariant; Begin WordDoc:=CreateOleObject('Word.Document'); WordTables:=WordDoc.Tables; End;В этом случае в уже загруженном Word откроется новый документ. Если к моменту создания WordDoc из приведенного выше примера MS Word загружен не был, то обратившись к свойству WordDoc.Application, можно самому подгрузить экземпляр MS Word:
WordDoc.Application.Visible:=True;
Итак центрируем:
Const wdAlignVerticalTop = $00000000; wdAlignVerticalCenter = $00000001; wdAlignVerticalJustify = $00000002; wdAlignVerticalBottom = $00000003; Var WordTables:OleVariant; Begin WordTables:=WordApp.ActiveDocument.Tables; WordTables.Item(1).Cell(1,2).VerticalAlignment:=wdAlignVerticalCenter; WordTables.Item(1).Cell(1,2).Range:='центрирование по вертикали'; End;Продолжаем изучать справку.
This example creates a 3x3 table in a new document and assigns a sequential cell number to each cell in the table. The example then sets the height of the first row to 20 points and vertically aligns the text at the top of the cells. Set newDoc = Documents.Add Set myTable = newDoc.Tables.Add(Selection.Range, 3, 3) i = 1 For Each c In myTable.Range.Cells c.Range.InsertAfter "Cell " & i i = i + 1 Next With myTable.Rows(1) .Height = 20 .Cells.VerticalAlignment = wdAlignVerticalTop End WithВ этом примере в новом документе создается таблица 3х3 (экземпляр MS Word уже должен быть запущен), затем в каждой ячейке пишется ее номер. Затем устанавливается высота первой строки в 20 точек и устанавливается центрирование текста по верхнему краю ячейки.
Прежде чем запускать этот пример надо включить MS Word. Хотя MS Word можно включить и позже :)
(Example1) procedure TForm1.Button1Click(Sender: TObject); Const wdAlignVerticalTop = $00000000; wdAlignVerticalCenter = $00000001; wdAlignVerticalJustify = $00000002; wdAlignVerticalBottom = $00000003; Var WordDocument:OleVariant; WordTable:OleVariant; N:Integer; CellCount:Integer; C:OleVariant; begin //создадим объект Document WordDocument:=CreateOleObject('Word.Document'); //получим ссылку на объект Tables WordTable:=WordDocument.Tables; //добавим в Document таблицу из трех строк и трех столбцов WordTable.Add(WordDocument.Range,3,3); //получим ссылку на объект Cells объекта Range первой таблицы объекта Tables C:=WordTable.Item(1).Range.Cells; //получим количество ячеек, находящихся в объекте Cells CellCount:=C.Count; For N:=1 To CellCount Do Begin //вставим в каждую ячейку ее номер C.Item(N).Range.InsertAfter(IntToStr(N)); End; //увеличим высоту первой строки WordTable.Item(1).Rows.Item(1).Height:=20; //отцентрируем текст в первой строке по центру (вертикаль) WordTable.Item(1).Rows.Item(1).Cells.VerticalAlignment:=wdAlignVerticalCenter; end;Чем интересен этот пример.
Delphi:
WordTable.Item(1).Rows.Item(1).Height:=20;
WordTable.Item(1).Rows.Item(1).Cells.VerticalAlignment:=wdAlignVerticalCenter;
Примечание: В данном случае воспользоваться
With - Do не получится, т.к.
WordTable.Item(1).Rows.Item(1)
для Delphi не является записью, объектом или классом, соответственно
компилятор выдаст эту ошибку.
Т.е. для того, чтобы изменить свойство объекта надо пользоваться следующей конструкцией
главный_объект.коллекция_объектов.item(№).свойство:=константа(или значение);
Во-вторых, можно посмотреть как пользоваться методами объектов
MS Word Visial Basic:
Set newDoc = Documents.Add
Set myTable = newDoc.Tables.Add(Selection.Range, 3, 3)
Set myRange = ActiveDocument.Range(0, 0)
ActiveDocument.Tables.Add Range:=myRange, NumRows:=3, NumColumns:=4
В обоих случаях к методу объекта в Delphi будет обращение:
WordTable.Add(Range,NumRows,NumColumns)
Только в первом случае объект Range, можно использовать от объекта Selection, а мы для
упрощения возьмем Range от WordDocument
WordTable.Add(WordDocument.Range,3,3);
А во втором случае объявляем переменную myRange типа OleVariant, присваиваем ей нужные значения и подставляем в обращение к методу Add.
Var myRange:OleVariant; Begin myRange:=WordDocument.Range; myRange.Start:=0; myRange.End:=0; WordTable.Add(myRange,3,4); End;Обратите внимание на строку myRange:=WordDocument.Range;
Итак, вызывая методы VB в Delphi, надо пользоваться следующей конструкцией:
главный_объект.коллекция_объектов.item(№).метод(аргумент, аргумент,..,аргумент);
Некоторые аргументы за ненадобностью можно не указывать.
Например, метод Close (см. справку Document - Methods - Close Method) объекта Document имеет три аргумента
Close(SaveChanges, OriginalFormat, RouteDocument)
В Delphi можно писать:
1.
WordDocument.Close;
2.
WordDocument.Close(wdDoNotSaveChanges);
3.
WordDocument.Close(wdDoNotSaveChanges, wdOriginalDocumentFormat)
4.
WordDocument.Close(wdDoNotSaveChanges, wdOriginalDocumentFormat, True);
как пользоваться константами уже говорилось.
В-третьих, просто подсказано хорошее решение. К ячейкам таблицы идет обращение не через объект Table напрямую, а через его встроенный объект Range. В объекте Table ячейки имеют адресацию Cell(строка, столбец), а в объекте Range - Cells(номер ячейки). Кроме этого объект Table не имеет свойства Count для ячеек, а объект Range имеет.
Ну на самом деле все не так страшно. Главное понять как обращаться к объектам MS Word Visial Basic, уметь общаться с его справкой и немного тренировок :)
На основании вышеизложенного следует сделать вывод, что время жизни Application - величина
неопределенная. Эту особенность следует учитывать при проектировании приложений. По моему
мнению, лучший вариант:
1. Создать объект Word.Application
2. Произвести все необходимые манипуляции с отчетом
3. Показать готовый отчет пользователю
4. Закрыть свое приложение, предоставив управление Application'ом надежным и крепким рукам пользователя -
"мавр", так сказать, "сделал свое дело... "
В случае же, если мы делаем первые шаги по управлению Word'ом, то лучше лишение жизни Application'а предусмотреть заранее. Иначе неизбежные в ходе опытов ошибки напрочь переполнят память компьютера экземплярами Winword'а.
Но это еще не все: в ходе экспериментов сам объект Word.Application может оказаться разрушен и
обращение к процедуре глобальной обработки ошибок в свою очередь также может вызвать ошибку.
И пошло - поехало: погоня за собственным хвостом.
Короче, ниже приведен грубый, но надежный метод казни непослушного Word.Application:
unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComObj; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } WordApp:OleVariant; Procedure WordAppExcept(Sender:TObject; E:Exception); public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} Procedure TForm1.WordAppExcept(Sender:TObject; E:Exception); Begin Try WordApp.Quit(0); Except End; End; procedure TForm1.FormCreate(Sender: TObject); begin Application.OnException:=WordAppExcept; WordApp:=CreateOleObject('Word.Application'); end; end.Включите приведенный текст в модуль и вперед, к покорению Word.Application!
Example2 unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComObj, Mask, StdCtrls; type TForm1 = class(TForm) memoText: TMemo; Label1: TLabel; edNumber: TEdit; Label2: TLabel; meDate: TMaskEdit; Label3: TLabel; Button1: TButton; procedure FormCreate(Sender: TObject); procedure edNumberKeyPress(Sender: TObject; var Key: Char); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure Button1Click(Sender: TObject); private { Private declarations } WordApp:OleVariant; WordTables:OleVariant; Procedure WordAppExcept(Sender:TObject; E:Exception); public { Public declarations } end; Const ShablonFileName='shablon.doc'; var Form1: TForm1; implementation {$R *.DFM} Procedure TForm1.WordAppExcept(Sender:TObject; E:Exception); Begin //место экзекуции непослушного Word.Application Try WordApp.Quit(0); Except End; End; procedure TForm1.FormCreate(Sender: TObject); Var FileName:String; DocNumber:Integer; begin //настраиваем глобальный обработчик ошибок Application.OnException:=WordAppExcept; //создаем объект Word.Application WordApp:=CreateOleObject('Word.Application'); //получаем путь к шаблону FileName:=ExtractFilePath(ParamStr(0))+ShablonFileName; //открываем документ WordApp.Documents.Open(FileName); //получаем ссылку на объект Tables активного документа WordTables:=WordApp.ActiveDocument.Tables; //пытаемся считать номер документа Try DocNumber:=StrToInt(Trim(WordTables.Item(1).Cell(1,2).Range.Text)); Except DocNumber:=0; End; //увеличиваем номер Inc(DocNumber); //показываем на форме номер документа edNumber.Text:=IntToStr(DocNumber); //показываем на форме текущую дату meDate.Text:=DateToStr(Now); end; procedure TForm1.edNumberKeyPress(Sender: TObject; var Key: Char); begin //набирать можно только цифры If Not((Key In ['0'..'9'])Or (Key=Chr(8))) Then Key:=Chr(7); end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin //показываем наш шаблон WordApp.Visible:=True; //разворачиваем его на весь экран //wdWindowStateMaximize = $00000001; WordApp.WindowState:=1; //активизируем текущий экземпляр MS Word WordApp.Activate; end; procedure TForm1.Button1Click(Sender: TObject); Var TextStr:String; N:Integer; begin //запишем в шаблон номер документа WordTables.Item(1).Cell(1,2).Range:=edNumber.Text; //запишем в шаблон дату документа WordTables.Item(1).Cell(1,4).Range:=meDate.Text; //соберем текст с символами конца строки и перехода на новую строку //для каждой строчки TextStr:=''; For N:=0 To memoText.Lines.Count-1 Do TextStr:=TextStr+memoText.Lines[N]+#13#10; //запишем текст в шаблон WordTables.Item(2).Cell(1,1).Range:=TextStr; //Уходя - выключай свет! ShowMessage('Перед повторным запуском не забудь закрыть MS Word!'); //закрываемся... Close; end; end.Ну вот, первый шаг сделан.
Напоследок.
Если кому-то статья помогла - буду рад. А если нет - "звыняйте, дядьку!... :)
Удачи!
Другие небольшие программы и примеры ищите на http://www.inta.portal.ru/dark/