Разработка интегрированных прикладных программ (Меньшикова К. Г.) (548342), страница 3
Текст из файла (страница 3)
Необходимую информацию можно получить также из библиотеки типов сервера. В Delphi или C++ Builder для этого можно воспользоваться командой импорта библиотеки типов сервера, например, для Excel 2000 в списке библиотек можно увидеть строку: Microsoft Excel 9.0 Object Library. После ее выбора будут созданы файлы с описанием имеющихся объектов (для С++Builder файлы Excel_TLB.cpp и Excel_TLB.h, а для Delphi файл Excel_TLB.pas). Файлы размещаются в (системной) папке, например, C:\ ProgramFiles\ Borland\ Delphi6\ Imports.
Для управления серверами удобнее всего воспользоваться компонентами визуальной библиотеки. Однако для этого требуется предварительное знакомство с офисными объектами и проведение программных экспериментов.
3.1.MS Excel и компоненты библиотеки VCL
С++Builder и Delphi поддерживают работу со многими распространенными приложениями, предлагая программистам соответствующие компоненты. Офисные компоненты чаще всего располагаются на странице Servers (хотя возможно, что в названии используется номер офисной версии). В любом случае при разработке сложных приложений надо решить вопрос совместимости версий Windows, Microsoft Office и инструментариев разработки, иначе переносимость таких приложений может быть очень ограничена.
Компонент ExcelApplication задает приложение Excel, его свойства, методы и события характеризуют приложение в целом. Его свойство Workbooks определяет коллекцию рабочих книг (все открытые в приложении рабочие книги).
Компонент ExcelWorkbook задает рабочую книгу и, в свою очередь, имеет свойство Worksheets – все рабочие листы книги. Компонент Worksheet – это конкретный лист рабочей книги.
Установить связь с физическим объектом можно так:
ExcelApplication1->Connect();
ExcelWorkbook1-> ConnectTo (ExcelApplication1 ->
ActiveWorkbook);
ExcelWorksheet1 -> ConnectTo (ExcelWorkbook1->
ActiveSheet);
ExcelWorksheet2 -> ConnectTo (ExcelWorksheet1 ->
get_Next());
Для вызова некоторых методов и свойств используется специальная константа - LOCALE_SYSTEM_DEFAULT (lcid); ее значение равно 0. Например, можно сделать окно Excel видимым (или невидимым, если параметр равен false):
#define lcid LOCALE_SYSTEM_DEFAULT
ExcelApplication1->set_Visible(lcid,true);
При работе с коллекцией Workbooks можно обращаться к ее свойствам, например, узнать количество открытых книг
int n= ExcelApplication1-> Workbooks-> Count;
и методам, например, открыть и добавить новую книгу
WideString filename="d:/work.xls";
ExcelApplication1->Workbooks->Open(filename);
ExcelApplication1->Workbooks -> Add();
Сохранить рабочую книгу или сделать рабочий лист активным можно с помощью соответствующих компонент:
ExcelWorkbook1->Save(lcid);
ExcelWorksheet2 ->Activate (lcid);
При работе с офисными компонентами используется раннее связывание. Компилятор, конечно, четко отслеживает типы передаваемых параметров. Однако иногда необходимо или удобно его “обмануть”, упаковав данные в формат TVariant. Например, зададим имена листов:
WideString str; str="MyList 1";
ExcelWorksheet1->set_Name(str);
ExcelWorksheet2->set_Name((TVariant)"MyList 2");
Работа с ячейками таблицы
Одна из ячеек таблицы является активной и с ней можно работать отдельно. Например, можно записать значение:
ExcelApplication1->ActiveCell->set_Value((TVariant)"a");
В Excel ячейки таблицы рассматриваются как двумерный массив Cells(,). Для получения доступа к этому массиву в Builder C++ используется метод get_Cells().
С помощью методов set_Item(, , ) и get_Item(, ) можно записывать и извлекать значения элементов с указанными индексами. Например:
// число 222 записывается в ячейку с номерами (1,1):
ExcelWorksheet2 -> get_Cells()->
set_Item((TVariant)1,(TVariant)1,(TVariant)"222");
// для записи формулы используется функция:
ExcelWorksheet2 -> get_Cells()->
set_Item((TVariant)5,(TVariant)1,(TVariant)
"=СУММА(A1:A3");
// из ячейки (1,4) извлекается значение:
k = (TVariant)ExcelWorksheet2 -> get_Cells()->
get_Item((TVariant)1,(TVariant)4);
Объект Range рабочего листа ExcelWorksheet предоставляет удобный доступ к таблице и позволяет работать с ячейкой таблицы, диапазоном ячеек, прямоугольной областью. Приведем примеры его использования:
// в ячейку B1 занести число 4:
ExcelWorksheet1->get_Range((TVariant)"B1",
(TVariant)"B1")->set_Value((TVariant)4);
// в ячейки с3-с6 записать формулы:
ExcelWorksheet2->get_Range((TVariant)"с3",(TVariant)"с6") -> set_Value((TVariant)"=a3+b3");
Когда формула присваивается диапазону ячеек, то переменные в формуле имеют относительные имена, поэтому в предыдущем примере в ячейку c4 будет вписана формула “=a4 +b4” и т.д.
// Получение значения из ячейки b5:
TVariant y; y=ExcelWorksheet2->get_Range((TVariant)"b5",
(TVariant)"b5") -> get_Value();
// Удаление содержимого диапазона ячеек:
ExcelWorksheet2 -> get_Range
((TVariant)"D1",(TVariant)"D3") -> Clear();
// Копирование через буфер обмена:
ExcelWorksheet2 -> get_Range
((TVariant)"A1",(TVariant)"B3") -> Copy();
ExcelWorksheet2 -> get_Range
((TVariant)"A7",(TVariant)"B9") -> Select();
ExcelWorksheet2 -> Paste();
При переходе от одного объекта Range к другому, например от одной ячейки к другой, отстоящей от первой на определенное расстояние, можно использовать смещение. Достигается это благодаря методу Offset объекта Range. Метод имеет два параметра: смещение по строкам и столбцам, и возвращает новый объект Range, отстоящий от прежнего на заданное расстояние.
Например, следующий оператор задает запись в ячейку, отстоящую от “b5” на (–1, 3), то есть в ячейку “e4”:
ExcelWorksheet2-> get_Range ((TVariant)"b5",
(TVariant)"b5") -> get_Offset ((TVariant)-1,(TVariant)3)
->set_Value((TVariant)"=b5+d4");
Оформление ячеек таблицы можно выполнить так:
// выделение курсивом
ExcelWorksheet2 -> get_Range ((TVariant)"A1", (TVariant)"E5")->get_Font()->set_Italic((TVariant)true);
// выравнивание
ExcelWorksheet2->get_Range ((TVariant)"D1", (TVariant) "E3")-> set_HorizontalAlignment((TVariant)xlCenter);
// изменение цвета букв:
ExcelWorksheet2 -> get_Range((TVariant)"D1", (TVariant) "E3")-> get_Font()-> set_Color((TVariant)0x00FF0000);
// заливка цветом:
ExcelWorksheet2 -> get_Range((TVariant)"A1",(TVariant) "B7")-> Interior-> set_Color((TVariant)RGB(0,128,200));
Работа с сервером Word организуется аналогичным образом. Среди основных компонент - WordApplication, WordDocument, WordFont и WordParagraphFormat. Примеры работы с ними можно найти в [1].
3.2.Серверы MS Office и позднее связывание
Приложения Microsoft Office созданы с соблюдением всех правил COM и поэтому обладают рядом свойств, обязательных для серверов автоматизации. Подробный перечень свойств можно найти в [3]. В табл. 1 перечислены только обязательные свойства и методы.
Таблица 1. Обязательные свойства и методы объекта втоматизации
Имя | Чтение, запись | Тип | Смысл |
Application | Только чтение | IDispatch | Приложение |
FullName | Только чтение | WideString | Путь и имя приложения |
Name | Только чтение | WideString | Краткое описание приложения |
Parent | Только чтение | IDispatch | То же, что и свойство Application |
Visible | Чтение и запись | WordBool | Видимость окна приложения |
Quit | Метод | Закрытие приложения |
В общем случае любой контроллер автоматизации (не только для офиса) должен проверить, запущена ли уже копия приложения-сервера, и решить, запускать ли новую копию или подключиться к имеющейся. После окончания работы с сервером закрыть приложение (если сервер был запущен контроллером) или отключиться от него. Рассмотрим программный код, который позволяет это сделать.
Создадим в C++Builder новое приложение с двумя кнопками (Button1-> Caption=Connect и Button2-> Caption=Disconnect). Включим в текст строку #include
Объявим логическую переменную, которая будет помнить, запустил ли контроллер приложение-сервер (true) или подключился к работающей копии (false): bool RunServer;
Вариантные переменные будут представлять в контроллере объекты сервера (приложение и коллекцию рабочих книг): Variant App, WorkBs;
Код обработчика первой кнопки попытается связаться с запущенной копией сервера, передав в качестве параметра строку, содержащую имя объекта автоматизации (ProgID – программные идентификаторы содержатся в реестре и независимы от версии). При неудаче возникнет системное исключение и тогда контроллер сам создаст объект автоматизации:
void __fastcall TForm1::Button1Click(TObject *Sender)
{AnsiString AppProgID;
AppProgID="Excel.Application";
RunServer=False;
if (VarType(App)!=varDispatch)
{ try
{App=GetActiveOleObject(AppProgID);}
catch (EOleSysError&)
{App=CreateOleObject(AppProgID);RunServer=true;} }
if (VarType(App)==varDispatch)
{ App.OlePropertySet("Visible",true);
WorkBs=App.OlePropertyGet("Workbooks");
WorkBs.OleProcedure("Add"); } }
Вторая кнопка закроет сервер (если контроллер его сам стартовал) и освободит указатели на все полученные интерфейсы:
void __fastcall TForm1::Button2Click(TObject *Sender)
{ if (RunServer) App.OleProcedure("Quit");
WorkBs=NULL; App=NULL; }
Если окно сервера видимо, то пользователь может непредсказуемо вмешаться в совместную работу приложений. Поэтому при создании контроллеров таких приложений не рекомендуется давать доступ конечному пользователю к интерфейсу сервера. Проще всего этого достичь, установив свойство Visible=false, а чтобы сервер не выводил на экран диагностические сообщения для пользователя, то установить свойство DisplayAlerts=false.
3.3.Контроллер на C++ Builder (позднее связывание)
Для организации позднего связывания контроллера с сервером MS Excel, естественно, понадобятся переменные типа Variant: AppE (объект Application), Workbs (коллекция рабочих книг), Workb (рабочая книга), Workshs (коллекция листов рабочей книги), Worksh (рабочий лист), work (ячейка таблицы). После создания приложения (объект Application) AppE=CreateOleObject ("Excel.Application"); с помощью метода OlePropertyGet можно получить доступ к другим объектам MS Excel:
Workbs=AppE.OlePropertyGet("Workbooks");
Workb=Workbs.OlePropertyGet("Item",1);
Workshs=Workb.OlePropertyGet("Worksheets") ;
Worksh=Workshs.OlePropertyGet("Item",2);
Для добавления нового объекта к коллекции (например, рабочей книги) используется процедура Add, для вызова которой придется использовать метод OleProcedure: Workbs.OleProcedure("Add");
Для изменения свойств используется метод OlePropertySet:
AppE.OlePropertySet("Visible",true);
Workshs.OlePropertyGet("Item",1).OlePropertySet ("Name","Исходная таблица");
Доступ к ячейкам таблицы организуется совместной работой методов:
// запись значения в ячейку (числа или формулы)
Worksh.OlePropertyGet("Cells").OlePropertyGet
("Item",3,1).OlePropertySet("Value",-34);
Worksh.OlePropertyGet("Cells").OlePropertyGet
("Item",11,1).OlePropertySet ("Value","=СУММ(A1:A10)");
// оформление ячейки таблицы
work=Worksh.OlePropertyGet("Cells").OlePropertyGet
("Item",3,2);
work.OlePropertyGet("Font").OlePropertySet
("Color",clBlue);
work.OlePropertyGet("Font").OlePropertySet
("Bold",true);
Для организации позднего связывания c MS Word также понадобятся переменные типа Variant: AppW (объект Application), WordDs (коллекция документов WordDocuments), WordD (документ Document), WordPars (коллекция Paragraphs), Rng (объект Range).
После создания приложения-сервера AppW=CreateOleObject ("Word.Application"); доступ к его свойствам (среди свойств есть и такие, которые представляют коллекции других объектов) можно получить через функцию OlePropertyGet:
WordDs=AppW.OlePropertyGet("Documents");
WordD=AppW.OlePropertyGet("ActiveDocument");
WordPars=WordD.OlePropertyGet("Paragraphs");
Для установки значений свойств используется OlePropertySet:
AppW.OlePropertySet("Visible",true);
AppW.OlePropertySet("Width",200);
Для доступа к конкретному объекту коллекции документов или параграфов используется функция OleFunction, а для создания новых объектов необходимо использовать метод OleProcedure, например:
WordD = WordDs.OleFunction ("Item",2);
WordDs.OleProcedure("Add");
WordPars.OleProcedure("Add");
Для работы с документом потребуется сочетание перечисленных функций и методов:
//получение количества документов и активизация документа
int j=(int) (WordDs.OlePropertyGet("Count"));
WordD =WordDs.OleFunction ("Item",2).OleProcedure
("Activate");
// доступ к частям документа
Rng=WordD.OleFunction("Range",10,15);
Rng= WordPars.OleFunction ("Item",1).
OlePropertyGet("Range");
// вставка текста в документ
Rng.OleProcedure("InsertBefore","Текст 1");
WordPars.OleFunction("Item",1).OlePropertyGet("Range").
OleProcedure("InsertAfter","Текст 33");
// изменение цвета букв
Rng.OlePropertyGet("Font").OlePropertySet("Color",clRed);
3.4.Работа с серверами из Delphi (позднее связывание)
При создании контроллеров позднего связывания на Delphi следует обратить особое внимание на различия в синтаксисе обращений к членам коллекций объектов Excel и Word: в случае MS Word используется метод Item, в Excel члены коллекции рассматриваются как элементы массивов. В предыдущем параграфе было показано, что в С++Builder различие офисных серверов сказалось на использовании различных функций.
При работе с MS Excel доступ к объектам можно организовать так:
AppE:=CreateOleObject('Excel.Application');
WorkBs:=AppE.Workbooks;
WorkSh:=AppE.Workbooks[1].WorkSheets[2];
WorkSh:=AppE.ActiveWorkBook.WorkSheets[2];
Методы серверных объектов можно вызывать обычным образом: