Разработка многомодульных интегрированных SDI-приложений (3. OLE - технология)

Посмотреть архив целиком

OLE -технология

OLE – технология (Object Linking and Embedding – объектное связывание и встраивание) позволяет создавать сложные составные документы, в которых содержатся разнотипные объекты, созданные различными приложениями. Так в текстовый документ редактора Word можно вставить таблицу Excel, диаграмму, поясняющую текст, или математическую формулу, для пользователя это останется единым документом. Приложение, отвечающее за составной документ, принято называть контейнером. Оно имеет сложную структуру, так как умеет работать с “чужими” объектами. Приложение, создавшее объект, называется сервером.

Контейнеры и серверы могут поддерживать два режима взаимодействия:

  • встраивание (внедрение) объектов. Этот режим означает, что данные объекта будут храниться вместе с основным документом (например, внедренная таблица Excel будет сохранена в .doc – файле редактора Word).

  • связывание объектов. В составном документе хранится только ссылка на объект, данные которого находятся в другом документе.

При внедрении увеличивается объем хранимых документов, однако, их легче перемещать, тогда как при связывании, необходимо помнить, что изменение места расположения файлов может привести к ошибочным ссылкам.

Для редактирования связанных данных открывается отдельное окно, того приложения, в котором эти данные были созданы, т.е. сервера. При внедрении объектов можно также запустить сервер в отдельном окне, но можно и редактировать данные «на месте» («in Place»), т.е. в окне контейнера, если он это позволяет. В этом случае контейнер обязан иметь меню, а загрузившийся «in Place»сервер дополнит его своими командами.

Компонент OLEContainer

На странице System палитры компонент в Borland Builder С++ есть специальный компонент , предназначенный для внедрения и связывания объектов из других приложений - OLEContainer.

Основные свойства

Свойство State позволяет определить состояние объекта и его сервера. Его значения:

  • osEmpty –контейнер не содержит объекта;

  • osLoaded – объект в контейнере, сервер не выполняется;

  • osRunning – сервер запущен;

  • osOpen – OLE –объект открыт в отдельном окне сервера;

  • osInPlaceActive – объект активизирован «на месте», но меню еще не изменено. Это промежуточное состояние объекта перед полной загрузкой сервера.

  • osUIActive объект активизирован «на месте», меню изменено.


Следующий код позволяет определить имя объекта, загруженного в контейнер (свойство AnsiString OleClassName), способ работы с объектом (Linked = true – связывание, иначе – внедрение), а также получить имя связанного документа:

if (OleContainer1 -> State != osEmpty)

{

Label2 -> Caption = OleContainer1 -> OleClassName;

// Состояние контейнера – целое число, начиная с 0 (osEmpty)

Label6 -> Caption = OleContainer1 -> State;

if ( OleContainer1 -> Linked)

Label4 -> Caption = OleContainer1 -> SourceDoc;

}


Свойство bool AllowInPlace определяет возможность редактировать внедренный объект «на месте». Если AllowInPlace = true и Iconic = false (свойство Iconic определяет должен ли объект быть представлен в виде пиктограммы), то «InPlace» – редактирование разрешено. При AllowInPlace = false сервер будет открываться в отдельном окне.


Свойство AutoActivate имеет три возможных значения: aaManual, aaGetFocus, aaDoubleClick и определяет способы активизации загруженного в контейнер объекта.

По умолчанию AutoActivate = aaDoubleClick, то есть объект становится активным при двойном щелчке. Значение aaGetFocus определяет активизацию при получении фокуса ввода. При AutoActivate = aaManual за активизацию объекта отвечает программист. В этом случае можно использовать метод компонента-контейнера DoVerb, который отвечает за передачу команд от контейнера серверу. Например, можно воспользоваться следующим оператором:

OleContainer1->DoVerb (ovShow); // Показать объект

Кроме посылки команд серверу, методы контейнера обеспечивают создание, загрузку и разрушение объектов. Перейдем к их рассмотрению.

Создание и сохранение нового объекта (внедрение)

Создание нового объекта можно обеспечить использованием специального диалогового окна Insert Object (вставка объекта) или вызовом метода CreateObject. В первом случае класс объекта выбирает пользователь из системного списка возможных объектов, а во втором программно создается конкретный объект.

Для использования диалогового окна можно воспользоваться следующим кодом, расположенным, например, в команде меню «новый»:

AnsiString File_Name; // переменная объявлена глобально или в классе формы

if (OleContainer1->InsertObjectDialog() )

{ File_Name = "";

OleContainer1->DoVerb(ovShow);

}

В появившемся диалоговом окне необходимо установить значение RadioButton - кнопки «Создать новый», в списке выбрать необходимый тип объекта и щелкнуть «OK».

Программно объект можно создать так (операторы можно вставить, например, в соответствующие пункты меню):

  • таблица Excel

OleContainer1->CreateObject("Excel.sheet",false);

  • документ Word

OleContainer1->CreateObject("Word.Document",false);


Если создать нужно объект, имя типа которого неизвестно, то нужно обратиться либо к соответствующей документации по серверу, либо написать тестовую программу с загрузкой объекта методом OleContainer->InsertObjectDialog() и воспользоваться свойством OleContainer -> OleClassName для определения его имени.

При создании нового объекта используется внедрение (так как для связывания необходим файл). В этом случае за хранение данных объекта отвечает программа - контейнер. Сохранить данные в файле можно с помощью метода SaveToFile (<имя файла>), например, в пункте меню «Файл - Сохранить…» можно использовать следующий код:

void __fastcall TForm1::FSaveClick(TObject *Sender)

{ if (File_Name=="")

if ( SaveDialog1->Execute() )

File_Name = SaveDialog1->FileName;

else return;

OleContainer1->SaveToFile(ChangeFileExt(File_Name,".ole"));

}

В данном примере расширение файла .ole указывает на то, что объект будет сохранен в специальном формате отличном от формата сервера. Приложение - сервер отдельно от контейнера прочесть эти данные не сможет.

Функция ChangeFileExt была использована в примере для замены расширения файла. При выполнении команд сохранения и извлечения данных из файла могут понадобиться и другие функции обработки имен файлов:

  • ChangeFileExt(const AnsiString FileName, const AnsiString Extension) – принудительно изменяет имя файла FileName, заменяя расширение на Extension;

  • функция AnsiString ExtractFileExt(AnsiString FileName) возвращает расширение файла и, следовательно, позволяет проверить его тип;

  • AnsiString ExtractFileName(AnsiString FileName) возвращает имя файла, извлеченное из строки FileName, т.е. после последнего обратного слэша или двоеточия;

  • AnsiString ExtractFilePath(AnsiString FileName) извлекает путь к файлу, включая последний слэш или двоеточие;

  • AnsiString ExtractFileDrive(AnsiString FileName) извлекает диск файла с двоеточием (например, «D:»).


Метод контейнера LoadFromFile(<имя файла>) позволяет загрузить запомненный объект в контейнер:

void __fastcall TForm1::FOpenClick(TObject *Sender)

{

if ( OpenDialog1->Execute() )

{

if (ExtractFileExt(OpenDialog1->FileName)!= ".ole")

return;

File_Name = OpenDialog1->FileName;

OleContainer1->LoadFromFile(File_Name);

OleContainer1->DoVerb(ovShow);

}

}

Создание объекта из файла (внедрение)

Для создания объекта из имеющегося файла можно воспользоваться тем же окном Insert Object, как и в случае создания нового объекта. В случае внедрения пользователь устанавливает значение RadioButton-кнопки «Создать из файла», а для поиска файла щелкает на кнопке «Обзор…».

Программный способ создания объекта из файла обеспечивается методом: OleContainer-> CreateObjectFromFile (AnsiString <имя файла>, bool Iconic).

Параметры методы определяют имя исходного файла и режим отображения объекта (Iconic=true – объект в виде пиктограммы). Вот такой код можно вставить в соответствующий пункт меню:

void __fastcall TForm1::FFileClick(TObject *Sender)

{

if ( OpenDialog1->Execute() )

{

OleContainer1->CreateObjectFromFile(OpenDialog1->FileName,false);

OleContainer1->Repaint();

}

}

Метод OleContainer->Repaint() приводит к перерисовке окна контейнера и, следовательно, появлению данных объекта на экране.

Создание связанного объекта

Так же как и при внедрении создать связанный объект может или пользователь или программист.

Пользователю в окне Insert Object следует выполнить действия по выбору файла, перечисленные выше, и дополнительно установить флажок «Связь».

Программист должен воспользоваться методом: OleContainer->CreateLinkToFile (AnsiString <имя файла>, bool Iconic).

Поскольку при связывании редактировать объект можно только в отдельном окне, то для сохранения объекта пользователь может обратиться к меню сервера.

Работа с сервером

Поскольку работать с данными объекта может только программа создавшая объект (сервер), то контейнеру могут потребоваться знания о возможных действиях над объектом. Метод DoVerb (int Verb) требует выполнения одной из команд, а весь список возможных действий содержит свойство ObjectVerbs компонента контейнера. Получить этот список можно только после загрузки объекта в контейнер, и, естественно, что каждый сервер (а, следовательно, и объект) имеет свой список команд.

Константа ovShow – это пример зарезервированной OLE – команды. Использование метода DoVerb с параметром ovShow, которое было уже рассмотрено в одном из предыдущих разделов, приводит к немедленному открытию сервера.

Следующий код проявляет список возможных команд объекта в компоненте ListBox (команды нумеруются с нуля) и просит выполнить вторую команду в списке:

ListBox1->Items = OleContainer1->ObjectVerbs;

OleContainer1->DoVerb(1);

Кроме этого контейнер может попросить сервер сохранить данные объекта в виде документа в формате сервера. Для этого используется метод SaveAsDocument(<имя файла>). Этот документ в дальнейшем может обрабатываться приложением сервером без участия контейнера. Интересно, что этот метод можно использовать как для связанных так и для внедренных объектов.

При завершении работы с объектом программа может освободить OleContainer, вызвав метод OleContainer->DestroyObject() - разрушить загруженный объект. Этот метод можно вызывать перед загрузкой нового объекта или в команде меню «Файл-Выход».

Задание

1. Создать новое приложение. На главной форме расположены следующие компоненты:

  • OleContainer

  • ListBox

  • Несколько элементов Label

  • MainMenu

И два невизуальных компонента:

  • OpenDialog

  • SaveDialog.

Примерный вид главного окна приложения представлен на рисунке. В OleContainer загружен рисунок (файл с расширением .bmp). Состояние сервера: osRunning.

2. Добавить на форму компонент, в котором будет отображаться информация об объекте: «не загружен» / «внедрение» / «связывание».

3. Меню должно содержать следующие команды:

  • «Файл» (Сохранить объект, Сохранить документ, Загрузить объект, Разорвать связь, Выход)




  • «Объект» (InsertDialog, новый объект Excel, новый объект Paint, внедренный из файла, внедренный из «имя презентации PowerPoint», связанный из файла, связанный из «имя документа Word», Выполнить команду);

  • «Свойства» (Свойства объекта, Команды сервера);

  • «Справка» (О программе).

Предусмотреть, чтобы пункты меню были доступны только в тот момент, когда соответствующие им действия могут быть выполнены. Например, пункт «Объект»| «Выполнить команду» может быть доступен только, если объект загружен в OleContainer, а в список ListBox помещен список доступных команд сервера.

4. Для всех команд меню создать соответствующие обработчики событий.

  • «Файл» | «Сохранить объект» - внедренный объект сохраняется в отдельном файле с расширением .ole;

  • «Файл» | «Сохранить документ» - объект сохраняется в документе сервера;

  • «Файл» | «Загрузить объект» - сохраненный объект загружается из ole – файла.


Случайные файлы

Файл
146973.rtf
55766.rtf
115216.rtf
48122.rtf
80641.rtf




Чтобы не видеть здесь видео-рекламу достаточно стать зарегистрированным пользователем.
Чтобы не видеть никакую рекламу на сайте, нужно стать VIP-пользователем.
Это можно сделать совершенно бесплатно. Читайте подробности тут.