Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C _Учебник_МОНУ

.pdf
Скачиваний:
206
Добавлен:
12.05.2015
Размер:
11.12 Mб
Скачать

 

Об’єктно-орієнтоване програмування

529

 

 

 

 

 

 

 

Таблиця 14.2

 

 

Деякі методи класу TWinControl

 

 

 

 

 

 

 

 

Прототип методу

Призначення

 

 

 

 

 

 

 

virtual void __fastcall

Передає об‟єктові “фокус”, після чого натискання

 

 

SetFocus(void);

клавіш клавіатури сприйматимуться саме цим

 

 

 

 

об‟єктом

 

 

 

DYNAMIC void __fastcall

Викликає функцію відгуку на подію OnKeyDown,

 

 

KeyDown(Word &Key,

яка відбувається за натискання будь-якої клавіші

 

 

Classes:: TShiftState

на клавіатурі. Параметр Key визначає клавішу,

 

 

 

Shift);

 

 

 

яку натиснуто. Параметр Shift є такий самий,

 

 

 

 

 

 

 

 

як у MouseDown

 

 

 

DYNAMIC void __fastcall

Викликає функції відгуку на подію OnKeyPress,

 

 

KeyPress( char&Key);

яка відбувається за натискання будь-якої

 

 

 

 

символьної клавіші

 

 

 

DYNAMIC void __fastcall

Викликає функції відгуку на подію OnKeyUp,

 

 

 

KeyUp(Word &Key,Classes::

яка відбувається за відпускання будь-якої клавіші

 

 

TShiftState Shift);

 

 

 

 

 

 

 

 

Клас TGraphicControl – це абстрактний клас, похідний від TControl, але який, на відміну від класу TWinControl, не має віконного дескриптора. Цей клас використовують для графічних зображень на формі без звертань до системних ресурсів Windows. Важлива властивість цього класу – Canvas, яка забезпечує доступ до поверхні малювання (див. підрозд. 12.4). Похідні від цього класу також можуть обслуговувати події маніпулювання з мишею.

Завдяки важливій властивості класів – успадкуванню – можна створювати нові компоненти не з нуля, а як клас, який успадковує властивості, методи чи події батьківського класу, тобто класу, на базі якого створюється цей нащадок. Наприклад, при створюванні нової кнопки можна взяти за основу один з уже розроблених класів кнопок, наприклад клас TButton, й лише долучити до нього певні нові властивості чи то відкинути певні властивості та методи батьківського класу.

14.9.2 Побудова компонента-нащадка

Яскравим прикладом застосування успадкування є створення нового компонента у візуальному середовищі програмування як нащадка існуючого компонента. При цьому компоненту можна долучити нові властивості чи нові події.

Процес створювання компонента складається з послідовності етапів:

1)обирання батьківського компонента;

2)створення модуля нового компонента;

3)тестування компонента;

4)інсталяція (долучення) компонента до пакета компонентів.

Розглянемо цей процес на прикладі створення нового компонента, який

запам‟ятовує кількість натискань на нього та відображує цю інформацію.

530

Розділ 14

 

 

Обирання батьківського компонента. Створимо власний компонент як нащадок класу TButton, долучивши до нього нову властивість, яка буде обчислювати кількість натискань. Назвемо новий компонент TBtnNClick. До компонента, окрім властивостей, звичних для TButton, долучимо нову властивість у вигляді додаткового цілого типу – int NClick – лічильник натискань.

Створення модуля нового компонента. Роботу над створенням нового компонента розпочинаємо з побудови шаблона нового класу. Для цього слід виконати такі дії.

Виконати команду File / New / Application. У меню Component обрати опцію New Component і в однойменному діалоговому вікні заповнити такі поля з інформацією про компонент, який створюється:

Ancestor type – батьківський клас нащадка, що будується (обираємо для нашого прикладу клас кнопки TButton);

Class Name – ім‟я нового класу, що будується (тут напишемо TBtnNClick); Palette Page – сторінка палітри компонентів, на яку буде розміщено новий компонент. За замовчуванням це сторінка Samples. Можна зазначити одну

з існуючих сторінок, або ж задати нове ім‟я – відповідну нову сторінку палітри буде сформовано. Задамо ім‟я MyClass;

Unit file name – слід зазначити ім‟я нового модуля (unit) та шлях до нього. В цей unit буде розміщено код мовою C++, потрібний для побудови но-

вого класу. За замовчуванням імена файлів модуля збігаються з ім‟ям класу, –

за винятком першої літери T, – отже, якщо клас називається TBtnNClick, файли буде названо BtnNClick.cpp та BtnNClick.h. Щодо шляху до файла, то за замовчуванням C++ Builder встановлює шлях до власного бібліотечного ката-

логу LIB. Рекомендується змінити цей шлях і розмістити unit нового класу у власному каталозі, наприклад:

C:\STUDENTS\SEMESTR2\ТС104\Ivanov\BtnNClick.cpp

Search path – тут перелічено каталоги, в яких C++ Builder шукатиме unit нового класу. Якщо у попередньому пункті було зазначено повний шлях

Об’єктно-орієнтоване програмування

531

 

 

до власного каталогу, C++ Builder автоматично допише його до Search path; тоді залишиться лише перевірити, чи правильно це було зроблено.

Тепер слід натиснути кнопку ОК, – і буде утворено модуль нового компонента, який складається з двох файлів: заголовного файла BtnNClick.h та файла реалізації BtnNClick.cpp. При цьому буде відкрито вікно файла BtnClick.cpp; проте оголошення нового класу буде сформовано у заголовному файлі BtnNClick.h.

До шаблона компонента, який утворено, треба ввести певні доповнення: оголошення нових полів даних, функції доступу до них, властивості та методи. Для нашого компонента створимо нове поле NClick типу int та допишемо прототип методу Click.

Файл BtnNClick.h:

#ifndef BtnNClickH #define BtnNClickH #include <SysUtils.hpp> #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp>

class PACKAGE TBtnNClick : public TButton { private:

int NClick; // Змінна для підрахунку кількості натискань protected:

public: // Прототип конструктора нового компонента

__fastcall TBtnNClick(TComponent* Owner);

// Прототип події Click

DYNAMIC void __fastcall Click(void);

__published: };

#endif

У цьому файлі рядок

class PACKAGE TBtnNClk : public TButton

повідомляє про те, що клас TBtnNClk є нащадком класу TButton. Слово public означає, що поля й методи батьківського класу будуть доступними з екземплярів його нащадка. Поле NСlick вміщено до секції private, щоб користувач не мав до нього доступу. Тепер слід долучити до класу TBtnNClick додаткові методи. У секції public нового класу вже вміщено прототип методу:

__fastcall TBtnNClick (TComponent* Owner);

Це так званий метод-конструктор об‟єктів нового класу. Далі у секції public йде прототип методу Click, який перекриває метод Click класу TButton. Цей прототип має вигляд:

DYNAMIC void __fastcall Click(void);

Тепер перейдемо до файла BtnNClick.cpp. У цьому файлі розмістимо реалізацію оновленого конструктора та методу Click.

532

Розділ 14

 

 

Файл BtnNClick.cpp:

#include <vcl.h> #pragma hdrstop #include "BtnNClick.h"

#pragma package(smart_init)

//---------------------------------------------------------------

static inline void ValidCtrCheck(TBtnNClick *) { new TBtnNClick(NULL);

}

//---------------------------------------------------------------

__fastcall TBtnNClick::TBtnNClick(TComponent* Owner) : TButton(Owner)

{ NClick=0; // Початкове значення змінної кількості натискань

}

//----------------------------------------------------------------

void __fastcall TBtnNClick::Click(void)

{ // Збільшення значення змінної кількості натискань на 1

NClick++;

//Виведення значення кількості натискань на кнопці

Caption=Name+" ("+IntToStr(NClick)+") клацань";

//Подальше успадкування роботи методу Click()від класу TButton TButton::Click();

}

//----------------------------------------------------------------

namespace Btnnclick

{ void __fastcall PACKAGE Register()

{TComponentClass classes[1]= {__classid(TBtnNClick)}; RegisterComponents("MyClasses", classes, 0);

}

}

Першою у цьому файлі стоїть функція ValidCtrCheck(), яка запобігає вміщенню до нового класу віртуальних функцій. Далі йде конструктор класу, який ініціалізує поле NClick значенням 0. Новий конструктор тепер виконуватиме, окрім усіх дій батьківського конструктора, ще й додаткову інструкцію NClick=0. У такий спосіб він перекриває батьківський метод. Параметр конструктора Owner має тип TComponent*, тобто є вказівником на об‟єкт класу TComponent. Це означає, що “володарем” кнопки типу TBtnNClick може бути лише якийсь з компонентів C++ Builder.

Далі треба перекрити ще один метод класу TButton – метод Click. Функція Click() збільшує на одиницю лічильник натискань кнопки; формує властивість кнопки Caption як рядок, у якому до її імені Name дописано кількість натискань, і потім викликає успадкований метод TButton::Click(). Останнє зроблено для того, щоби, за винятком відображення кількості натискань, “поводження” кнопок нового типу нічим не відрізнялось від типу TButton.

Останньою є директива namespace і функція Register(), потрібна для реєстрації нового класу як компонента C++ Builder. Ця функція викликає біблі-

Об’єктно-орієнтоване програмування

533

 

 

отечну підпрограму RegisterComponents, перший параметр якої визначає сторінку, на яку буде вміщено новий компонент, другий – масив імен класів, які реєструються, а останній параметр має бути на 1 меншим за кількість класів у масиві. Директива namespace визначає константу BtnNClick, яка збігається з ім‟ям модуля з точністю до регістра літер. У подальшому ця константа дозволяє викликати “правильну” функцію Register для реєстрації різних класів.

Тестування компонента. Після створення модуля нового компонента його бажано протестувати перед інсталяцією, щоби переконатися, що новий компонент працює правильно. Для цього розробленні модулі зберігають та створюють проект, який використовує модуль нового компонента. Компонент буде створено як динамічну змінну, тому що на палітрі компонентів його піктограми ще нема.

На форму проекту нанесемо тільки стандартну кнопку Button1 для керування роботою проекту. Варіант форми для тестування:

#include <vcl.h> #pragma hdrstop

#include "BtnNClick.cpp" // Приєднуємо модуль компонента

#include "Unit1.h" //------------------------------------------------------------

#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1;

//------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)

{

}

//-------------------------------------------------------------

TBtnNClick

*Btn; // Оголошення динамічної змінної – об‟єкта класу

//---------

Відгук для кнопки “Створити нову кнопку”---------

void __fastcall TForm1::Button1Click(TObject *Sender) { Btn = new TBtnNClick (Form1);

534

Розділ 14

 

 

Btn->Parent=Form1;

// Координати розміщення нового компонента на формі

Btn->Left=70; Btn->Top=100;

Btn->Width=200; Btn->Height=30;

}

Власником об‟єкта, що тестується, є вікно форми Form1 (власник показано як параметр конструктора TBtnNClick). Властивість Parent створеного екземпляра класу (її задають обов‟язково) також дорівнює Form1, а це означає, що новий компонент Btn буде розміщено у вікні Form1. Після запуску проекту та натискання на стандартну кнопку “Створити нову кнопку” на формі з‟явиться новий компонент. При клацанні по цій кнопці, на ній з‟явиться повідомлення про кількість клацань, як це показано на формі з результатами роботи.

Наведемо ще один приклад створення та тестування нового компонента.

Приклад 14.8. Необхідно створити новий компонент − клас TSG як нащадок класу TStringGrid. Цей компонент повинен мати такі додаткові можливості:

при натисканні на клавішу <F11> його комірки заповнюватимуться випадковими цілими числами від 0 до 20;

при натисканні на клавішу <Esc> комірки компонента очищуватимуся;

при клацанні лівою кнопкою миші на будь-яку комірку розмір шрифту

їїтексту збільшуватиметься вдвічі, а при повторному клацанні – повертатиметься до початкового стану.

Розв‟язок. Для реалізації останньої з названих можливостей введемо додаткове поле flag логічного типу bool – прапорець, який змінюватиме власне значення після змінювання розміру шрифту з true на false та навпаки. Для опрацювання подій клацання лівою кнопкою миші до оголошення класу внесемо прототип Click (див. табл. 14.1). Також до оголошення класу впишемо прототип функції KeyPress (див. табл. 14.2) з метою опрацювання події натискання клавіші <F11>. Обидві функції оголосимо як DYNAMIC, що й дозволить перекрити зміст методу базового компонента.

 

Об’єктно-орієнтоване програмування

535

 

 

 

Наведемо коди файлів SG.h та SG.cpp.

 

 

Файл SG.h:

 

 

 

#ifndef SGH

 

 

 

#define SGH

 

 

 

#include <SysUtils.hpp>

 

 

#include <Classes.hpp>

 

 

#include <Controls.hpp>

 

 

#include <Grids.hpp>

 

 

//------------------------------------------------------------

 

 

 

class PACKAGE TSG : public TStringGrid

 

{private:

 

 

 

bool flag; // Оголошення змінної логічного типу

 

protected:

 

 

 

public: // Прототип конструктора нового компонента

 

__fastcall TSG(TComponent* Owner);

 

// Прототип події KeyDown

 

 

DYNAMIC void __fastcall KeyDown(Word &Key,

 

 

Classes::TShiftState Shift);

 

// Прототип події Click

 

 

DYNAMIC void __fastcall Click(void);

 

__published:

 

 

 

};

 

 

 

#endif

 

 

 

Файл SG.cpp:

 

 

 

#include <vcl.h>

 

 

#pragma hdrstop

 

 

#include "SG.h"

 

 

#pragma package(smart_init)

 

 

static inline void ValidCtrCheck(TSG *)

 

{ new TSG(NULL); }

 

 

//------------------------------------------------------------

 

 

 

__fastcall TSG::TSG(TComponent* Owner)

 

: TStringGrid(Owner)

 

 

{ flag=true;

// Надання початкового значення змінній flag

 

}

 

 

 

// Новий код функції на подію Click

 

 

void __fastcall TSG::Click()

 

 

{ if(flag) Font->Size=Font->Size*2;

// Збільшення шрифту удвічі

 

else Font->Size=Font->Size/2;

// Зменшення шрифту удвічі

 

flag=!flag;

// Змінювання значення flag на протилежне

 

// Подальше

успадкування роботи методу Click() від класу TStringGrid

 

TStringGrid::Click();

}

//------------------------------------------------------------

// Новий код функції на подію KeyDown

void __fastcall TSG::KeyDown(Word &Key,

536

Розділ 14

 

 

Classes::TShiftState Shift)

{ if(Key==VK_ESCAPE)

// Перевірка натискання клавіші <Esc?

for(int i=0; i<RowCount; i++)

 

for(int j=0; j<ColCount; j++) Cells[j][i]="";

if(Key==VK_F11)

// Перевірка натискання клавіші <F11>

for(int i=0; i<RowCount;i++)

// Заповнення компонента

for(int j=0; j<ColCount; j++)

// StringGrid

Cells[j][i]=IntToStr(random(20)); // випадковими числами

// Подальше успадкування роботи методу KeyDown() від класу TStringGrid

TStringGrid::KeyDown(Key, Shift);

}

//------------------------------------------------------------

namespace Sg

{ void __fastcall PACKAGE Register()

{TComponentClass classes[1] = {__classid(TSG)}; RegisterComponents("Samples", classes, 0);

}

}

Протестуємо модуль нового компонента. Варіант форми проекту для тестування:

Створимо новий компонент як динамічну зміну SGt, задамо координати розташування та деякі властивості компонента.

Файл Unit1.cpp

#include <vcl.h> #pragma hdrstop

#include "SG.cpp" // Долучення модуля нового компонента

#include "Unit1.h" //-----------------------------------------------------------

#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1;

//-----------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)

{

}

 

Об’єктно-орієнтоване програмування

537

 

 

 

//-----------------------------------------------------------

 

 

TSG *SGt; // Оголошення динамічної змінної класу нового компонента

 

//----

Відгук на кнопку “Відобразити компонент”--------------------

 

void __fastcall TForm1::Button1Click(TObject *Sender)

{SGt=new TSG(Form1); SGt->Parent=Form1;

//Координати розміщення нового компонента на формі

SGt->Left=20; SGt->Top=10;

//Значення властивостей нового компонента

SGt->FixedRows=0;

SGt->FixedCols=0;

SGt->RowCount=4;

SGt->ColCount=5; SGt->Options<<goEditing<<goTabs;

}

Власником об‟єкта, що тестується, є вікно форми Form1 (власник показано як параметр конструктора TSG). Властивість Parent створеного екземпляра класу також має значення Form1, а це означає, що новий компонент SGt буде розміщено у вікні Form1. Після запуску проекту та натискання на стандартну кнопку “Відобразити компонент” на формі з‟явиться новий компонент. Коли курсор знаходитиметься у будь-якій комірці компонента SGt стануть доступними такі можливості: при натисканні клавіші <F11>, компонент заповнюватиметься випадковими числами (рис. 14.4, а), при клацанні лівою клавішею миші шрифт символів комірок збільшуватиметься удвічі (рис. 14.4, б), при натисканні клавіші <Esc> всі комірки автоматично очищуватимуться (рис. 14.4, в).

а

б

в

Рис. 14.4. Результати роботи з компонентом SGt: а) при натисканні клавіші <F11> ;

б) при клацанні лівою клавішею; в) натисканні клавіші <Esc>.

14.9.3 Інсталяція компонента

Компоненти у C++ Builder компілюються у пакети. Тому, для того, щоб ярлик створеного компонента відобразився на палітрі компонентів C++ Builder,

538

Розділ 14

 

 

треба створити пакет і бажано розмістити його у власному каталозі. Для створення пакета слід виконати такі дії:

виконати команду File / New і в діалоговому вікні New Items обрати піктограму Package. Після чого у вікні Package буде відображено склад пакета:

виконати команду File / Save As для зберігання у власному каталозі. Ім‟я Package1 можна змінити, наприклад, на MyCompn.

Створений пакет складається з двох файлів: файл з розширенням .bpk та файл з розширенням .cpp, який містить інструкції щодо розміщення побудованих класів в особливій динамічній бібліотеці компонентів C++ Builder. Після компіляції цих файлів новим компонентом можна буде користуватися.

Як приклад розглянемо послідовність дій при компіляції компонента BtnNClick, розглянутого на початку п. 14.9.2. Для цього виконаємо дії у такій послідовності.

У головному меню оберемо опцію Component / Install Component, що спричинить появу вікна Install Component.

Перейдемо на сторінку Into new package цього вікна і задамо такі параметри нового пакета:

Unit file name – шлях (місцеперебування файла, яке записується у вигляді послідовності імен каталогів, розпочинаючи з кореневого) та ім‟я бібліотеки з визначенням нового класу. Наприклад, при створенні нового компонента класу TBtnNClick (див. п. 14.9.2) визначимо шлях:

C:\STUDENTS\SEMESTR2\ТС104\Ivanov\BtnNClick.cpp

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]