Збереження даних – додаток перегляду класів у CBuilder

Зміни, які нам треба внести у форму нашого застосування перегляду класів для забезпечення постійного зберігання даних, досить прямолінійні У правий нижній кут форми ми додамо кнопку із заголовком Імпорт Ця кнопка буде використовуватися користувачем для імпорту поточного обраного класу в базу даних Крім кнопки, ми додамо на форму три обєкти TTable, Які представлятимуть три визначені нами тільки що таблиці – класів, методів і властивостей

Встановіть назву бази даних (Database name) для таблиці класів в « \», Що дасть знати CBuilder про те, що таблиця повинна знаходитися в тій же директорії, що і сам додаток Оскільки це відносний шлях, програма буде працювати коректно незалежно від того, в яку директорію ми її синсталліруем Якщо ми поставимо абсолютний шлях (типу «C: \ Program Files \ Class View \»), нам доведеться інсталювати нашу систему в цю директорію для кор

ректно роботи Ми, звичайно, можемо задавати шлях під час запуску програми, але застосований нами підхід є найпростішим і дієвим Ми таким чином упевняємося, що всі частини нашого компонента були синсталлірова ни в одне і те ж місце, тим самим позбавляючи додаток від необхідності додаткових перевірок Ви можете запитати, чому було не привласнити додатком псевдонім (alias) BDE і не використовувати його Це більш трудомісткий процес і, отже, містить більше помилок Вам треба заводити псевдонім на машині кінцевого користувача, перевіряти, чи правильно все установле але, і т д Псевдоніми відмінно працюють в програмах, що працюють з мережевими або віддаленими базами даних, але надто перевантажують невеликі додатки типу нашого

Після встановлення назви бази даних перейдемо до назви таблиці (Table name) – встановимо його в NamesDBF Це та сама таблиця, яку ми трохи раніше створили Сам компонент-таблицю назвемо NameTable (Тобто змінимо значення її властивості Name) Я зовсім не завжди встановлюю персональні назви для компонентів, що використовуються в додатку, – тільки коли існує реальна можливість переплутати їх один з одним В даному випадку у нас на формі є три обєкти TTable, Які відрізняються один від одного тільки номерами, так що легко заплутатися Саме тому ми і назвемо їх осмислено – так, щоб можна було відразу зрозуміти, до якої з використовуваних нами таблиць відноситься обєкт

Визначивши повністю таблицю Names, виконайте все те ж саме для таблиць Methods і Properties Обидві таблиці будуть мати той же самий шлях до бази даних ( \) назва асоціюється з Methods таблиці буде MethodsDBF, а з Properties – PropsDBF Для всіх обєктів-таблиць встановіть прапор Active в true, щоб можна було безпосередньо використовувати їх у нашому коді

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

void __fastcall TForm1::ListBox1Click(TObject *Sender)

{

AnsiString s

/ / Отримуємо обраний елемент

for ( int i=0 i&ltListBox1-&gtItems-&gtCount ++i ) if ( ListBox1-&gtSelected[i] )

{

s = ListBox1-&gtItems-&gtStrings[i]

}

/ / Завантажуємо інші списки

ListBox2-&gtClear() ListBox3-&gtClear()

GetMethodsAndProperties(FstrFileNamec_str(), sc_str(), ListBox3, ListBox2 )

/ / Якщо який-небудь елемент був обраний,

/ / Йдемо далі – імпортуємо дані

/ / В базу даних

if ( ListBox1-&gtItemIndex &gt -1 )

{

Button1-&gtEnabled = true

}

}

Тепер із цим кодом кнопка Імпорт буде доступна тільки в тому випадку, якщо вибрано якесьнебудь значення у списку Для більшої впевненості спочатку встановіть властивість Enabled кнопки Імпорт в false, а то вона буде доступна відразу після запуску програми

Коли користувач натискає кнопку Імпорт, нам треба додавати дані в базу Для цього додайте обробник для події OnClick кнопки Імпорт з наступними рядками коду:

void __fastcall TForm1::Button1Click(TObject *Sender)

{

/ / Спочатку додаємо обраний елемент

/ / До списку

if ( ListBox1-&gtItemIndex = -1 )

{

AnsiString strClass = ListBox1-&gtItems-&gt Strings[ ListBox1-&gtItemIndex ]

/ / Додаємо його в базу даних

int nRecordNo = NameTable-&gtRecordCount NameTable-&gtAppend()

NameTable-&gtFieldValues[&quotClassName&quot] =  strClassc_str() NameTable-&gtFieldValues[&quotClassID&quot]  =

AnsiString(nRecordNo+1) try

{

NameTable-&gtPost()

}

catch ( Exception&amp te )

{

MessageBox(NULL, teMessagec_str(), &quotError&quot, MB_OK)

}

/ / Тепер обробляємо властивості

for ( int nProp=0 nProp&ltListBox3-&gtItems-&gtCount ++nProp )

{

PropertyTable-&gtAppend()

PropertyTable-&gtFieldValues[&quotClassID&quot]  = AnsiString(nRecordNo+1)

PropertyTable-&gtFieldValues[&quotPropertyNa&quot]  = ListBox3-&gtItems-&gtStrings[nProp] PropertyTable-&gtPost()

}

/ / І нарешті, обробляємо методи

for (int nMethod=0 nMethod&ltListBox2-&gtItems-&gtCount

++nMethod )

{

MethodTable-&gtAppend()

MethodTable-&gtFieldValues[&quotClassID&quot]  = AnsiString(nRecordNo+1)

MethodTable-&gtFieldValues[&quotMethod&quot]  =

ListBox2-&gtItems-&gtStrings[nMethod] MethodTable-&gtPost()

}

}

Цей код виконує кілька завдань По-перше, імя обраного класу додається в таблицю Names Унікальний ідентифікатор буде встановлений рівним номеру цього запису в таблиці, так що нам не доведеться генерувати його за допомогою якогось хитрого алгоритму або хвилюватися про те, що у двох записів будуть збігаються номери Ми надаємо базі даних подбати про унікальність ідентифікатора, зробивши його чимось кшталт «поля автоматичного прирощення» Отже, ідентифікатори класу нумеруються від 0 до кількості записів у базе1

Після того як головна запис додана в таблицю Names, ми повторюємо процес для двох, що залишилися списків і таблиць Немає потреби шукати обрані значення в цих списках, оскільки всі елементи в них представляють властивості (або методи), що належать обраному класу Зверніть увагу на властивість FieldValues обєктів-таблиць, яке ми використовуємо для присвоєння значення полю в базі Ця властивість має тип Variant Змінні типу Variant можуть містити будь-яку кількість полів будь-яких типів У даному випадку Variant може містити

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

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

Зверніть увагу на імена полів в таблицях Незважаючи на те що поле імен властивостей в таблиці PropsDBF називається у нас PropertyName, dBase підтримує тільки 10 символів у назві поля, так що нам доведеться скорочувати його назву до PropertryNa в нашому коді Якщо ми спробуємо використовувати повна назва, BDE не зможе його переварити і вирішить, що поле не знайдено Так що треба про це памятати Використовуйте розроблене нами раніше додаток перегляду полів баз даних для зясування необхідних імен полів (звичайно, можна використовувати і Database Desktop – утиліту для роботи з базами даних, що поставляється з CBuilder)

Після того як додаток скомпільовано, зібрано і запущено, його треба протестувати У деяких випадках при спробі запустити додаток безпосередньо з середовища CBuilder ви будете отримувати дивне повідомлення про помилку (Database Structure Corrupted – порушена структура бази даних) Якщо це відбувається, просто закрийте CBuilder і запустіть ваш додаток з Windows Explorer або з командного рядка Я, чесно кажучи, так і не зрозумів, чому виникає ця помилка, але виникає вона тільки в IDE CBuilder

Рис 174 Додаток перегляду та імпорту класів в дії

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

Ну що ж, тепер ми готові до створення нового, поліпшеного Майстри компонентів Ідея його створення подобається мені з двох причин По-перше, його описом я зможу довести дану главу до обсягу, який задовольнить мого редактора По-друге, це стане вашою стартовим майданчиком у написанні Майстрів, зокрема повнорозмірного Майстри компонентів + ​​+ Наш Майстер компонентів, на відміну від поставляється з CBuilder, дозволить вам не тільки вибрати

базовий клас, але і додати в компонент ще багато корисної інформації – він дозволить нам

«Підсаджувати», говорячи в термінах CBuilder, властивості з базового класу Він також дозволить нам заміщати методи в базовому класі Крім того, він дозволить нам визначати нові властивості і методи і додавати їх у клас компонента Коротше кажучи, це нова версія Майстри компонентів

– Майстер компонентів + ​​+

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

Для того щоб створити Майстри, треба спочатку створити той код, що робить його роботу Кращий спосіб зробити це – створити код для нього спочатку у вигляді додатку, а потім цей код перенести на каркас Майстри (З чим я познайомлю вас дещо пізніше), створивши додаток-Майстер Останнім кроком буде інсталяція Майстра – ми та її розглянемо, закінчивши з кодом Майстра

Наш Майстер буде реалізований у вигляді сторінкового діалогу, як це показано на рис 175 – 177 Три сторіночки, показані на малюнках, власне і утворюють в сукупності сторінковий діалог нашого Майстра на них представлено все, що нам треба знати про форму для нашого застосування

Для створення форми скористайтеся пунктом меню File д New, в якому в розділі форм виберіть форму сторінкового діалогу У цей діалог додайте три сторіночки, що відповідають показаним на рис 175 – 177 Як тільки ви з цим закінчите, можна буде перейти до написання коду

Рис 175 Сторінка 1 форми Майстри компонентів

Рис 176 Сторінка 2 форми Майстри компонентів

Рис 177 Сторінка 3 форми Майстри компонентів

Почнемо ми, природно, з першої сторінки Нам треба завантажити в знаходиться на ній комбінований список класів класи, що знаходяться у створеній нами раніше базі даних Це варто зробити на самому початку – При створенні форми, тобто в обробнику події Create форми Отже, додайте обробник для цієї події, назвавши його FormCreate, А в нього додайте наступний код:

void __fastcall TPagesDlg::FormCreate(TObject *Sender)

{

/ / Завантажуємо комбінований список

Table1-&gtFirst()

while ( Table1-&gtEof )

{

ComboBox1-&gtItems-&gtAdd(Table1-&gtFieldValues[&quotCLASSNAME&quot]) Table1-&gtNext()

}

}

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

void __fastcall TPagesDlg::ComboBox1Change(TObject *Sender)

{

/ / Отримуємо імя обраного класу

Table1-&gtFilter = &quotCLASSNAME = &quot + ComboBox1-&gtText + &quot’" Table1-&gtFiltered = true

/ / Переходимо на цю запис

Table1-&gtLast()

/ / Отримуємо ідентифікатор класу

AnsiString strClassId = Table1-&gtFieldValues[&quotClassID&quot] Table1-&gtFiltered = false

/ / Завантажуємо властивості

Table2-&gtFilter = &quotCLASSID = &quot + strClassId + &quot’" Table2-&gtFiltered = true

Table2-&gtFirst() ListBox1-&gtClear() while ( Table2-&gtEof )

{

ListBox1-&gtItems-&gtAdd( Table2-&gtFieldValues[&quotMethod&quot] ) Table2-&gtNext()

}

/ / Завантажуємо методи

Table3-&gtFilter = &quotCLASSID = &quot + strClassId + &quot’" Table3-&gtFiltered = true

Table3-&gtFirst() ListBox3-&gtClear() while ( Table3-&gtEof )

{

ListBox3-&gtItems-&gtAdd( Table3-&gtFieldValues[&quotPropertyNa&quot]  ) Table3-&gtNext()

}

}

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

Наступна група керуючих елементів, яку нам треба обробити, – це кнопки переміщення елементів між списками обраних та існуючих властивостей (методів) Ці кнопки будуть використовуватися для внесення властивостей і заміщення методів базового класу в наш клас У другу сторінку нашого діалогу додайте два обробника для кнопок> і < (Кнопки 3 і 4 форми):

void __fastcall TPagesDlg::Button3Click(TObject *Sender)

{

/ / Якщо що-небудь вибрано в першому списку

if ( ListBox1-&gtItemIndex = -1 )

{

ListBox2-&gtItems-&gtAdd(  ListBox1-&gt Items-&gtStrings[ListBox1-&gtItemIndex]  )

ListBox1-&gtItems-&gtDelete(  ListBox1-&gtItemIndex )

}

}

//——————————————————–

void __fastcall TPagesDlg::Button4Click(TObject *Sender)

{

/ / Якщо що-небудь вибрано в другому списку

if ( ListBox2-&gtItemIndex = -1 )

{

ListBox1-&gtItems-&gtAdd(  ListBox2-&gt Items-&gtStrings[ListBox2-&gtItemIndex]  )

ListBox2-&gtItems-&gtDelete(  ListBox2-&gtItemIndex )

}

}

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

void __fastcall TPagesDlg::Button6Click(TObject *Sender)

{

/ / Якщо що-небудь вибрано в першому списку

if ( ListBox3-&gtItemIndex = -1 )

{

ListBox4-&gtItems-&gtAdd(  ListBox3-&gt Items-&gtStrings[ListBox3-&gtItemIndex]  )

ListBox3-&gtItems-&gtDelete(  ListBox3-&gtItemIndex )

}

}

//——————————————————

void __fastcall TPagesDlg::Button7Click(TObject *Sender)

{

/ / Якщо що-небудь вибрано в другому списку

if ( ListBox4-&gtItemIndex = -1 )

{

ListBox3-&gtItems-&gtAdd(  ListBox4-&gt Items-&gtStrings[ListBox4-&gtItemIndex]  )

ListBox4-&gtItems-&gtDelete(  ListBox4-&gtItemIndex )

}

}

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

Джерело: Теллес М – 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>

*

*