Собранные версии компонента с примерами использования
Архив на Яндекс.Диск
Файлы в архиве
Файлы для 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.
Остальные Вопросы
В программе необходимо сделать вывод отчета в формате ворд. Есть несколько полей в которые вводится информация + из неслькольких переменных данные необходимо вывести в таблице в ворде, помимо этого там еще будет обычный текст(неменяющийся) Почитал, но мало что понял) все говорят по разному кто то предлагает, какие тогенераторы отчетов использовать, хз де их искать кто то через создание шаблона и вставку в нужные места текста потом. Посоветуйте как лучше сделать может у кого есть ссылки на необходимые статьи