Microsoft Office и Delphi 5. Часть 2

Microsoft Office и Delphi 5. Часть 2 Продолжение. Начало в КГ №19

Во второй части статьи, посвященной работе с серверами автоматизации средствами Delphi 5, мы займемся созданием информационных отчетов и диаграмм в редакторе таблиц MS Excel, а также работой с программой MS Outlook с целью отсылки писем по адресам в адресной книге.
MS Word 2000. Но сначала хотелось бы ненадолго вернуться к первой части статьи, так как у читателей возникли вполне резонные вопросы.


1. Можно ли с произвольной ячейки таблицы Word попасть в начальную?
Да, можно. Вообще говоря, мне представляется возможным создание таблиц двумя наиболее простыми путями. В одном из них, в случае, когда таблица представляет собой фиксированный набор столбцов, будет полезен следующий алгоритм. Мы можем получить доступ к информации о количестве столбцов и строк в таблице, используя следующие свойства: ActiveDocument. Tables(1).Columns.Count — это счетчик столбцов в таблице, и ActiveDocument.Tables(1).Rows.Count — счетчик строк. Как видно из записи, есть возможность обращаться к таблицам внутри документа по их порядковому номеру, таким образом, используя эти значения и возможность передвинуть курсор методом Move. Их, этих методов, существует достаточно много. Как правило, для решения большинства типовых задач они подходят. Нас вполне удовлетворит код наподобие этого:

Unit_:=wdCell;
Count:=-3;//отрицательное значение этой переменной означает, что перемещение курсора должно происходить к началу документа
If WordApp.Selection.Information(wdWithInTable) = True Then Selection.Move(Unit_, Count);
End

2. Как вывести документ на печать?
Также нет ничего сложного. Следующая часть кода отсылает на принтер весь документ с количеством копий, равным единице.

FileName:="";
Range:=wdPrintAllDocument;
Item:=wdPrintDocumentContent;
Copies:=1;
Pages:=""; PageType:=wdPrintAllPages;
Collate:=True; Background:=True;
PrintToFile:=False;
PrintZoomColumn:=0; PrintZoomRow:=0; PrintZoomPaperWidth:=0;PrintZoomPaperHeight:=0;
WordApp.ActivePrinter = "Epson FX-1050";
WordApp.PrintOut(FileName, Range, Item, Copies, Pages, PageType, Collate, Background, PrintToFile, PrintZoomColumn, PrintZoomRow, PrintZoomPaperWidth, PrintZoomPaperHeight);

3. Как можно выравнивать столбцы и ячейки в таблицах?
Насколько я могу понять, вопрос о том, как выравнивать текст в ячейках таблицы. После того, как курсор программно установлен в соответствующую ячейку, используем следующий код для выставления типа выравнивания текста в ячейке:

WordApp.Selection.ParagraphFormat.Alignment:= wdAlignParagraphCenter
WordApp.Selection.ParagraphFormat.Alignment:= wdAlignParagraphRight
WordApp.Selection.ParagraphFormat.Alignment:= wdAlignParagraphLeft

Данный код выравнивает содержимое ячейки по центру, по правому краю и по левому соответственно.
Кроме того, подозреваю, что понадобится это дело оптимизировать, так как выставлять каждый раз тип выравнивания в таблицах по 30-40 строк и по 7-8 столбцов будет слишком утомительно. Воспользовавшись таким прекрасным свойством, как выделение нескольких строк и/или столбцов, можно выставить выравнивание сразу серии ячеек:

Unit_:=wdLine; Count:=2; Extend:=wdExtend;
WordApp.Selection.MoveDown(Unit_, Count, Extend);
WordApp.Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter;

Тут мы сначала выделили небольшой фрагмент таблицы, а точнее три ячейки одного столбца со сдвигом вниз (Count:=2; и Selection.MoveDown). Новый параметр Extend, который в первой части статьи мы просто игнорировали, теперь нам пригодился — он определят тип передвижения курсора, с выделением или без.
Если же есть необходимость увеличить или, наоборот, уменьшить ширину столбцов, подойдет ниже описанный вариант. Вообще, интуитивно просто предположить, что, как и в структуре языка Object Pascal (да и в других тоже), достучаться до значения ширины столбца можно, обратившись к конкретному столбцу конкретной таблицы и прочитав или присвоив этому свойству некоторое значение. Таким образом, запись

WordApp.Selection.Tables.Item(1).Columns.Item(1).Set_Width(105);

решает большинство проблем, которые могут возникнуть на пути изменения ширины столбцов. Мы выбрали в документе первую по порядку таблицу, затем ее первый столбец и установили его длину равной 105 единиц.
А как же объединять ячейки в таблице? Как насчет пресловутого "итого" в конце документа, которому, как всегда, причитается больше всех? Обратимся немного выше по тексту к тому месту, где говорилось о выравнивании информации в ячейках. Нам понадобится тот же механизм выделения, только после его применения необходимо будет использовать метод WordApp.Selection.Cells.Merge, который объединит выделенные ячейки в одну.

MS Excel 2000. Теперь же перейдем к формированию отчетов в MS Excel 2000.
В работе с редактором электронных таблиц нет практически ничего нового в сравнении с текстовым процессором MS Word. Тем не менее, иногда приходится пользоваться именно этим редактором таблиц.
Пробежимся по основным моментам работы с этим сервером автоматизации из Delphi 5. Рассмотрим передачу данных серверу автоматизации, обрамление таблиц рамками, вставку в ячейки формул для расчетов и переименование листов.
Итак, после того, как вы поместили на форму компоненты TExcelApplication и TЕxcelWorkbook, установив свойства автоматического подключения к СОМ-серверу в значение true, займемся обработчиком передачи данных из приложения в MS Excel. Для начала необходимо выбрать некоторую ячейку, куда и будем передавать данные. Делается это посредством метода Select:

ExcelApplication.Range['D6','D6'].Select;
ExcelApplication.ActiveCell.FormulaR1C1:='10';

Данный пример кода вставляет значение "10" в ячейку D6. Таким способом можно заполнять ячейки не только просто значениями, но и формулами. В этом случае вычисление, скажем, итоговых значений перекладывается с приложения на плечи сервера автоматизации. Как готовый пример сначала занесем несколько значений в ячейки листа рабочей книги, а потом вычислим две формулы с использованием этих данных. Примерный код приведен ниже:

ExcelApplication.Range['A1','A1'].Select;
ExcelApplication.ActiveCell.FormulaR1C1:='1';
ExcelApplication.Range['A2','A2'].Select;
ExcelApplication.ActiveCell.FormulaR1C1:='2';
ExcelApplication.Range['A3','A3'].Select;
ExcelApplication.ActiveCell.FormulaR1C1:='3';
ExcelApplication.Range['A4','A4'].Select;
ExcelApplication.ActiveCell.FormulaR1C1:='4';
ExcelApplication.Range['A5','A5'].Select;
ExcelApplication.ActiveCell.FormulaR1C1:='5';
//последовательно заносим значения в первый столбец
//теперь переходим к новой ячейке для введения формулы
ExcelApplication.Range['A7','A7'].Select;
ExcelApplication.ActiveCell.Formula:='Сумма:';
ExcelApplication.Range['B7','B7'].Select;
ExcelApplication.ActiveCell.Formula:='=SUM(A1:A5)';
//записали в ячейку значение, полученное применением системной функции самого Excel
ExcelApplication.Range['A9','A9'].Select;
ExcelApplication.ActiveCell.Formula:='Выражение:';
ExcelApplication.Range['B9','B9'].Select;
ExcelApplication.ActiveCell.Formula:='=(A1+A2)*2+A3-A5+A4';
//записали в ячейку выражение, полученное в результате работы произвольной пользовательской функции.

Результатом работы программы будет вот такой лист в рабочей книге:
Теперь попробуем заключить наши исходные данные в ячейках А1-А5 в рамку и закрасить эти ячейки каким-нибудь цветом, например синим. Результаты же работы функций вместе с названиями также объединим рамками — фактически заключим в рамку несколько ячеек. Сделать это так же просто, как и работать с таблицами в MS Word. Для начала нам необходимо выделить набор ячеек. Затем обратиться к методу BorderAround и передать ему параметры на создание обрамления ячеек тонкой ярко-синей линией. После этого мы закрасим выделенные ячейки синим цветом, а шрифт сделаем желтым.

LineStyle:=6;
Color:=41;
ExcelApplication.Range['A1','A5'].BorderAround(LineStyle,5,41,Color);
//две переменные типа OleVariant были специально введены для того, чтобы избежать ошибок взаимодействия приложения и сервера автоматизации. До конца механизм возникновения ошибок не известен, так как Microsoft не очень-то охотно делится своими разработками.

Эти переменные отвечают за передачу типа линии, ее цвета соответственно. Второй параметр, равный пяти, в процедуре отвечает за толщину рисуемой линии.
Теперь закрасим ячейки с нашими исходными данными и поменяем цвет шрифта на желтый. Закрашиваем синим пять ячеек:

ExcelApplication.Range['A1','A5'].Select;
With ExcelApplication.Selection.Interior do
begin
ColorIndex = 1;
Pattern:= xlSolid;
end;//поменяли заливку цветом
ExcelApplication.Range['A1','A5'].Select;
ExcelApplication.Selection.Font.ColorIndex:= 6 //поменяли цвет шрифта на желтый

Нам осталось только сделать маленькую процедуру, которая будет переименовывать активный лист Excel в открытой книге по вашему желанию.

ExcelApplication.Sheets('Лист1').Name = 'Наше новое название';

После чего название листа в левом нижнем углу экрана изменится на вновь установленное.
Теперь время перейти к работе с приложением MS Outlook. Как много раз уже говорилось, каждое приложение Офиса представляет собой сервер автоматизации. Получив доступ к серверу автоматизации, мы также получаем доступ к множеству методов и свойств этого сервера. Кроме того, удобство такой системы доступа способствует лучшему пониманию программистом способов реализации поставленной задачи. Так как в проектировании серверов автоматизации применяется объектный подход, мы можем получить любой параметр простым перечислением его предков через точку — как и в объектно-ориентированном языке программирования. Насколько это бывает удобно, вы знаете сами. Еще более удобным это становится, если учесть структуру программы MS Outlook и структуру хранения данных в ней.
Так же, как и в других серверах, в Outlook имеется базовый класс Application, в который встраивается класс NameSpace. Класс NameSpace через объект класса MAPIFolders предоставляет доступ к данным, которые представляют собой простую коллекцию папок пользователя. Значит, получив доступ к серверу автоматизации через компоненту OutlookApplication, можно извлечь объект доступа к самим MAPI папкам.

Mapi:=OutlookApplication.GetNameSpace('Mapi');
For i:=0 to Mapi.Folders.Count — 1 do
FoldersListBox.Items.Add(Mapi.Folders.Item[i].Name);

Добраться до соответствующей папки теперь не составит большого труда, так как, как я уже не раз повторял, мы имеем дело с вложенными объектами.
Следующий пример производит рассылку писем по адресам, которые извлекаются из базы данных. Нельзя сказать, что он очень хорош — над ним надо еще поработать, чтобы привести его в более "товарный" вид.

procedure TForm1.SendButtonClick(Sender: TObject);
var
mapi:NameSpace;
begin
Table1.Active:=false;
Table1.Active:=true;
//Получаем доступ к папке
mapi:=OutlookApplication1.GetNamespace('MAPI');
while not Table1.Eof do
begin
//Подключаем объект класса TMailItem к новому элементу исходящих писем, для работы через Vtable интерфейс
MailItem1.ConnectTo(_DMailItem(mapi.Folders.Item(olPersonal). Folders.Item(olFolderOutbox). Items.Add(olPostItem) as iDispatch));
//Наполняем новое письмо информацией
MailItem1.Subject:='тестирование для '+Table1Common_Name.Value;
MailItem1.to_:=Table1Category.Value+'@elsite.ru';
Table1Graphic.SaveToFile(Table1SpeciesNo.AsString+'.BMP');
MailItem1.Attachments.Add(ExtractFilePath(Application.EXEName)+Table1SpeciesNo.AsString+
'.BMP',1,1,Table1SpeciesName.Value);
MailItem1.Body:=#13#13+'Письмо с вложенным документом '+#13+ MailItem1.SenderName;
MailItem1.Sensitivity:=olConfidential ;
MailItem1.FlagStatus:=olFlagMarked;
//Сохраняем письмо. OutLook самостоятельно его отошлет по почте
MailItem1.Save;
Table1.next;
end;
end;

Конечно, в одной статье невозможно все охватить, особенно когда это касается такой обширной темы, как описание работы с приложениями MS Office — одного из крупнейших программных пакетов. Однако написанного должно быть достаточно, чтобы начать самому разбираться во всех премудростях функционирования серверов автоматизации. Начальные сведения, полученные из этого материала, должны помочь вам в создании простейших приложений — контроллеров. Создание текстовых отчетов, чтение данных из файлов MS Word и MS Excel, импорт и экспорт данных из приложений MS Outlook и MS Outlook Express являются огромным рынком сбыта, до сих пор у нас еще не полностью востребованным. Зачастую, ввиду невозможности приобрести платные компоненты сторонних разработчиков, знания в этой ветви программирования практически не востребованы. И если на лицензионные продукты от Microsoft, такие как MS Office или MS Windows 98/2000, предприятие вынуждено будет раскошелиться из-за агрессивной политики компании-производителя, то попытка заставить начальство поверить в необходимость покупки дополнительных компонент, скорее всего, наткнется на обвинение в неспособности справиться с поставленной задачей.
В заключение хотелось бы еще раз подчеркнуть, что использование Vtable интерфейса значительно упрощает процесс разработки контроллеров автоматизации СОМ-серверов. С использованием мощного средства разработки, такого как Borland Delphi 5, и открытых интерфейсов серверов MS Office можно проектировать и строить очень большие, серьезные приложения, работающие совместно.

Денис Мигачев


Компьютерная газета. Статья была опубликована в номере 25 за 2002 год в рубрике программирование :: delphi

©1997-2024 Компьютерная газета