БГУ Пособие - Программирование в C++ Builder. Учебное пособие по курсу методы программирования для студентов специальностей
Скачать 1.24 Mb.
|
Вопросы 1. Какие свойства используются при создании приложения-сервера с использованием компонента TserverSocket? 2. Какие свойства используются при создании приложения-клиента с использованием компонента TclientSocket? 3. С помощью какого метода можно получить данные с сервера по инициативе клиента ? 4. С помощью какого метода клиент может переслать текстовые дан- ные на сервер ? 5. Куда в приложении-клиенте поступают данные, пересылаемые от сервера? 6. Какие методы используются для передачи информации от клиента серверу? 7. С помощью какого метода можно получить данные с сервера по инициативе клиента? 8. Как организовать постоянное отслеживание информации на серве- ре в приложении-клиенте? 9. Какое событие в приложении-сервере может быть использовано для определения того, что от клиента серверу послана информация? 10. Какие способы установления контакта с сервером Вы знаете? 11. Что нужно сделать, чтобы при запуске приложения-клиента авто- матически запускалось и приложение-сервер? Упражнения 1. Организовать пересылку текстовых сообщений между клиентом и сервером в обоих направлениях с постоянным отслеживанием информа- ции. 2. Реализовать передачу координат курсора мыши между клиентом и сервером в обоих направлениях с постоянным отслеживанием коорди- нат. 3. Реализовать простейший “чат”. 4. Реализовать игру в “слова”, например по очереди называть назва- ния городов. 5. Реализовать игру «крестики/нолики» в сети. 6. Реализовать игру «морской бой» в сети. 112 7. СОЗДАНИЕ СОБСТВЕННЫХ КОМПОНЕНТОВ Процесс разработки собственного компонента (назовем его TMyComp) состоит из следующих этапов: 1. Создание модуля для нового компонента. 2. Наследование производным классом для нового компонента уже существующего базового класса библиотеки VCL. 3. Добавление нужных свойств, событий и методов. 4. Регистрация компонента в среде C++Builder. 5. Отладка. 6. Инсталляция компонента на Палитру компонентов. 7. Сохранение файлов компонента. Мастер компонентов способен выполнить автоматически создание файлов модуля, наследование компонентного класса, объявление нового конструктора и регистрацию компонента. Разработчик компонента "вручную" или с помощью имеющихся средств добавляет свойства, со- бытия, методы и устанавливает компонент на Палитру компонентов. Рассмотрим подробнее действия, которые выполняются на каждом из перечисленных этапов. 7.1. Создание модуля компонента Программный модуль компонента состоит из двух файлов Му- Соmр.срр и MyComp.h, которые компилируются в объектный файл MyComp.obj. При paзработке компонента либо создают новый модуль, либо модифицируют существующий. Чтобы создать модуль, необходимо выполнить командуFile|New и в открывшемся диалоговом окне New Items выбрать значок Unit. Чтобы добавить компонент к существующему модулю, нужно выполнить командуFile|Open и в открывшемся диалого- вом окне выбрать файл имя_модуля.cpp для модуля, в который будет до- бавлен компонент. Далее формируется заготовка файла МуСоmр.h: #ifndef MyCompH #define MyCompH #include #include #include #include //class TMyComponent : public < базовый компонентный класс > class PACKAGE TMyComponent : public < базовый класс > { public: __fastcall TMyComponent(TСomponent *Owner); 113 }; #endif Объявление нового класса компонента должно включать макрос PACKAGE. Функционально сходные компоненты группируются в паке- ты – динамические библиотечные файлы с расширением .bpl. Как и обычные dll-библиотеки, пакеты содержат код, разделяемый многими приложениями. Пакетная организация ускоряет компиляцию и сборку приложений, позволяет получить более эффективные исполняемые коды за счет того, что к выполняемой программе VCL уже не загружается це- ликом. Созданный компонент пока не отличается от своего родителя. 7.2. Наследование компонента Любой компонент является производным от базового класса TComponent и его наследников (таких как TControl или TGraphicControl) или от существующего компонентного класса. Простейший способ построить новый компонент – это изменить свойства существующего компонента. Для этого можно использовать любой абстрактный класс VCL, в название которого входит слово Custom. Например, можно создать новый компонент списка со специаль- ными свойствами, которых нет в стандартном классе TListBox. Посколь- ку нельзя непосредственно модифицировать TListBox, то можно начать с его ближайшего предшественника в иерархии классов. Для этой цели подходит класс TCustomListBox, который реализует все мыслимые свой- ства производных компонентов списка, однако не выставляет всех их в секции _published. Наследуя компонент, нужно объявить в разделе _published те свойства, которые требуется включить в создаваемый ком- понент. Все оконные компоненты являются производными от базового класса TWinControl. Стандартный элемент оконного управления характеризует так называемый "оконный дескриптор" (window handle), который заклю- чен в свойстве Handle. Благодаря дескриптору, Windows идентифицирует данный компонент, в частности, она может принять фокус ввода. Хотя можно создать оригинальный оконный интерфейсный элемент (который не имеет существующих аналогов и никак не связан с ними), используя в качестве базового класса TWinControl, C++Builder предоставляет класс TCustomControl – специализированный оконный элемент управления, который упрощает рисование сложных визуальных изображений. Все компоненты стандартного оконного управления: кнопки, списки, тексто- вые поля (за исключением компонента TLabel, который никогда не при- 114 нимает фокус ввода) – являются косвенными производными TWinControl. В отличие от оконных компонентов, производных от класса TCustomControl, графические компоненты лишены оконного дескрипто- ра и не могут принять фокус ввода. Графические компоненты обеспечи- вают отображение объектов без использования системных ресурсов. Новые графические компоненты необходимо наследовать от базового абстрактного класса TGraphicControl (потомка TControl). Класс TGraphicControl предоставляет канву для рисования и обрабатывает со- общения WM_PAINT. Все, что нужно сделать, это переопределить метод рисования Paint в соответствии с заданными требованиями. Все компоненты имеют общий абстрактный базовый класс TСomponent, однако, только невидимые компоненты можно наследовать непосредственно от класса TComponent. Невидимые компоненты ис- пользуются в качестве интерфейсных элементов с другими компонента- ми (доступ к базам данных или диалоговым окнам). 7.3. Добавление свойств, событий и методов Свойства, в отличие от данных-членов, сами не хранят данные, одна- ко методы чтения и записи организуют к ним доступ. Об этом необходи- мо помнить при создании или изменении компонентных свойств. Событие – это связь между некоторым воздействием на компонент и кодом обработчика события, который реагирует на это воздействие. Об- работчик события пишется прикладным программистом. Используя со- бытия, программист может приспособить поведение компонента к своим требованиям без необходимости изменения самих объектов. События, возникающие в результате типичных действий пользователя (например, движений мышью) встроены во все стандартные компоненты VCL, од- нако вы можете определить новые события. C++Builder реализует собы- тия как свойства. 7.4. Регистрация компонента Регистрация компонента – это процесс, который информирует C++Builder о том, какой компонент добавляется к VCL и на какой вклад- ке Палитры компонентов он должен появиться. Для регистрации компо- нента выполняются следующие действия: 1) Добавляется функция Register() в файле МуСоmр.срр. При этом функция заключается в пространство имен с именем, совпадающим с 115 именем модуля компонента (при этом первая буква должна быть заглав- ной, а все остальные – строчными). 2) В теле функции Register объявляется массив типа TComponentClass, в который вводится имя класса регистрируемого ком- понента. 3) В теле функции Register вызывается функция RegisterComponents с тремя параметрами: названием вкладки Палитры компонентов, массивом компонентных классов и индексом последнего класса в этом массиве. Например: namespace Mycomp { void __fastcall PACKAGE Register() { TComponentClass classes[1] = {_classid(TMyComponent)}; RegisterComponents("Samples", classes, 0);} } Листинг представляет включение в файл МуСоmр.срр кода для реги- страции компонентf TMyComponent на вкладке Samples Палитры ком- понентов. Когда компонента зарегистрирована, можно ее испытать и инсталли- ровать на Палитру компонентов. 7.5. Отладка неинсталлированного компонента Поведение компонента следует проверить до инсталляции на Палит- ру компонентов. По существу необходимо смоделировать действия, ко- торые производит C++Builder, когда пользователь перемещает компо- нент из Палитры компонентов на форму. Процесс требует выполнения следующих шагов: 1) Включить файл модуля MyComp.h компонента в заголовочный файл некоторой формы: #include " MyComp.h " 2) Добавить объектный член данных, представляющий испытывае- мый компонент, в раздел объявлений public класса формы: TMyCompo- nent *MyComponent1;. 3) Подсоединить обработчик к событию OnCreate формы. 4) Вызвать конструктор компонентного объекта из обработчика этого события, передав ему параметр, указывающий на владельца компонента. Обычно это указатель this на объект, который содержит компонент (на- пример, форма). 5) Сразу же за вызовом конструктора установить свойство Parent – родителя компонента. Обычно значением этого свойства является указа- 116 тель this. Если компонент не является элементом управления, т.е. не на- следовался от TControl, то этот шаг пропускается. 6) Инициировать значения других свойств компонента. Ниже приводится листинг модуля формы, используемой для отладки компонента: // Заголовочный файл TestForm.h #ifndef TestFormH #define TestFormH #include #include #include #include #include "MyComp.h" // 1 class TForm1 : public TForm { __published: private: public: TMyComponent * MyComponent1; // 2 __fastcall TForm1 (TComponent* Owner); // 3 }; extern PACKAGE TForm1 *Forml; #endif // Файл TestForm.cpp модуля формы #include #pragma hdrstop #include "TestForm.h" #pragma package(smart_init) pragma resource "*.dfm" TForm1 *Forml; __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { MyComponent1 = new TMyComponent(this); // 4 MyComponent1->Parent = this; // 5 MyComponentl->Left = 12; // 6 } Для отладки компонента необходимо выполнить компиляцию и за- пустить тестовое приложение. Если поведение компонента соответствует предъявляемым к ему требованиям, то можно перейти к его установке на Палитру компонентов. 7.6. Инсталляция компонента на Палитру компонентов Чтобы добавить к VCL компонент, необходимо выполнить следую- щие шаги: 117 1) С помощью командыComponent|Install Componentоткрывается диалоговое окно инсталляции компонент. Можно выбрать вкладку Into New Package, если компонент включается в новый пакет, или вкладку Into existing package, если используется существующий пакет. 2) Вводится имя модуля компонента MyComp.cpp и путь к нему в по- ле Unit file name. Далее вводится имя нового пакета (совпадающее с на- званием вкладки Палитры компонентов, на которую устанавливается но- вый компонент) в поле Package file name, а его краткое описание – в поле Package description. Щелчок на кнопке ОК закрывает диалоговое окно ус- тановки. Добавление компонента в существующий пакет выполняется аналогично. 3) С текущим содержимым пакета можно ознакомиться вь открыв- шемся окне Менеджера пакетов. Все файлы, составляющие рассматри- ваемый пакет, будут созданы (или перестроены), и новый компонент ус- тановлен на ту вкладку Палитры компонентов, которая была задана в ка- честве одного из параметров функции регистрации Register. C++Builder автоматически включает в проект системные файлы периода выполнения (с расширениями .bpi, .res), необходимые для сборки пакета. 4) Выбирается команда Install в Менеджере пакетов. В результате выполняется компиляция, перестройка VCL и установка нового компо- нента на Палитру компонентов. 5) Командой Component|Install Packages или Project|Options открыва- ется список установленных пакетов. По щелчку на кнопке Components можно увидеть список всех компонентов, включенных в выбранный па- кет. Если нужно, чтобы текущая конфигурация пакетов принималась по умолчанию в каждом новом создаваемом проекте, то необходимо уста- новить флажок Default. Чтобы удалить компонент из VCL, необходимо выполнить следую- щие действия: 1) Выполнить командуComponent|Install Component, которая откры- вает диалоговое окно установки компонентов. 2) Найти удаляемый компонентный класс в списке Component classes выбранной группы Библиотеки и нажать кнопкуRemove. 3) Нажать кнопку ОК. Библиотека будет перестроена и компонент удален из Палитры компонентов. Чтобы перестроить Палитру компонентов, необходимо выполнить следующие действия: 1) Открыть диалог установки опций Палитры компонентов с помо- щью команд Component|Configure Palette илиOptions|Environment|Palette. 118 2) Нажать кнопкуAdd и выбрать имя для новой вкладки. Имя добав- ленной вкладки появится внизу списка Pages названий вкладок. 3) Перетащить мышью выбранный компонент в списке Components на нужную вкладку списка Pages. 4) Нажать кнопку ОК. Библиотека и Палитра компонентов будут пе- рестроены. 7.7. Сохранение файлов нового компонента После окончания процесса разработки, компонент будет представлен следующими файлами: объектный файл результата компиляции MyComp.obj; файлы модуля компонента (MyComp.h, MyComp.cpp); файлы пакета с именем имя_пакета и расширениями bpl, bpk, lib, bpi, cpp, res; файл пиктограммы компонента для Палитры компонентов My- Comp.dcr; файл формы MyComp.dfm, если компонент использует форму; желательно создать и сохранить контекстно-справочный файл My- Comp.hlp. По умолчанию C++Builder сохраняет компонентный пакетный файл с расширением bpl в каталоге \...\ProgramFiles\Borland\CBuilder6\ Pro- jects\Bpl, а библиотечные файлы с расширениями lib и bpi – в каталоге \...\ProgramFiles\Borland\CBuilder6\Projects\Lib. Используя новый компо- нент в дальнейшем, нельзя забывать проверять вкладку Directo- ries|Conditionals диалогового окна команды Project|Options, где должен быть указан путь к библиотечным каталогам. 8. ПРИМЕР РАЗРАБОТКИ ПРОСТОГО КОМПОНЕНТА Перед тем, как приступить к разработке компонент, необходимо знать, что он должен делать и как будет реализовано его оригинальное поведение. Рассмотрим пример компонента, моделирующего бинарный индикатор, который меняет цвет при изменении состояния. Некоторое свойство компонента будет хранить его текущее состояние (true – инди- катор включен, и false – в противном случае). Мы уже знаем, что жела- тельно выбрать для наследования наиболее близкий в иерархии VCL ба- зовый компонентный класс. Очевидно, что индикатор представляет со- бой графический компонент семейства TGraphicControl. Поскольку мы разрабатываем простой компонент, пусть он будет иметь форму круга, а 119 не более хитроумный образ. Компонент TShape из вкладки Палитры компонентов Additional выглядит ближайшим родственным компонен- том. При внимательном рассмотрении Tshape мы видим, что он имеет больше свойств и событий, чем нам требуется. Все что мы хотим изме- нить при наследовании от TShape – это форму индикатора и цвет кисти при его переключении. Перейдем к фактической разработке компонента: 1. Создание формы тестового приложения Пока мы не убедились, что разрабатываемый компонент работает, его нельзя включать в VCL. Сначала следует создать тестовое приложение для формы с прототипом нового компонента MyComp: а) С помощью командыFile|NewApplication создайте пустую форму. б) Разместите кнопку TButton на форме. в) С помощью командыFile|SaveAll сохраните форму и проект при- ложения в файлах под именами MyCompForm.cpp и MyCompProj.bpr. 2. Создание модуля компонента Мастер компонентов (Component Wizard) упрощает начальные шаги создания компонента: а) Выполните командуComponent|New и в открывшемся диалоговом окне Мастера компонентов заполните поля диалога указанными на рис. 26 значениями. Нажмите кнопку ОК. б) С помощью команды File|Save As сохраните файл Unitl.cpp под именем MyComp.cpp. Файл MyComp.cpp будет содержать пустой конструктор объекта и функцию Register для регистрации компонента. Созданный при этом файл MyComp.h будет содержать объявление нового компонентного класса с конструктором, а также несколько заголовочных файлов пред- компиляции. 3. Члены данных, свойства и методы Прежде всего, в файле MyComp.h опишем булеву переменную со- стояния индикатора и две переменные перечисляемого типа TColor для хранения цветов, отображающих оба состояния. Члены данных следует поместить в разделе private объявлений класса. Там же расположим про- тотипы методов записи соответствующих свойств, а сами свойства объя- вим в разделе _published. 120 Рис. 26. Окно Мастера компонентов Ниже приводится заголовочный файл модуля компонента: // MyComp.h ------------------------------------------------------------ #ifndef MyCompH #define MyCompH #include #include #include #include //--------------------------------------------------------------------------- class PACKAGE MyComp : public TShape { private: bool FOnOff; TColor FOnColor; TColor FOffColor; void __fastcall SetOnOff(const bool Value) ; void __fastcall SetOnColor(const TColor OnColor); void __fastcall SetOffColor (const TColor OffColor) ; protected: public: __fastcall MyComp(TComponent* Owner); __published: __property bool OnOff= { read= FOnOff,write= SetOnOff} ; __property ТСоlог OnColor= { read=FOnColor,write=SetOnColor} ; __property TColor OffColor={ read=FOff Color, write= SetOffColor} ; }; //--------------------------------------------------------------------------- 121 #endif Для добавления в файл MyComp.cpp необходимо написать три функ- ции для присваивания значений свойств соответствующим членам дан- ных и наполнить конструктор компонента инструкциями для инициали- зации переменных. Ниже приводится листинг файла MyComp.cpp после внесения изменений: //MyComp.cpp #include #pragma hdrstop #include "MyComp.h" #pragma package(smart_init) //--------------------------------------------------------------------------- // ValidCtrCheck is used to assure that the components created // do not have any pure virtual functions. static inline void ValidCtrCheck(MyComp *) { new MyComp(NULL); } void __fastcall MyComp::SetOnOff(const bool Value) { FOnOff = Value; Brush->Color= (FOnOff) ? FOnColor : FOffColor ; } void __fastcall MyComp::SetOnColor(const TColor OnColor) { FOnColor = OnColor; Brush->Color = (FOnOff) ? FOnColor : FOffColor; } void __fastcall MyComp::SetOffColor(const TColor OffColor) { FOffColor = OffColor; Brush->Color = (FOnOff) ? FOnColor : FOffColor; } //--------------------------------------------------------------------------- __fastcall MyComp::MyComp(TComponent* Owner) : TShape(Owner) { Width = 15; //ширина по умолчанию Height = 15; // высота по умолчанию FOnColor = clLime; // зеленый, когда включен FOffColor = clRed; // красный, когда выключен FOnOff = false; // выключен по умолчанию Shape = stEllipse; //в форме эллипса по умолчанию Pen->Color = clBlack; // черный контур по умолчанию Pen->Width = 2; // ширина контура по умолчанию Brush->Color = FOffColor; // цвет заливки по умолчанию } namespace Mycomp { void __fastcall PACKAGE Register() { TComponentClass classes[1] = {__classid(MyComp)}; 122 RegisterComponents("Samples", classes, 0); } } //--------------------------------------------------------------------------- Установленные конструктором значения членов данных по умолча- нию появятся в окне Инспектора объектов при создании объекта. Дей- стительно, при помещении компоненты на форму конструктор вызыва- ется автоматически. В результате появляется возможность менять значе- ния свойств компонента не только во время выполнения программы, но и на стадии проектирования приложения. |