Компонент FilterEdit в CBuilder

На сторінках глави 4 ми обговорили можливість відсівати невідповідні символи з числа введених користувачем Тоді ми це робили перехоплюючи вводяться користувачем в поля редагування символи і не допускаючи появи небажаних в поле редагування Оскільки це доводилося робити для кожного окремого поля на формі, код розростався до неймовірних розмірів Прийшов час вирішити цю приватну проблему, створивши компонент для фільтрування символів

Цей приклад буде вельми корисний вже з точки зору створення компонента, який ви напевно будете не раз використовувати в ваших додатках, але крім цього він ще й покаже вигоди використання компонентів VCL, а не ActiveX У VCL можна створювати нові компоненти з ваших же базових компонентів, роблячи дочірні компоненти вузькоспеціалізованими на вирішенні конкретних завдань І для демонстрації цих можливостей в даному прикладі ми створимо базовий компонент, який буде фільтрувати будь-який вид введення, а потім створимо наследующий від нього клас, фільтруючий специфічні види вводу

Як і в будь-якому нормальному проектуванні, ми почнемо з формулювання проблеми, яку хочемо вирішити В даному випадку проблема полягає в тому, що нам потрібна можливість відфільтровувати деякі види вводяться користувачем значень, а саме все, що не є цифрою Нам потрібен компонент, який можна було б використовувати у всіх формах, що допускають введення тільки числових значень Така приватна проблема

Приватну проблему можна легко узагальнити – від компонента, який пропускає тільки певні значення, перейдемо до компоненту, який може або пропускати, або, навпаки, блокувати певні значення Припустимо, наприклад, що ви хочете випустити працююче демонстраційне додаток, проте працююче не до такої міри, щоб користувачі могли ним користуватися і не платити вам Одне рішення може полягати в тому, щоб вводити в програму все, що завгодно, якщо у введенні не присутній небудь символ, наприклад буква N Можливий і інший підхід – можна перераховувати тільки ті, символи, які користувачеві дозволяється вводити (з подібним ми стикаємося дуже часто – наприклад, вводити тільки цифри) Узагальнюючи обидві концепції ми створимо компонент, що дозволяє або вводити всі символи, крім перерахованих, або, навпаки, вводити тільки перераховані, і нічого крім них

У даному прикладі ми збираємося втілити не тільки приватне рішення, а й загальне, яке стане базовим класом для приватного рішення про дозвіл введення тільки цифр

Для початку нам треба визначити властивості класу для приватного рішення – керуючого елемента, що допускає введення тільки цифр Як зясовується, таких немає Все, що ми хочемо, це щоб наш керуючий елемент поводився точно також, як веде себе нормальне поле редагування, не дозволяючи користувачеві вводити нічого, крім цифр

Загальне ж рішення це окреме питання Давайте займемося ім

У разі узагальненого рішення – про дозвіл або заборону введення певних даних в керуючий елемент-поле редагування – нам потрібні від користувача два блоки

інформації, і ці блоки стануть властивостями нашого керуючого компонента Першим властивістю стане інформація про те, які дані є дозволеними (або забороненими) для введення в керуючий елемент Для наших цілей цілком підійде рядок, в якій будуть перераховані всі символи, що відповідають цій умові Це заодно дозволить вам набратися досвіду в роботі з властивостями, тип яких не є базовим Другим властивістю стане прапор, що показує, чи є символи в рядку тими, крім яких вводити нічого не можна (значення прапора = true), або ж тими, які вводити не можна (значення прапора = false) Властивість, що визначає набір символів, ми назвемо Allowed (для дозволених символів), а властивість-прапор

– Include (тобто чи будуть символи включені в текст, чи ні)

Для втілення базового компонента створіть в CBuilder новий компонент і надайте йому імя TFilterFdit Встановіть йому як предка клас TCustomEdit Це надасть нам всі можливості компонента-поля редагування і дозволить нам відфільтровувати непотрібні дані, що не дублюючи всі без виключення можливості лежить в його основі керуючого елемента-поля редагування Windows Після того, як базовий компонент був згенерований Майстром компонентів CBuilder, в нього треба додати необхідні нам властивості Додайте наступні рядки коду в заголовний файл компонента:

#include &ltvcl\Systemhpp&gt

//——————————————————————-

class TFilterEdit : public TCustomEdit

{

private:

System::AnsiString     FFilterString bool     FbInc

protected:

virtual void __fastcall KeyPress(char &ampKey) public:

    fastcall TFilterEdit(TComponent* Owner)

__published:

__property System::AnsiString Allowed = {read=FFilterString, write=FFilterString}

__property bool Include = {read=FbInc, write=FbInc, default=true}

}

У даному випадку ми додаємо кілька внутрішніх змінних-членів класу для зберігання фактичних значень властивостей і заміняємо функцію KeyPress – член класу TCustomEdit для власне фільтрування вводяться даних

Ми додали властивість Allowed, яке представляє з себе рядок типу AnsiString, і властивість Include, яке на ролі прапора, логічного (boolean) типу Зверніть увагу на те, що тип AnsiString укладений в області (namespace) System, так що нам треба задавати його, використовуючи оператор дозволу видимості System :: для того, щоб повідомити компілятору, де знаходиться тип AnsiString Крім того, ми повинні підключити заголовний файл Systemhpp з каталогу заголовних файлів системи (CBuilder \ include \ vcl) щоб отримати опис класу Object Inspector і інші інструменти CBuilder розуміють тип AnsiString, так що користувач зможе редагувати ці рядки, використовуючи стандартний редактор рядків системи

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

зробленим нами раніше:

__fastcall TFilterEdit::TFilterEdit(TComponent*  Owner)

: TCustomEdit(Owner)

{

FbInc = true

}

Єдиним кодом для компонента стане код для методу KeyPress, який перевірятиме вводиться символ на входження в список Allowed і, залежно від значень Allowed і Include, або вирішувати, або не дозволяти введення Ось як цей код буде виглядати:

void __fastcall TFilterEdit::KeyPress(char &ampKey)

{

/ / Перевіряємо натискання клавіші

for ( int i=0 i&ltFFilterStringLength() ++i ) if ( Key == FFilterString[i] )

if ( FbInc )

return else

{

Key = 0 return

}

/ / Не знайти символу, що вводиться

/ / Дуже погано if (FbInc) Key = 0

}

Як завжди, ніяких чудес Тут ми просто переміщаємося по всіх існуючих в заданій терміні символам в пошуках введеного користувачем Якщо ми його знаходимо, і при цьому значення прапора Include – істина (True), символ нас потроює, і функція повертає управління керуючому елементу – полю редагування Якщо символ не знайдений, цикл завершується, і знову перевіряється значення прапора Include Якщо його значення істинно, символ не є допустимим, оскільки в іншому випадку він мав би бути в списку Якщо це так, натискання клавіші обнуляється, що означає для керуючого елемента, що обробляти його не треба

Після того, як компонент TFilterEdit створений, можна створити базується на ньому клас TNumericEdit Цей клас навіть простіше, ніж TFilterEdit, оскільки він допускає введення тільки числових значень Для того, щоб рухатися далі, доведеться спочатку відкомпілювати і синсталліровать компонент TFilterEdit, проробивши всю звичайну процедуру Для того, щоб переконатися в тому, що компонент працює належним чином, протестуйте його, вводячи різні значення для Allowed і Include Якщо все добре, можна робити наступні кроки

Після того, як ви синсталліровалі новий компонент в CBuilder, ви можете його використовувати для будь-яких цілей Серед цих цілей може бути і створення класу, що посяде від цього компонента Якщо ви працювали в інших системах, в яких наслідувати можна було тільки від базових класів системи, ви напевно з радістю прийміть подібне цінне додавання

можливостей Памятайте – після того, як ви синсталліровалі компонент, він стає частиною базової системи CBuilder Немає жодних відмінностей між компонентом, який написали ви і компонентом, створеним командою Borland VCL Можливість розширювати систему CBuilder робить її ідеальною для роботи в корпоративному середовищі

Синсталліровав компонент TFilterEdit, скористайтеся Майстром компонентів для створення нового компонента TNumericEdit У цього нового компонента предком буде клас TFilterEdit (який тепер теж буде бути присутнім в комбінованому списку)

Все, що вам треба змінити в коду для класу TNumericEdit, це конструктор класу – для того, щоб ініціалізувати властивості Include і Allowed так, щоб користувач міг вводити тільки числові значення Ось як виглядатимуть ці зміни:

__fastcall TNumericEdit::TNumericEdit(TComponent*  Owner)

: TFilterEDit(Owner)

{

Allowed = &quot1234567890"

Include = true

}

На жаль, це не все Є якась проблема Для того, щоб побачити, в чому справа, додайте невеликий шматок коду для створення нового компонента Ось як виглядає цей код тестування:

void __fastcall TForm1::FormCreate(TObject *Sender)

{

pEdit = new TNumberEdit(this) pEdit-&gtLeft = 10

pEdit-&gtTop = 10

pEdit-&gtWidth = 100

pEdit-&gtHeight = 30 pEdit-&gtParent = this

pEdit-&gtAllowed = &quotABCDEFG" pEdit-&gtInclude = false

}

Якщо ви тепер додасте заголовний файл для компонента TNumericEdit в цю форму, то побачите, що наведений вище код скомпіліруется без помилок У чому ж тут справа Проблема полягає в тому, що властивості з компонента TFilterEdit були успадковані в TNumericEdit, і користувач має можливість замістити ті установки, які ви зробили в класі вашого нового компонента Це нормальна поведінка класу C + +, так як розділ published опису класу аналогічний секції public Очевидно, що подібний варіант роботи нашого компонента нас не влаштовує Чи є можливість якось впоратися з виниклою проблемою НЕ переписуючи весь код для базового компонента заново У деякому роді так Отже, насправді проблема з властивостями, описаними в розділі published, полягає в тому, що ці властивості завжди будуть доступи в будь-якому успадковує класі Тобто, іншими словами, ми не можемо перекрити програмісту можливість використання властивостей Allowed і Include в класах-спадкоємців при теперішньому стані речей

Так як же впоратися з проблемою В принципі, єдиним шлях, при якому ви можете гарантувати правильність роботи властивостей, це створення абстрактного базового класу для обох компонентів, в якому ці властивості були б віднесені до захищених Наприклад, ми могли б створити клас TBaseFilterEdit, який би виглядав наступним чином:

class TBaseFilterEdit : public TCustomEdit

{

private:

System::AnsiString     FFilterString bool     FbInc

protected:

virtual void __fastcall KeyPress(char &ampKey)

__property System::AnsiString Allowed = {read FFilterString write FFilterString}

__property bool Include = {read=FbInc write=FbInc default = true}

public:

    fastcall TBaseFilterEdit(TComponent* Owner) : TCustomEdit(Owner)

{

}

__published:

}

Тепер клас TFilterEdit буде виглядати так: class TFilterEdit: public TBaseFilterEdit

{

private: protected: public:

    fastcall TFilterEdit(TComponent* Owner)

__published:

__property Allowed

__property Include

}

У цьому класі властивості Allowed і Include заново поміщаються в секцію published, щоб кінцевий користувач міг бачити їх у Object Inspector Клас TNumericEdit також успадковує від класу TBaseFilterEdit:

class TNumericEdit : public TBaseFilterEdit

{

private: protected: public:

    fastcall TNumericEdit(TComponent* Owner)

__published:

}

Зверніть увагу на те, що в цьому класі властивості Allowed і Include не переважають, так що компонент типу TNumericEdit не дозволяє кінцевому користувачеві використовувати ці властивості Усередині класу існує прямий доступ до властивостей Allowed і Include, оскільки вони є захищеними членами класу Змінні-члени класу, що представляють ці властивості в базовому класі (FbInc і FFilterString) недоступні в обох наследующих класах Повний вихідний код всіх трьох класів може бути знайдений – як ви вже здогадалися – на прикладеному компакт-диску

Ми проробили досить важкий шлях до переможного фіналу замість того, щоб відразу поговорити про кінцевий базовому класі з двох причин По-перше, ми зрозуміли причину того, що всі компоненти в VCL будуються навколо абстрактних класів типу TCustomEdit або TCustomListBox

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

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

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

Джерело: Теллес М – Borland C + + Builder Бібліотека програміста – 1998

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*