- •107 Методические указания «Программное обеспечение сетей эвм. Часть 4. Версия 2. Развитие схемы «клиент-сервер» в com и corba»
- •Введение
- •1.1. Необходимость использования компонент
- •1.2. Методы встраивания компонентов
- •1.3. Основы com
- •1.4. Типы компонентов
- •1.5. Размещение управляющих элементов при помощи cWnd
- •1.6. Использование директивы #import
- •1.7. Компоновка тестовой программы
- •1.7.1 О компонентах
- •1.7.2 Регистрация компонентов
- •1.7.3 Импортирование библиотеки типов
- •1.7.4 Определение членов cDemoClientView
- •1.7.5 Создание компонентов
- •1.7.6 Создание точек взаимодействия
- •1.7.7 Синхронизация параметров
- •1.7.8 Обработка событий от компонентов
- •1.7.9 Очистка
- •1.7.10 Шаблонный код
- •1.9. Индивидуальные задания на работу
- •2.1. Проект. Основные принципы
- •2.2. Как создать компонент
- •Шаг 2: Создание компонента:
- •2.3. Значения по умолчанию
- •2.5. Индивидуальные задания на работу
- •3.1. Cоздание сервера com
- •3.2. Использование com-объектов
- •3.3. Индивидуальные задания на работу
- •Лабораторная работа № 4. Использование atl
- •4.1 Создание dcom-сервера с использованием atl
- •4.1.1 Введение в atl
- •4.1.2 Что такое atl?
- •4.1.3 Разделение труда
- •4.1.4 Создание хранилища компонентов с помощью atl Com AppWizard
- •4.1.5 Вставка кода заглушки/прокси-объекта.
- •4.1.7 Atl com-карта
- •4.1.9 Класс cComModule
- •4.1.10 Язык скриптов реестра в atl
- •4.1.11 Распределенная com (dcom)
- •4.1.12 Dcom и службы nt
- •4.1.13 Структура службы nt
- •4.1.14 Основанный на службах nt сервер сом
- •4.1.15 Создание проекта при помощи atl
- •4.1.16 Добавление функциональных средств
- •4.1.17 Функция CacheQuotes (dcomServiceXdcomService.Cpp)
- •4.1.18 Функция GetQuote (dcomServiceXdcomService.Cpp)
- •4.2 Создание dcom сервера
- •4.3 Создание dcom клиента
- •4.4 Индивидуальные задания на работу
- •Лабораторная работа № 5. Разработка corba приложений
- •5.1. Конфигурирование
- •5.2. Порядок действий
- •5.3. Объектно-ориентированный анализ и моделирование
- •5.4. Описание и трансляция объектов
- •5.5. Создание сервера
- •5.6. Создание клиента
- •5.7. Отладка объектов
- •5.8. Индивидуальные задания на работу
- •Лабораторная работа № 6. Адаптер роа
- •6.1. Архитектура poa
- •6.2. Политики poa
- •Политика обработки запросов
- •6.3. Создание серверов на основе poa
- •6.4. Индивидуальные задания на работу
- •Лабораторная работа № 7. Прикладная задача связи
- •7.1. Постановка задачи
- •7.1.1. Сотовая станция
- •7.1.2. Телефоны
- •7.1.3. Система
- •7.2. Функционирование системы
- •7.3. Индивидуальные задания на работу
- •Лабораторная работа № 8. Работа по умолчанию
- •8.1. Сервер с сервантом по умолчанию
- •8.2. Индивидуальные задания на работу
- •Лабораторная работа № 9. Создание менеджеров сервантов
- •9.1. Менеджеры сервантов
- •ServantActivator
- •ServantLocator
- •9.2. И снова практика
- •9.3. Индивидуальные задания на работу
- •Лабораторная работа № 10. Сервис именования
- •10.1. Сервис для именования (Naming Service)
- •10.2. Индивидуальные задания на работу
2.3. Значения по умолчанию
У свойтва может быть значение default, то есть -
__property bool LEDOn = {read=FOnOff, write=SetOnOff, default=false};
Это значение НЕ то, что видно по умолчанию в object inspector (их вы должны задать в конструкторе компонента, мы займемся этим позже). Тут заложен другой смысл. Каждый раз при добавлении компонента на форму, Билдер сохраняет информацию о нем в файле .DFM. Так как все свойства компонента определяют, как он будет выглядеть, где будет на форме и так далее, они просто сохраняются в двойчном .DFM-файле на диске. Значение по умолчанию, которое вы присваиваете компоненту, будет определять, будет ли свойство сохраняться в .DFM-файле или нет. Если значение свойства на форме совпадает со значением по умолчанию, оно НЕ будет сохраняться, а если оно другое, то сохранится.
Свойства могут быть объявлены с ключевым словом nodefault:
__property bool LEDOn = {read=FOnOff, write=SetOnOff, nodefault};
Это означает, что они ВСЕГДА будут сохраняться. Также имеется атрибут stored. Вы можете переопределить сохраняющие действия Билдера по умолчанию с помощью него. Если вы установите stored в true, свойтво всегда будет сохраняться, если в false - никогда не будет сохраняться. Кроме того, вы можете определить его с помощью метода, возвращающего логическое значение (в нижеприведенном примере функция check возвращает булево значение).
__property bool LEDOn = {read=FOnOff, write=SetOnOff, stored=true};
__property bool LEDOn = {read=FOnOff, write=SetOnOff, stored=false};
__property bool LEDOn = {read=FOnOff, write=SetOnOff, stored=Check};
Последний атрибут, который имеет свойство - это index. Он полезен, когда нужно иметь несколько аксессоров и мутаторов с дублирующимся кодом. Вместо того, чтобы писать несколько отдельных функций, можно написать одну с использованием index. Чтобы его использовать, нужно добавить соответствующее ключевое слово в объявление свойства, и индекс будет первым элементом, который передается аксессору/мутатору. Например:
__property TColor OnColour = {read=FOnColour, write=SetOnOffColour, index=1};
__property TColor OffColour = {read=FOffColour, write=SetOnOffColour, index=2};
Реализация функции SetOnOffColour должна выглядеть примерно так:
void __fastcall TLED::SetOnOffColour(int Index,TColor Colour)
{
switch(Index)
{
case 1 : FOnColour = Colour;
break;
case 2 : FOffColour = Colour;
break;
}
Brush->Color = (FOnOff)?FOnColour:FOffColour;
}
Вот как должен выглядеть файл LED.h:
//---------------------------------------------------------------------------
#ifndef LEDH
#define LEDH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Controls.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
//---------------------------------------------------------------------------
class PACKAGE TLED : public TShape
{
private:
bool FOnOff;
TColor FOnColour;
TColor FOffColour;
void __fastcall SetOnOff(const bool Value);
void __fastcall SetOnColour(const TColor OnColour);
void __fastcall SetOffColour(const TColor OffColour);
protected:
public:
__fastcall TLED(TComponent* Owner);
__published:
__property bool LEDOn = {read = FOnOff, write = SetOnOff};
__property TColor OnColour = {read = FOnColour, write = SetOnColour};
__property TColor OffColour = {read = FOffColour, write = SetOffColour};
};
//---------------------------------------------------------------------------
#endif
2.4. CPP - файл
Самая трудная часть позади. Легкая часть - написание .cpp файла. Сначала будет написан код мутаторов:
//---------------------------------------------------------------------------
void __fastcall TLED::SetOnOff(const bool Value)
{
FOnOff = Value; // Set the state of FOnOff
Brush->Color = (FOnOff)?FOnColour:FOffColour;
}
//---------------------------------------------------------------------------
void __fastcall TLED::SetOnColour(const TColor OnColour)
{
FOnColour = OnColour;
Brush->Color = (FOnOff)?FOnColour:FOffColour;
}
//---------------------------------------------------------------------------
void __fastcall TLED::SetOffColour(const TColor OffColour)
{
FOffColour = OffColour;
Brush->Color = (FOnOff)?FOnColour:FOffColour;
}
//---------------------------------------------------------------------------
Теперь надо написать конструктор. В нем будут устанавливаться значения по умолчанию, которые будут видны в object inspector:
__fastcall TLED::TLED(TComponent* Owner)
: TShape(Owner)
{
Width = 15; // Установим ширину нашего LED в 15.
Height = 15; // Установим высоту нашего LED в 15.
FOnColour = clLime; // Установим OnColour лимонно-зеленым.
FOffColour = clRed; // Установим OffColour красным.
FOnOff = false; // Сосотояние по умолчанию - выключено
Shape = stEllipse; // Форма по умолчанию - эллипс
Pen->Color = clBlack; // Цвет пера - черный
Pen->Width = 1; // Толщина пера 1
Brush->Color = FOffColour; // Цвет кисти одинаков с цветом по умолчанию
}
Все достаточно прозрачно. Эти значения будут установлены, когда компонент поместят на форму и при этом автоматически будет вызван конструктор. Несмотря на это, можно менять эти значения и во время проектирования, а не только во время выполнения.
Существует несколько способов инициализации переменных в конструкторе. Вышеприведенный пример можно было написать и так:
__fastcall TLED::TLED(TComponent* Owner)
: TShape(Owner),
FOnColour(clLime), // установить OnColour в лимонно-зеленый
FOffColour(clRed) // установить OffColour красным
{
Width = 15; // Установим ширину нашего LED в 15.
Height = 15; // Установим высоту нашего LED в 15.
Shape = stEllipse; // Форма по умолчанию - эллипс
Pen->Color = clBlack; // Цвет пера - черный
Pen->Width = 2; // Толщина пера 2
Brush->Color = FOffColour; // Цвет кисти одинаков с цветом по умолчанию
}
Можно и так:
__fastcall TLED::TLED(TComponent* Owner)
: TShape(Owner), FOnColour(clLime), FOffColour(clRed), Width(15),
Height(15), Shape(stEllipse), Pen->Width(2),Brush->Color(FOffColour)
{}
Важно понимать, что fOnOff инициализировать не обязательно, так как тип bool имеет встроенное значение по умолчанию(false), в отличие от большинства простых типов C++, которые автоматически не инициализируются. Тем не менее, считается хорошим стилем инициализировать значения всех свойств.
Теперь, когда написан этот небольшой компонент, можно убедиться, что все работает. Сначала сохраняется проект (File | Save All). Затем добавляется модуль LED, который только что создан, к тестовому проекту. Чтобы это сделать, выберается (Project | Add to Project) и находится led.cpp (по умолчанию сохраненный в папку lib в v3 и v4). Потом вводится #include "LED.h" вверху LEDForm.h:
#include <vcl\Classes.hpp>
#include <vcl\Controls.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Forms.hpp>
#include "LED.h"
Теперь добавляется в секцию private файла LEDForm.h:
private: // User declarations
TLED* LED1;
После этого выполняется возврат на форму LEDForm, выберается событие OnCreate в object inspector и вводится следующий код в тело функции:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
LED1 = new TLED(this);
LED1->Parent = this;
LED1->Left = (Width/2)-(LED1->Width/2);
LED1->Top = (Height/2)-(LED1->Height/2);
}
Этот код динамически создает новый компонент TLED и помещает его в центр экрана (если динамически создается компонент, надо задать все значения вручную). Очень важно также запомнить, что в этом случае необходимо задать свойство Parent компонента! Теперь выберается событие OnClick кнопки:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
LED1->LEDOn = !LED1->LEDOn;
}
Теперь самое время нажать волшебную кнопку Run. Программа должна выглядеть так (рис. 2.2.):
Рис. 2.2. Кнопка Run “LED Change”
Щелкая кнопку, можно менять цвет индикатора с красного на зеленый с черным и обратно. Компонент польностью готов, и единственное, что осталось - инсталлировать его в палитру. В версии 3 и выше предварительно надо еще и создать пакетную библиотеку (пакедж).
Прежде чем добавить компонент в палитру, нужно разработать для него иконку (стандартная иконка слишком неинформативна) с помощью утилитки Image Editor (Tools | Image Editor) (если нет желания делать иконку для компонента, можно пропустить этот материал).
C++Builder v3 or later
Необходимо выбрать (File|New|Resource), щелкнуть правой клавишей на ветке дерева "Contents" и выбрать (New | Bitmap). В появившемся диалоге надо выбрать высоту и ширину 24 и VGA(16 colours), затем "OK". После этого следует переименовать иконку в LED (кликнув правой клавишей), и после этого дважды кликнуть на ней. Теперь можно нарисовать иконку. После этого надо выбрать (File | Save), сохранить файл ресурса в ту же папку, что и файл LED.cpp (папка lib по умолчанию), под именем LED.res (см. рис. 2.3.).
C++Builder v1
Необходимо выбрать (File | New | Bitmap), в диалоге выбрать высоту и ширину в 24, VGA (16 colours), щелкнуть "OK". Далее выбрать (Resource | Rename), назвать битмап TLED. Дважды кликнув, создать рисунок. Далее, (File | Save As) и сохранить файл ресурса в ту же папку, что и файл LED.cpp под именем LED.res.
Рис. 2.3. Создание иконки
Теперь можно инсталлировать компонент.
Теперь все готово к инсталляции компонента. Процедура сильно отличается в зависимости от того, какая версия Билдера используется.
Инсталляция в C++Builder v1
Процедура инсталляции разработанного компонента ничем не отличается от процедуры инсталляции любого другого. Сначала последний вызывает (File | Save All), затем выбирается (Component | Install) из главного меню C++Builder. Появится диалогInstallComponents, где надо нажать кнопкуAdd, и затем (из диалогаAddModule) нажать кнопкуBrowse. После выбираетсяLED.cppв диалогеAddComponent, и наконец нажимается кнопка "OK" в диалогеInstallComponents. C++Builder скомпилирует и подлинкует компонент, а затем добавит его в палитру.
Инсталляция в C++Builder v3 или старше
В C++Builder v3 Borland впервые ввела пакетные библиотеки (пакеджи). Компоненты теперь сначала компилируются в пакедж, который потом инсталлируется. Этим обеспечивается разделение компонентного кода между приложениями (через BPL, которые представляют собой особый вид DLL).
Сначала сохраняется все (File | Save All), затем закрываются все файлы (File | Close All). Теперь выбирается (Component | Install Component), далее выбирается "Into new package" и подключается файл LED.cpp. Необходимо назначить имя для пакеджа (оно должно отличаться от имени компонента) - например, LEDPack, и потом можно, если потребуется, ввести краткое описание пакеджа. Далее надо щелкнуть "OK". C++Builder спросит подтверждение того, что инсталлируется компонент, после этого скомпилирует и установит компонент.