Разработка интегрированных прикладных программ (Меньшикова К. Г.) (548342), страница 4
Текст из файла (страница 4)
WorkBs.Add; AppE.Quit;
AppE.Workbooks[2].Activate; AppE.WorkBooks[2].Close;
AppE.ActiveWorkBook.Close(True,'D:\Work1.xls');
Последний пример хорошо иллюстрирует еще одно преимущество позднего связывания. Метод Close на самом деле имеет несколько параметров, но поскольку компилятор в данном случае не проверяет правильность обращений контроллера, то можно закрыть рабочую книгу, используя параметры по умолчанию.
Задание свойств объектов не отличается от случая обычных компонентов AppE.Visible:=true; Worksh.Name:='Результаты';
К ячейкам таблицы можно обращаться как к элементам двумерного массива, а группу ячеек задает свойство Range:
Worksh.Cells[1,2].Value:=25;
Worksh.Cells[1,2].Font.Name:='Arial';
AppE.WorkBooks[1].WorkSheets[3].Range['B2:C4'].Value:='5';
В случае контроллера MS Word доступ к объектам выглядит несколько иначе:
WordDs:=AppW.Documents; WordD:=WordDs.Item(1);
WordPar:=WordD.Paragraphs.Item(3);
Перед вызовом методов объекта коллекции также приходится предварительно обращаться к методу Item:
AppW.Documents.Item(2).Activate;
Работа с текстом может осуществляться так:
// вставка текста после указанного абзаца
Rng:= AppW.ActiveDocument.Paragraphs.Item(1).Range;
Rng.InsertAfter(‘Новый текст’);
Rng.Copy; // копирование фрагмента текста
AppW.Documents.Item(1).Paragraphs.Item(2).Range.Paste;
// вставка текста после символов:
WordD.Range(6,8).InsertAfter('Текст 2');
4.Элементы управления ActiveX
4.1.Создание ActiveX на основе компонентов VCL
Для демонстрации создадим управляющий элемент на основе компонента TMonthCalendar:
-
открыть окно галереи объектов и создать пустую библиотеку, выбрав значок ActiveX Library на странице ActiveX. Сохранить проект (например, MC_Project.dpr);
-
добавить в созданную библиотеку элемент управления, выбрав значок ActiveX Control и заполнить поля диалогового окна ActiveX Control Wizard: VCL Class Name (выбрать TMonthCalendar), New ActiveX Name (предложено MonthCalendarX), Implementation Unit;
-
сохранить, скомпилировать проект и зарегистрировать ActiveX в реестре.
Для регистрации используется команда Run | Register ActiveX Server, и будет получено сообщение: Successfully registred ActiveX Server, ‘D:\ActiveX\Delphi – ActiveX\ MC_Project.ocx’. В папке проекта можно видеть, что кроме самого элемента ActiveX (файл MC_Progect.ocx), создана его библиотека типов (файл MC_Project.tlb).
4.2.Тестирование ActiveX
Лучшим средством для тестирования элементов управления являются инструментарии фирмы Microsoft, так как спецификация элементов управления создавалась, в первую очередь, в расчете на эти средства разработки. К тому же проверять работоспособность созданного элемента лучше в среде, отличной от среды его создания. Для созданного нами элемента можно использовать Visual Basic, Visual C++, а проще всего Visual Basic for Applications (Microsoft Word или Excel).
Тестирование с использованием VBA
-
Запустить Microsoft Excel (Word), создать и сохранить документ, войти в редактор VBA.
-
В окне проекта (Project) выделить имя документа и выбрать меню команду Insert | User Form.
-
В контекстном меню панели элементов (toolbox) выбрать команду Additional Controls и в открывшемся списке всех зарегистрированных управляющих элементов выбрать MonthCalendarX Control.
-
Поместить элемент управления на форму и в окне Properties изменить его свойства (при необходимости или для проверки).
-
В документе создать кнопку Button1 и в связанную с ней процедуру CommandButton1_Click добавить строку UserForm1.Show, проверить ее работу.
4.3.Создание активных форм
Активная форма (ActiveForm) – это способ создания ActiveX, содержащего несколько VCL-компонент. Можно использовать практически любые компоненты (исключением является TMainMenu). Создадим, например, в Builder C++ управляющий элемент, который будет по заданной дате определять день недели. Порядок создания почти такой же, как у обычного приложения:
-
в галерее объектов выбрать ActiveForm (страница ActiveX) и ввести имя создаваемого элемента (например, Day_AFX);
-
сохранить проект DayAFProj1 в отдельной папке;
-
разместить на форме компоненты Image1 (фоновая картинка), Edit1 (поле ввода даты), Label1 (поле для вывода дня недели), Label2 и Label3 – вспомогательные надписи;
-
в модуле формы Day_AFImpl1.cpp (в модуле .h объявлен класс TDay_AFX с базовым классом TActive Form) объявить символьный массив: char days[7][15] = {"Воскресенье ", "Понедельник", "Вторник", "Среда","Четверг", "Пятница", "Суббота "};
-
написать код обработчиков событий. Например, по щелчку на кнопке должен выводиться день недели для заданной даты:
void __fastcall TDay_AFX::Button1Click(TObject *Sender)
{ TDateTime dtDate = StrToDate(Edit1->Text);
Label1->Caption=(AnsiString)( days[dtDate.
DayOfWeek()- 1]);}
При создании окна управляющего элемента можно, например, вывести текущую дату и день недели:
void __fastcall TDay_AFX::ActiveFormCreate(TObject *Sender)
{Label1->Caption=(AnsiString)
(days[DayOfWeek(Date()) - 1]);
Edit1->Text=DateToStr(Date());}
После создания активную форму следует скомпилировать и зарегистрировать, как и обычный ActiveX.
Тестирование также можно провести как с любым ActiveX, а можно, например, сгенерировать в Builder C++ тестовую HTML-страницу и для ее отображения использовать Microsoft Internet Explorer. Для этого в меню выбрать команду Project | Web Deployment Options.
Добавление свойств и методов
К созданным элементам управления можно добавлять собственные свойства и методы, редактируя для этого библиотеку типов и добавляя в модули соответствующую реализацию. Для демонстрации этой возможности создадим, например, в Delphi новую активную форму с именем класса CountClickX. Разместим на форме кнопку Button1, надпись Label1 (Caption:=«Количество нажатий») и надпись Label2.
Пусть управляющий элемент запоминает и отображает число щелчков на Button1, а также посылает уведомление контейнеру о произведенном нажатии кнопки. Для посылки уведомлений необходимо добавить новый метод в интерфейс ICountClickXEvents, который содержит прототипы методов исходящего (нотификационного) интерфейса контейнера. В окне библиотеки типов выбрать данный интерфейс и, нажав кнопку New Method, ввести его имя (например, OnButton). На странице Parameters указать тип возвращаемого значения (Return Type) void и, если требуется, добавить (кнопка Add) параметры обработчика. Вызов OnButton следует добавить в код управляющего элемента, тогда процедура, отвечающая за щелчок на кнопке, может выглядеть следующим образом:
procedure TCountClickX.Button1Click(Sender: TObject);
var i :integer;
begin i:=StrToInt(Label2.Caption)+1;
Label2.Caption:=IntToStr(i);
if FEvents<>nil then FEvents.OnButton; end;
Данный метод увеличивает и визуализирует число щелчков, а также проверяет наличие реализации нотификационного интерфейса у клиента (контейнера). При наличии такой реализации вызывается метод OnButton.
Для добавления нового свойства воспользуемся тем же окном библиотеки типов и к интерфейсу IСountClickX добавим свойство Count (кнопка New Property). Щелкнув в редакторе библиотеки типов Refresh Implementation, получим заготовку методов и добавим в них необходимый код:
function TCountClickX.Get_Count: Integer;
begin Result:=StrToInt(Label2.Caption); end;
procedure TCountClickX.Set_Count(Value: Integer);
begin Label2.Caption:=IntToStr(Value); end;
При создании подобного элемента управления в среде Builder C++ код методов выглядит несколько сложнее. Например, функции для получения и записи значения свойства Count могли бы быть следующими:
STDMETHODIMP TClickCountCXImpl::get_Count(long* Value)
{ AnsiString s;
try
{s=m_VclCtl->Label2->Caption; *Value =StrToInt64(s); }
catch(Exception &e)
{return Error(e.Message.c_str(), IID_IClickCountCX); }
return S_OK; };
Свойству Count при создании был присвоен диспетчерский идентификатор 16, а для организации правильной обработки при задании нового значения свойства - проверяется соответствие идентификаторов:
STDMETHODIMP TClickCountCXImpl::set_Count(long Value)
{try { const DISPID dispid = 16;
if (FireOnRequestEdit(dispid) == S_FALSE)
return S_FALSE;
m_VclCtl->Label2->Caption=IntToStr(Value);
FireOnChanged(dispid); }
catch(Exception &e)
{return Error(e.Message.c_str(), IID_IClickCountCX);}
return S_OK; };
После компиляции и регистрации ActiveX можно закрыть проект, а затем перейти к проверке его работоспособности.
Тестирование элемента управления в Builder C++
С оздадим новое Builder-приложение (рис. 5). Командой Component | Import ActiveX Control поместим элемент управления на палитру компонент (по умолчанию он отобразится на странице ActiveX). После этого используем его как любой VCL-компонент (настроим свойства и создадим обработчики).
Рис. 5
Для проверки ActiveX создадим обработчик события OnButton, добавим в него код, учитывающий число полученных уведомлений, а также будем обнулять число щелчков в управляющем элементе, если оно достигнет какого-то критического значения (для проверки возьмем 10) путем изменения значения свойства Count. Вот код созданного обработчика:
void __fastcall TForm1::CountClickX1Button(TObject *Sender)
{ static int msg=0; msg++;
Label2->Caption=IntToStr(msg);
if (CountClickX1->Count ==10)
CountClickX1->Count=0; }
4.4.Динамическое создание элементов управления ActiveX
Наверное, работая в C++ Builder или Delphi с компонентом ActiveX, естественно поместить его сначала на палитру компонентов, а затем на форму. Однако иногда удобно создавать компоненты динамически, то есть в процессе выполнения программы.
Для примера создадим Windows-приложение и на его форме (Form1) разместим две кнопки (Button1 и Button2) и текстовую метку (Label1). Для размещения управляющего элемента требуется контейнер: экземпляр класса TOleControl. Для доступа к этому классу в код следует вставить строку #include , а затем определить класс-наследник:
class TConX: public ToleControl
{ protected: TControlData FControlData;
virtual void __fastcall InitControlData(void);
public: __fastcall TConX(TComponent* AOwner,
TWinControl* AParent, TRect Rect); };
В данном классе определен конструктор, метод InitControlData, который требуется переопределить, и область TСontrolData, в которую будут помещены данные о содержимом контейнера. В модуле формы определим указатель на экземпляр класса: TConX *tXObj; Конструктор созданного класса может выглядеть так:
__fastcall TConX::TConX(TComponent* AOwner,
TWinControl* AParent,TRect Rect): TOleControl(AOwner)
{ this->Parent=AParent; this->Visible=True;
this->Left=Rect.Left; this->Top=Rect.Top;
this->Width=Rect.Right-Rect.Left;
this->Height=Rect.Bottom-Rect.Top; }
Метод InitControlData вызывается из конструктора класса-предка (TOleControl), свойство ControlData запоминает адрес структуры с данными (GUID элемента управления ActiveX, ссылки на интерфейсы клиента и т.д.):
void __fastcall TConX::InitControlData(void)
{ TGUID AD= {0x12DAB429, 0x9BA1, 0x40A4,
{0x9A, 0xB8, 0x45,0x51, 0xE9, 0x51,0x9B, 0xFE}};
FControlData.ClassID=AD;
FControlData.EventCount=0;
FControlData.EventDispIDs=NULL;
FControlData.LicenseKey=NULL;
FControlData.Flags=0x00000000;
ControlData=&FControlData; }
Для примера взят GUID элемента управления, созданного нами ранее на основе активной формы (его CLSID можно найти в файле _TLB.h).
Обработчик кнопки Button1 отвечает за создание элемента управления:
void __fastcall TForm1::Button1Click(TObject *Sender)
{ TRect r; r.left=0; r.top=0; r.bottom=200; r.right=400; tXObj=new TConX(this,this,r); }
Результат работы приложения представлен на рис. 6. После инициализации можно обращаться к ActiveX, используя для этого свойство OleObject контейнера. Например, в Button2 получить имя (Caption) элемента управления:
{ if (tXObj!=NULL) { Label1->Caption = "Имя ActiveX: " +
tXObj ->OleObject.OlePropertyGet("Caption");}}
Рис. 6
5.Компонент OLEContainer
Технология OLE (Object Linking and Embedding – объектное связывание и встраивание) позволяет создавать сложные составные документы, в которых содержатся разнотипные объекты, созданные различными приложениями. На странице System палитры VCL-компонент есть специальный компонент, предназначенный для внедрения и связывания объектов из других приложений – OLEContainer.
Свойство State позволяет определить состояние объекта и его сервера (osEmpty – контейнер не содержит объекта, osLoaded – объект в контейнере, сервер не выполняется, osRunning – сервер запущен, osOpen – OLE-объект открыт в отдельном окне сервера, osInPlaceActive – объект активизирован «на месте», но меню еще не изменено, osUIActive – объект активизирован «на месте», меню изменено).