Собранные версии компонента с примерами использования
Архив на Яндекс.Диск
Файлы в архиве
Файлы для Delphi 7
- ОписаниеРазработки.txt — этот файл.
- WordReport70.zip — исполняемые файлы и ресурсы компонента.
- WR_ExampleD7.zip — пример применения компонента.
- WordReport70src.zip — исходные коды компонента.
Файлы для Delphi XE3
- ОписаниеРазработки.txt — этот файл.
- WordReport170.zip — исполняемые файлы и ресурсы компонента.
- WordReport170src.zip — исходные коды компонента.
- WR_ExampleDXE3.zip — пример применения компонента.
Назначение
Компонент предназначен для автоматизации создания отчетов через MS Word.
Как исходный шаблон, так и готовый отчет представляют собой обычные документы Word, что обеспечивает пользователю самыме богатые возможности редактирования, предпросмотр и печать без каких-либо дополнительных средств.
Программные требования
- Borland Delphi или Embarcadero RAD Studio XE3.
- Microsoft Word 2000 и выше.
Установка
- Извлечь файлы из WordReport(Version).zip в директорию с установленной Delphi (например, WordReport70.zip в «C:Program Files (x86)BorlandDelphi7»).
- Запустить Delphi.
- Выбрать пункт меню Component >> Install Packages…
- Нажать кнопку Add… и выбрать файл WordReport(Version).bpl в DelphiBin (например, WordReport70.bpl в «C:Program Files (x86)BorlandDelphi7BinWordReport70.bpl»)
- Компонент готов к работе. Его можно найти на вкладке WordReport.
Инструкция
Правила создания шаблонов
Шаблон в нашем случае — это документ MS Word (именно документ — т.е. файл *.doc, а не *.dot !), составленный по определенным правилам.
-
Секция — это диапазон шаблона, который должен повторяться в результирующем документе столько раз, сколько требуется для вывода всех записей привязанного к секции набора данных.
-
Каждая секция должна быть отмечена закладкой с именем DataN, где N — целое число от 1 до 8.
Повторяться будет ТОЛЬКО то, что в диапазоне закладки, поэтому закладкой лучше отмечать всю строку документа целиком. Если секция используется
для повторения строки таблицы, то отмечать закладкой следует также всю строку документа, в которой находится эта строка таблицы. -
Существует три категории переменных шаблона:
-
переменные вне секций
Синтаксис объявления: #(ИмяСвободнойПеременной)
Способ определения значения: напрямую, методом SetValue -
переменные секций
Синтаксис объявления: #(ИмяСекции(ИмяСчетчика).ИмяПеременной)
Способ определения значения: из текущей записи привязанного поля набора данных. -
счетчики записей секций
Синтаксис объявления: #(ИмяСчетчика)
Объявление действительно только внутри секции.
Заменяется на текущий номер записи привязанного набора данных при отсутствии групп секций
или на номер записи в неразвывной последовательности при группировке секций.
-
ИмяСвободнойПеременной — ненулевая последовательность латинских букв, цифр и точек (только букв, цифр и точек, никаких других знаков!). Регистр букв не важен.
-
ИмяПеременной — ненулевая последовательность латинских букв и цифр. Регистр букв не важен.
-
ИмяСчетчика — ненулевая последовательность латинских букв и цифр. Регистр букв не важен.
-
ИмяСекции — ненулевая последовательность латинских букв и цифр. Регистр букв не важен.
-
Максимальное количество переменных в секции — 16.
-
Максимальное количество секций в документе — 8.
-
Максимальное количество переменных вне секций — 2^31 — 1, то есть верхняя граница 32-битного целого типа.
Описание функционала компонента
Свойства времени разработки
Имя документа, содержащего шаблон
TemplateDocFileName: string
Имя документа, в котором следует сохранить готовый отчет
ResultDocFileName: string
Показать MS Word c готовым отчетом при вызове Quit
ShowResult: boolean
Свойства времени выполнения
Массив секций документа.
Доступ по имени секции.
Если секция не найдена — возвращает nil.
Bands[Name:string]: TDataBand
Количество секций документа.
BandCount: integer
Методы
Существует ли в шаблоне секция с именем BandName.
function BandExists(BandName: string): boolean;
Сохранить документ в файле FileName.
procedure SaveToFile(FileName: string);
Выйти. Завершает процесс MS Word или показывает готовый документ.
procedure Quit;
Сформировать отчет. Выполняет все операции для формирования одного отчета, сохраняет и закрывает полученный документ.
Однако, сам Word остается запущенным для формирования следующих отчетов.
procedure Build;
Установить значение свободной переменной.
procedure SetValue(VariableName:string; Value:Variant);
Связать две соседние секции вместе
так чтобы они чередуясь выводили записи из одного и того же набора данных (НД).
Однако, для этого требуется указать целочисленное поле в НД,
значение которого и будет определять, какую именно секцию использовать для вывода текущей записи.
procedure JoinBands(BandKeyField:string; BandName1:string; KeyValue1:integer; BandName2:string; KeyValue2:integer);
События
Событие наступает после прочтения структуры документа-шаблона,
т.е. тогда, когда имена всех секций (bands) и переменных уже определены, но
этим переменным еще не установлены значения или поля набора данных (НД).
OnReadMaket:TNotifyEvent;
Объект секции документа (TDataBand)
Свойства времени выполнения
Имя секции документа.
Name: string
Имя поля для переменной VarName.
Field[VarName:string]: string
Формат вывода переменной.
Format[VarName:string]: string
Методы
Подключить набор данных к секции.
Параметром служит указатель на TDataset, т.е. вызов производится так:
AssignDataSet(@IBQuery1) или AssignDataSet(@ADOTable1).
procedure AssignDataSet(aDataSet: PDataSet);
Установить переменной VariableName из секции поле FieldName набора данных, подключенного к этой секции.
Если поле содержит действительные числа, то лучше использовать маску формата для их отображения,
например %10.2f (полный список форматов см. в описании функции SysUtils.Format).
Во всех других случаях значение параметра формат можно оставить пустой строкой, т.к. это ни на что не повлияет
procedure SetField(VariableName,FieldName,Format:string);
Обработка события OnReadMaket
Так как каждый шаблон уникален и содержит свой неповторимый набор секций и переменных, то и связывание этих секций и переменных со своими
значениями также процесс уникальный, а потому не может быть до конца автоматизирован внутри самого компонента. Эту задачу предстоит решить пользователю компонента.
Специально для этой цели и было создано данное событие.
В обработчике этого события НЕОБХОДИМО произвести связывание:
- имен переменных с их значениями (TWordReport.SetValue),
- секций с их заполненными наборами данных (TDataBand.AssignDataset),
- переменных в секции с их полями (TDataBand.SetField),
- а также, если это нужно — формирование групп секций (TWordReport.JoinBands)
Подробнее об этом в примере приложения.
Иные версии Delphi
Если нужен компонент для другой версии Delphi — используйте исходные коды, чтобы собрать пакет на своей Delphi, а затем скопируйте его:
- 32-битную release версию bpl — в поддиректорию bin
- 64-битную release bpl — в bin64
- 32-битную release версию dcu вместе с файлами WordReport.dcr и wrtprogress.dfm в libwin32release.
- 64-битную release версию dcu вместе с файлами WordReport.dcr и wrtprogress.dfm в libwin64release.
- Отладочные DCU, если они нужны, копируются в libwin32debug и libwin64debug уже без файлов ресурсов.
Шаблоны и отчёты MS Word
Многие популярные информационно-правовые системы содержат шаблоны различных документов в формате Word. Используя их и информацию данной статьи, вы можете легко и быстро создавать отчеты, если пишете свои программы на Delphi. Если пишете на другом языке, это не помеха, описанный подход справедлив к различным языкам.
Когда мы формируем сложный документ по шаблону, и когда в этом шаблоне есть таблицы, количество строк которых в выходном документе может быть произвольным и зависеть от объема информации, то нам недостаточно просто функций создания таблиц и записи в ячейки определенной информации. Для создания такого документа необходимо, как минимум, еще несколько функций работы с таблицами, в перечень которых входит перемещение по таблицам, добавление строк (столбцов) в конец или в середину таблицы. Также необходимо определять размер (количество строк, столбцов) и номер текущего столбца и строки. Чтобы понимать, о чем речь, необходимо просмотреть части 1-3 данной статьи, опубликованных в предыдущих номерах.
Для того, чтобы применить свои знания к конкретной задаче, сделаем ее постановку. Например, в нашем документе есть таблица, которая представляет собой шаблон и заполняется из массива информации, который имеет произвольную длину. Таким документом может быть счет-фактура, заголовок которой представляет собой сложную таблицу, средняя часть представляет таблицу переменной длины, а нижняя также представляет сложную таблицу. Для заполнения такого шаблона можно использовать способ, описанный во второй части данной статьи. Этот способ основан на поиске в шаблоне переменных (неповторяющиеся строковые значения длиной 3-5 символов) и подстановке вместо них реальных значений на этапе формирования документа. Поэтому для добавления информации в такую таблицу придется осуществить поиск и позиционирование в строку (по переменной), в которую и перед которой необходимо вставлять строки, и запомнить, в какие колонки какую записывать информацию, но для начала необходимо определить, находится курсор в таблице или нет.
Для этого используем свойство Information объекта Selection, в качестве параметра которого будет константа wdWithInTable. В этом случае этот метод возвращает TRUE, если курсор в таблице, или FALSE, если нет. Для использования в нашем приложении создадим функцию GetSelectionTable.
Function GetSelectionTable:boolean;
const wdWithInTable=12;
begin
GetSelectionTable:=true;
try
GetSelectionTable:=W.Selection.Information(wdWithInTable);
except
GetSelectionTable:=false;
end;
End;
Если в нашем документе может быть более одной таблицы, то, скорее всего, необходима возможность перехода и позиционирование курсора на следующей или предыдущей таблице. Объект Selection дает нам эту возможность через методы GoTo и GoTo, в этом случае в качестве их параметров должна использоваться константа wdGoToTable.
Function GoToTable (table_:integer):boolean;
const wdGoToTable=2;
begin
GoToTable:=true;
try
W.Selection.GoTo (wdGoToTable);
except
GoToTable:=false;
end;
End;
Function GoToTable (table_:integer):boolean;
const wdGoToTable=2;
begin
GoToTable:=true;
try
W.Selection.GoTo(wdGoToTable);
except
GoToTable:=false;
end;
End;
Когда мы позиционируемся на таблице, можем определить количество столбцов и строк в ней. Для этого также используем свойство Information объекта Selection, но в качестве аргументов используем константы wdMaximum Number Of Columns и wdMaximum NumberOfRows.
Function GetColumnsRowsTable(table_:integer;
var Columns,Rows:integer):boolean;
const
wdMaximumNumberOfColumns=18;
wdMaximumNumberOfRows=15;
begin
GetColumnsRowsTable:=true;
try
Columns:=W.Selection.Information (wdMaximumNumberOfColumns);
Rows:=W.Selection.Information (wdMaximumNumberOfRows);
except
GetColumnsRowsTable:=false;
end;
End;
Кроме размера таблицы, нам может быть необходим номер колонки и строки, на которой позиционирован курсор. Для этого так же используем свойство Information объекта Selection, но в качестве аргументов используем константы wdStartOfRangeColumnNumber, wdStartOfRangeRowNumber. Для реализации этого в Delphi создадим функцию GetColumnRowTable.
Function GetColumnRowTable(table_:integer;
var Column,Row:integer):boolean;
const
wdStartOfRangeColumnNumber=16;
wdStartOfRangeRowNumber=13;
begin
GetColumnRowTable:=true;
try
Column:=W.Selection.Information (wdStartOfRangeColumnNumber);
Row:=W.Selection.Information (wdStartOfRangeRowNumber);
except
GetColumnRowTable:=false;
end;
End;
После того, как мы нашли таблицу в шаблоне документа и позиционировались на определенной ячейке, нам необходимо выполнить некоторые действия с ней (добавить, вставить строки, записать информацию). Очевидно, что нам нужен будет набор функций для ее модификации.
Обычно во время формирования таблицы мы не знаем, сколько будет строк. Они могут добавляться в конец или вставляться в середину таблицы. Если для формирования документа мы используем шаблон таблицы и в нем уже есть, например, заголовок, то нам не обойтись без процедур добавления или вставления строк. Добавить строку в конец таблицы можно, используя метод Add коллекции Rows. Чтобы это сделать из приложения на Delphi, достаточно создать и использовать функцию. Определим ее как AddRowTableDoc.
Function AddRowTableDoc (table_:integer):boolean;
begin
AddRowTableDoc:=true;
try
W.ActiveDocument.Tables.Item(table_).Rows.Add;
except
AddRowTableDoc:=false;
end;
End;
Для того, чтобы вставлять строки в середину таблицы, удобно использовать пару операторов. Первый выделяет строку, перед которой необходимо вставить новую, второй вставляет строку (строки). Смотрите функцию InsertRowsTableDoc.
Function InsertRowsTableDoc(table_,position_,
count_:integer): boolean;
begin
InsertRowsTableDoc:=true;
try
W.ActiveDocument.Tables.Item(table_).Rows.Item(position_).Select;
W.Selection.InsertRows (count_);
except
InsertRowsTableDoc:=false;
end;
End;
Для добавления одной строки можно использовать также и метод Add коллекции Rows, но с параметром, в качестве которого выступает ссылка на строку, перед которой необходимо вставить новую. Первый оператор получает ссылку на строку, второй вставляет новую. Смотрите реализацию на Delphi (InsertRowTableDoc).
Function InsertRowTableDoc(table_,position_: integer):boolean;
var row_:variant;
begin
InsertRowTableDoc:=true;
try
row_:=W.ActiveDocument.Tables.Item(table_).Rows.Item(position_);
W.ActiveDocument.Tables.Item(table_).Rows.Add(row_);
except
InsertRowTableDoc:=false;
end;
End;
Когда мы в своем распоряжении имеем набор функций для изменения таблицы, можно приступать к решению задачи — созданию документа типа счета-фактуры на базе шаблона. Полный исходный текст и полную версию шаблона счета-фактуры можно скачать по адресу www.kornjakov.ru/st1_4.zip. Здесь мы рассмотрим фрагмент данного документа. Создадим шаблон — документ формата DOC — и разместим его на диске в каталоге нашего проекта. Внешний вид шаблона смотрите на рисунке.
Здесь будем заполнять только табличную часть. О том, как заполнять остальное, читайте вторую часть данной статьи. Для начала наши новые функции скопируем в библиотеку MyWord, которую мы создавали, начиная с первой части статьи. Затем создадим новый проект, на форме которого разместим кнопку, а в процедуре обработки ее нажатия напишем следующий программный текст.
procedure TForm1.Button1Click(Sender: TObject);
var tablica_:integer;
col_,row_:integer;
a_:integer;
metki_:array[1..12] of record
col:integer;
row:integer;
metka:string;
end;
tovar:array[1..2,1..12] of variant;
begin
// Заполняем массив данными. Массив используется
//для простоты демонстрации, в реальной программе
//данные берутся из базы данных.
tovar[1,1]:=‘Стул офисный’; tovar[1,2]:=‘шт.’;
tovar[1,3]:=2; tovar[1,4]:=520.00; tovar[1,5]:=1040.00;
tovar[1,6]:=‘-‘; tovar[1,7]:=20; tovar[1,8]:=208.0;
tovar[1,9]:=1248.00; tovar[1,10]:=62.40;
tovar[1,11]:=‘Россия’; tovar[1,12]:=‘-‘;
tovar[2,1]:=‘Телефон’; tovar[2,2]:=‘шт.’;
tovar[2,3]:=3; tovar[2,4]:=315.25; tovar[2,5]:=945.75;
tovar[2,6]:=‘-‘; tovar[2,7]:=20; tovar[2,8]:=189.15;
tovar[2,9]:=1134.90; tovar[2,10]:=56.70;
tovar[2,11]:=‘Беларусь’; tovar[2,12]:=‘-‘;
if CreateWord then begin
VisibleWord(true);
If OpenDoc(ExtractFileDir (application.ExeName) +‘sf.doc’)
then begin
tablica_:=1;
for a_:=1 to 12 do begin
StartOfDoc;
if FindTextDoc(‘###M’+inttostr(a_)+‘&’) then
if GetSelectionTable then begin
messagebox(handle,‘Находимся в таблице, запоминаем
метку(переменную), номер колонки и строки!’
,
pchar(‘Номер колонки/строки = ‘+inttostr(col_)+‘/’+inttostr(row_)),0);
metki_[a_].col:=col_;
metki_[a_].row:=row_;
metki_[a_].metka:=‘###M’+inttostr(a_)+‘&’;
end;
end;
Messagebox(handle,‘Заполняем первую строку’,»,0);
for a_:=1 to 12 do begin
SetTextToTable(tablica_,metki_[a_].row,metki_[a_].col,tovar[1,a_]);
end;
a_:=1;
Messagebox(handle,‘Добавляем строку’,»,0);
InsertRowTableDoc(tablica_, metki_[a_].row);
Messagebox(handle,‘Заполняем вторую строку’,»,0);
for a_:=1 to 12 do begin
SetTextToTable(tablica_,metki_[a_].row,metki_[a_].col,tovar[2,a_]);
end;
SaveDocAs(ExtractFileDir(application.ExeName)+‘Счет — фактура.doc’);
Messagebox(handle,‘Текст сохранен’,»,0);
CloseDoc;
end;
Messagebox(handle,‘ Текст закрыт’,»,0);
CloseWord;
end;
end;
Мы сформировали фрагмент сложного документа, но вы, возможно, захотите в дальнейшем сами развивать эту тему и использовать все возможности Word.Application. В следующей части я постараюсь на примерах объяснить, каким образом это сделать. По всем вопросам вы можете обратиться к автору по адресу www.kornjakov.ru или _kvn@mail.ru.
Василий КОРНЯКОВ
Литература: Н. Елманова, С. Трепалин, А. Тенцер «Delphi 6 и технология COM» «Питер» 2002.
В этой статье я хочу поговорить об очередной интересной полезности, такой как создание отчетности в Microsoft Word. Недавно передо мной стала задача, автоматизировать процесс заключения договоров у меня на работе, и последующего их хранения и учета в электронном виде.
Пришлось перелопатить конечно много информации, но на выходе неожиданно для самого себя получилось очень простое,
компактное и я бы даже сказал универсальное решение, которым бы я хотел поделиться.
Многие кто по долгу работы сталкивается с заключением договоров, знает, что даже работая с типовыми их формами, все равно возникают сложности, на предмет, то пропустишь, и забудешь вбить какие то данные, то вобьешь их не туда куда надо, бывает даже и такое, когда у тебя очередь и буквально разрываешься на части, и о возможности сконцентрироваться, чтобы качественно обслужить текущего клиента, можно только мечтать. Ошибся, переписываешь все заново, опять куча потерянного времени, а особенно под конец дня вообще, жесть. В общем решил я положить этому всему край, и в очередной выходной занялся реализацией задуманного.
Задача стояла следующая, необходимо было создать некую форму документа с полями, куда бы я мог вбивать данные по договору, а потом, по нажатию клавиши смог бы либо сохранить, либо распечатать, уже готовый договор.
Полный листинг получившегося приложения я приводить, здесь не буду по скольку всего очень много, а небольшой примерчик доступный для понимания мы рассмотрим, тем паче, что подробно рассмотрев его, любой из вас самостоятельно сможет создавать фишки с отчетностью даже еще круче чем получилось у меня.
Итак приступим:
Работать мы будем с шаблоном документа MS Word, для этого создаем вордовский документ,
набираем в нем форму нашего договора, только вместо данных, которые мы будем перемещать в документ из нашей формы, впишем имена произвольных переменных. Допустим вместо даты, напишем слово date, Ф.И.О исполнителя — «FIO1«, Ф.И.О заказчика — «FIO2» и.т.д.
Чтобы легче было ориентироваться, ниже привожу скринчик, ориентировочного шаблона:
Почему именно так и для чего все это надо, забегая немного вперед поясню. В дальнейшем,
мы с вами, напишем функцию, которая будет искать эти значения и заменять на то что мы будем вводить в поля нашей формы. Вот так все просто). Записываем в Edit1, Ф.И.О. клиента , функция находит абзац, находит слово FIO2, и заменяет его на содержимое из нашего Edit1.
Далее, когда шаблон готов, сохраняем документ в формате .dot присваиваем ему какое нибудь имя, (я например свой назвал просто — «Договор«) и для удобства работы сохранил его на диск D:\
Все с шаблоном разобрались, теперь переходим непосредственно к программированию.
1) Создаем новый проект и помещаем на форму ряд компонентов (как на скрине ниже),
подключаем в Uses библиотеку ComObj, объявляем глобальные переменные:
var
Dogovor,W:Variant;
Text:String;
и приступим к настройке компонентов на форме:
а) Кликаем компонент SaveDialog1, переходим к инспектору объектов, где в его свойстве
Filter — прописываем Документ Microsoft Word|*.doc ;
б) В список Items компонента Combobox1, записываем какие нибудь города, например тот где вы живете или работаете). Свойство ItemIndex устанавливаете в 0;
2) Теперь создадим функцию, о которой мы говорили выше, она будет искать и осуществлять замену, для этого в разделе private пропишем:
function Repl(Atx, B, C:String):String;
нажимаем Ctrl+Shift+C и описываем ее:
function TForm3.Repl(Atx, B, C: String):String;
var
F1,F2,F3:String;
begin
F1:=»;
F2:=Atx;
F3:=Atx;
while
Pos(B, F2)>0 do
begin
F2:=Copy(F2, Pos (B, F2), (Length(F2)- Pos(B, F2))+1);
F1:=Copy(F3, 1, Length(F3) — Length(F2))+C;
delete(F2, Pos (B, F2), Length(B));
F3:=F1+F2;
end;
result:=F3;
end;
3) В событии OnCreate на форме, внесем настройки в DateTimePicker1 и DateTimePicker2, чтобы при запуске они показывали текущую дату:
procedure TForm1.FormCreate(Sender: TObject);
begin
DateTimePicker1.Date:=Now;
DateTimePicker2.Date:=Now;
end;
4) В событии OnClick, на кнопке «Печать» пишем:
procedure TForm1.Button1Click(Sender: TObject);
var
Text :String;
begin
D:=CreateOleObject(‘Word.Application’); //Создаем OLE объект;
D.Documents.Open(‘D:Договор.dot’); //Загружаем для работы наш шаблон договора;
D.Options.CheckSpellingAsYouType:=false; //Отключение правописания и
D.Options.CheckGrammarAsYouType:=false; //грамматики;
W:=D.Documents.Item(1);
text:=W.Paragraphs.Item(1).Range.Text; //Замена Num, на содержимое Edit1;
text:=repl(text,’Num’,Edit1.Text);
W.Paragraphs.Item(1).Range.Text:=text;
text:=W.Paragraphs.Item(3).Range.Text; //Замена Gorod в договоре на содержимое
text:=repl(text,’Gorod’,Combobox1.Text); //Combobox1;
W.Paragraphs.Item(3).Range.Text:=text;
text:=W.Paragraphs.Item(3).Range.Text; //Замена Date1 в договоре на содержимое Q;
text:=repl(text,’Date1′,DateToStr(DateTimePicker1.Date));
W.Paragraphs.Item(3).Range.Text:=text;
text:=W.Paragraphs.Item(5).Range.Text; //Замена FIO1, на содержимое Edit2;
text:=repl(text,’FIO1′,Edit2.Text);
W.Paragraphs.Item(5).Range.Text:=text;
text:=W.Paragraphs.Item(7).Range.Text; //Замена FIO2, на содержимое Edit5;
text:=repl(text,’FIO2′,Edit5.Text);
W.Paragraphs.Item(7).Range.Text:=text;
text:=W.Paragraphs.Item(12).Range.Text; //Замена Tovar, на содержимое Edit6;
text:=repl(text,’Tovar’,Edit6.Text);
W.Paragraphs.Item(12).Range.Text:=text;
text:=W.Paragraphs.Item(14).Range.Text; //Замена Addr, на содержимое Edit3;
text:=repl(text,’Addr’,Edit3.Text);
W.Paragraphs.Item(14).Range.Text:=text;
text:=W.Paragraphs.Item(15).Range.Text; //Замена Tel, на содержимое Edit4;
text:=repl(text,’Tel’,Edit4.Text);
W.Paragraphs.Item(15).Range.Text:=text;
text:=W.Paragraphs.Item(18).Range.Text; //Замена Price, на содержимое Edit7;
text:=repl(text,’Price’,Edit7.Text);
W.Paragraphs.Item(18).Range.Text:=text;
text:=W.Paragraphs.Item(23).Range.Text; //Замена Date2, на содержимое DateTimePicker2;
text:=repl(text,’Date2′,DateToStr(DateTimePicker2.Date));
W.Paragraphs.Item(23).Range.Text:=text;
text:=W.Paragraphs.Item(27).Range.Text; //Замена FIO3, на содержимое Edit5;
text:=repl(text,’FIO3′,Edit5.Text);
W.Paragraphs.Item(27).Range.Text:=text;
text:=W.Paragraphs.Item(27).Range.Text; //Замена FIO4, на содержимое Edit2;
text:=repl(text,’FIO4′,Edit2.Text);
W.Paragraphs.Item(27).Range.Text:=text;
if PrintDialog1.Execute then //Печать документа;
D.ActiveDocument.PrintOut;
D.Application.ActiveDocument.Close(false); //Закрываем документ, не сохраняем изменения;
D.Quit; //Освобождаем переменную;
end;
5) В событии OnClick, на кнопке «Сохранить» пишем все тоже самое, только в самом начале, после begin, зададим параметр FileName для компонента SaveDialog1, чтобы при сохранении договоров, в имя файла автоматом вбивался номер и дата документа). А в конце опишем опции сохранения, вместо опций печати:
procedure TForm1.Button1Click(Sender: TObject);
var
Text :String;
begin
SaveDialog1.FileName:=(‘Договор ‘+’№ ‘+Edit1.Text+’ от ‘+DateToStr(DateTimePicker1.Date)+’.doc’);
D:=CreateOleObject(‘Word.Application’); //Создаем OLE объект;
D.Documents.Open(‘D:Договор.dot’); //Загружаем для работы наш шаблон договора;
D.Options.CheckSpellingAsYouType:=false; //Отключение правописания и
D.Options.CheckGrammarAsYouType:=false; //грамматики;
W:=D.Documents.Item(1);
text:=W.Paragraphs.Item(1).Range.Text; //Замена Num, на содержимое Edit1;
text:=repl(text,’Num’,Edit1.Text);
W.Paragraphs.Item(1).Range.Text:=text;
text:=W.Paragraphs.Item(3).Range.Text; //Замена Gorod в договоре на содержимое
text:=repl(text,’Gorod’,Combobox1.Text); //Combobox1;
W.Paragraphs.Item(3).Range.Text:=text;
text:=W.Paragraphs.Item(3).Range.Text; //Замена Date1 в договоре на содержимое Q;
text:=repl(text,’Date1′,DateToStr(DateTimePicker1.Date));
W.Paragraphs.Item(3).Range.Text:=text;
text:=W.Paragraphs.Item(5).Range.Text; //Замена FIO1, на содержимое Edit2;
text:=repl(text,’FIO1′,Edit2.Text);
W.Paragraphs.Item(5).Range.Text:=text;
text:=W.Paragraphs.Item(7).Range.Text; //Замена FIO2, на содержимое Edit5;
text:=repl(text,’FIO2′,Edit5.Text);
W.Paragraphs.Item(7).Range.Text:=text;
text:=W.Paragraphs.Item(12).Range.Text; //Замена Tovar, на содержимое Edit6;
text:=repl(text,’Tovar’,Edit6.Text);
W.Paragraphs.Item(12).Range.Text:=text;
text:=W.Paragraphs.Item(14).Range.Text; //Замена Addr, на содержимое Edit3;
text:=repl(text,’Addr’,Edit3.Text);
W.Paragraphs.Item(14).Range.Text:=text;
text:=W.Paragraphs.Item(15).Range.Text; //Замена Tel, на содержимое Edit4;
text:=repl(text,’Tel’,Edit4.Text);
W.Paragraphs.Item(15).Range.Text:=text;
text:=W.Paragraphs.Item(18).Range.Text; //Замена Price, на содержимое Edit7;
text:=repl(text,’Price’,Edit7.Text);
W.Paragraphs.Item(18).Range.Text:=text;
text:=W.Paragraphs.Item(23).Range.Text; //Замена Date2, на содержимое DateTimePicker2;
text:=repl(text,’Date2′,DateToStr(DateTimePicker2.Date));
W.Paragraphs.Item(23).Range.Text:=text;
text:=W.Paragraphs.Item(27).Range.Text; //Замена FIO3, на содержимое Edit5;
text:=repl(text,’FIO3′,Edit5.Text);
W.Paragraphs.Item(27).Range.Text:=text;
text:=W.Paragraphs.Item(27).Range.Text; //Замена FIO4, на содержимое Edit2;
text:=repl(text,’FIO4′,Edit2.Text);
W.Paragraphs.Item(27).Range.Text:=text;
if SaveDialog1.Execute then //Печать документа;
begin
D.ActiveDocument.SaveAs(SaveDialog1.FileName, $00000000);
ShowMessage(‘Файл сохранен в следующей директории: ‘+SaveDialog1.FileName);
end;
D.Application.ActiveDocument.Close(false); //Закрываем документ, не сохраняем изменения;
D.Quit; //Освобождаем переменную D;
end;
Теперь можно запускать проект и любоваться результатом). Если все делалось в той последовательности, как описано в статье, то все должно работать как часы, ибо пример рабочий на все 100%, а код копировался прямо из листинга.
Великовата получилась статейка, но из песни слов не выкинешь, а дорогу осилит идущий).
Кстати:
Если необходимо, можно установить ориентацию листа:
D.Application.Selection.PageSetup.Orientation:= $00000000; //Ориентация — портрет; если нужен ландшафт — $00000001;
и размеры полей:
D.Application.Selection.PageSetup.LeftMargin:=56; //отступ слева «2,5 сантиметра«;
D.Application.Selection.PageSetup.RightMargin:=28; //отступ справа «1,0 сантиметр«;
D.Application.Selection.PageSetup.TopMargin:=28; //отступ сверху «1.0 сантиметр«;
D.Application.Selection.PageSetup.BottomMargin:=42; //отступ снизу «1,5 сантиметра«;
Единицы измерения — пункты (1 см = 28,35 п).
Вот так, например можно установить жирность шрифта, размер и выравнивание:
W.Paragraphs.Item(?).Range.Font.Bold:=True;
W.Paragraphs.Item(?).Range.Font.Size:=13;
W.Paragraphs.Item(?).Alignment:=$00000000; //Выравнивание по левому краю; если нужно
по центру — $00000001; и т.д. значения некоторых констант приведены ниже:
wdAlignParagraphLeft = 000000;
wdAlignParagraphCenter = 000001;
wdAlignParagraphRight = 000002;
wdAlignParagraphJustify = 000003;
wdAlignParagraphDistribute = 000004;
wdAlignParagraphJustifyMed = 000005;
wdAlignParagraphJustifyHi = 000007;
wdAlignParagraphJustifyLow = 000008;
wdAlignParagraphThaiJustify = 000009;
Чтобы было удобней пользоваться программой в последующем, файл шаблона можно поместить в папке с экзешником проекта. А для обращения к нему воспользоваться следующим кодом:
var
FName, Path:String
begin
FName:=’Договор.dot’;
Path:=(ExtractFilePath(Application.ExeName)+»+FName);
D.Documents.Open(Path);
…
…
…
end;
Теперь куда бы ни был перемещен экзешник с программой, если вордовский шаблон находится с ним в одной папке, он будет без проблем открыт и использован. И не нужно никаких перезаписей путей в листинге.
Создание отчета в MS Word
(Пример для Delphi 1.0 поскольку в Delphi 2-3 лучше использовать:
var MsWord : variant;
MsWord := CreateOleObject('Word.Basic'); // Для Delphi 3, пример ниже
Создавать отчет в программе Word удобно если отчет имеет сложную структуру (тогда его быстрее создать в Word, чем в Qreport от Delphi, кроме того, этот QReport имеет «глюки»), либо, если после создания отчета его нужно будет изменять. Итак, первым делом в Word создается шаблон будущего отчета, это самый обыкновенный не заполненный отчет. А в места куда будет записываться информация нужно поставить метки. Например (для наглядности метки показаны зеленым цветом, реально они конечно не видны):
Накладная
| No | Поставщик | Наименование товара | Код товара | Кол-во | Цена | Сумма |
| 1 |
Сдал_______________________ Принял________________________
М.П. М.П.
Далее в форму, откуда будут выводиться данные, вставляете компоненту DdeClientConv из палитры System. Назовем ее DDE1. Эта компонента позволяет передавать информацию между программами методом DDE. Свойства:
ConnectMode : ddeManual — связь устанавливаем вручную
DdeService : (winword) — с кем устанавливается связь
ServiceApplication : C:MSOfficeWinwordWINWORD.EXE — полный путь доступа к программе. (Вот здесь можно наступить на грабли. Ведь Word может лежать в любой папке! Поэтому путь доступа к нему лучше взять из реестра, а еще лучше использовать OLE см.начало раздела)
Теперь пишем процедуру передачи данных:
{ Печать накладной }
procedure Form1.PrintN;
Var
S : string;
i : integer;
Sum : double; {итоговая сумма, кстати,совет: не пользуйтесь типом real!}
Tv, Ss : PChar;
begin
S:=GetCurrentDir+'Накладная.doc'; { имя открываемого документа }
DDE1.OpenLink; { устанавливаем связь }
Tv:=StrAlloc(20000); Ss:=StrAlloc(300); { выделяем память }
{ даем команду открыть документ и установить курсор в начало документа }
StrPCopy(Tv, '[FileOpen "'+S+'"][StartOfDocument]');
S:=NNakl.Text; { номер накладной }
{ записываем в позицию Num номер накладной }
StrCat(Tv, StrPCopy(SS, '[EditBookmark .Name = "Num", .Goto][Insert "'+S+'"]'+
'[EditBookmark .Name = "Table", .Goto]'); { и переходим к заполнению таблицы }
{ передаем данные в Word }
if not DDE1.ExecuteMacro(Tv, false) then
begin { сообщаем об ошибке и выход }
MessageDlg('Ошибка связи с Microsoft Word.', mtError, [mbOk], 0);
StrDispose(Tv); StrDispose(Ss);
exit;
end;
{ Заполняем таблицу }
Sum:=0; Nn:=0;
for i:=0 to TCount do
begin
inc(Nn);
{ предполагаем, что данные находятся в массиве T }
StrPCopy(Tv, '[Insert "'+IntToStr(Nn)+'"][NextCell][Insert "'+T[i].Company+'"]'+
'[NextCell][Insert "'+T.TName+'"][NextCell][Insert "'+T.Cod+'"][NextCell]'+
'[Insert "'+IntToStr(T.Count)+'"][NextCell]'+
'[Insert "'+FloatToStr(T.Cena)+'"][NextCell]'+
'[Insert "'+FloatToStr(T.Count*T.Cena)*+'"][NextCell]'));
inc(Nn);
Sum:=Sum+(T.Count*T.Cena); { итоговая сумма }
if not DDE1.ExecuteMacro(Tv, false)
then begin
MessageDlg('Ошибка связи с Microsoft Word.', mtError, [mbOk], 0);
exit;
end;
end;
{ Записываем итоговую сумму }
StrPCopy(Tv,
'[NextCell][Insert "Итого"][NextCell][NextCell][NextCell]'+
'[Insert "'+FloatToStr(Sum)+'"]'));
if not DDE1.ExecuteMacro(Tv, false)
then MessageDlg('Ошибка связи с Microsoft Word.', mtError, [mbOk], 0)
else MessageDlg('Акт удачно создан. Перейдите в Microsoft Word.',
mtInformation, [mbOk], 0);
StrDispose(Tv); StrDispose(Ss);
end;
Для Delphi 2 и выше
Пример проверен только на русском Word 7.0! Может, поможет…
unit InWord;
interface
uses
... ComCtrls; // Delphi3
... OLEAuto; // Delphi2
[skip]
procedure TPrintForm.MPrintClick(Sender: TObject);
var W: Variant;
S: String;
begin
S:=IntToStr(Num);
try // А вдруг где ошибка :)
W:=CreateOleObject('Word.Basic');
// Создаем документ по шаблону MyWordDot
// с указанием пути если он не в папке шаблонов Word
W.FileNew(Template:='C:MyPathDBMyWordDot',NewTemplate:=0);
// Отключение фоновой печати (на LJ5L без этого был пустой лист)
W.ToolsOptionsPrint(Background:=0);
// Переходим к закладке Word'a 'Num'
W.EditGoto('Num'); W.Insert(S);
//Сохранение
W.FileSaveAs('C:MayPathReportsMyReport')
W.FilePrint(NumCopies:='2'); // Печать 2-х копий
finally
W.ToolsOptionsPrint(Background:=1);
W:=UnAssigned;
end;
end;
{.....}
И еще, как определить установлен ли на компьютере Word, запустить его и загрузить в него текст из программы?
var
MsWord: Variant;
...
try
// Если Word уже запущен
MsWord := GetActiveOleObject('Word.Application');
// Взять ссылку на запущенный OLE объект
except
try
// Word не запущен, запустить
MsWord := CreateOleObject('Word.Application');
// Создать ссылку на зарегистрированный OLE объект
MsWord.Visible := True;
except
ShowMessage('Не могу запустить Microsoft Word');
Exit;
end;
end;
end;
...
MSWord.Documents.Add; // Создать новый документ
MsWord.Selection.Font.Bold := True; // Установить жирный шрифт
MsWord.Selection.Font.Size := 12; // установить 12 кегль
MsWord.Selection.TypeText('Текст');
По командам OLE Automation сервера см. help по Microsoft Word Visual Basic.
Остальные Вопросы

В программе необходимо сделать вывод отчета в формате ворд. Есть несколько полей в которые вводится информация + из неслькольких переменных данные необходимо вывести в таблице в ворде, помимо этого там еще будет обычный текст(неменяющийся) Почитал, но мало что понял) все говорят по разному кто то предлагает, какие тогенераторы отчетов использовать, хз де их искать 



