Форми до створення C + + Builder

Яким саме чином ви створюєте нове вікно Це один з найважливіших аспектів всієї системи багатодокументна додатків Якщо вам доводилося працювати з іншими системами, ви, мабуть, звикли довіряти створення дочірніх вікон самій системі і знаєте, що створення дочірніх форм самостійно – зазвичай дуже хворобливе підприємство Каркаси (frameworks) створені для конкретного виду роботи, і тому дуже скрутно буває обходити їх обмеження для того, щоб зробити щось по-своєму Оскільки система CBuilder заснована на компонентах, вона навіть не намагається робити речі по-своєму, надаючи вам можливість робити все так, як вам хочеться

Для того щоб обгрунтувати вищесказане, давайте звернемося до обробника команди меню Файл – Новий Цей обробник повинен створити та відобразити на екрані нову дочірню форму Як правило, вам хотілося б мати можливість змінювати назву форми, щоб воно несло смислове навантаження У даному випадку ми озаглавим форму «Scribble – дочірнє» Для цього додайте новий обробник для пункту меню Файл – Новий і в нього додайте наступні рядки:

void __fastcall TForm2::New1Click(TObject *Sender)

{

TForm1 * pForm1 = new TForm1 (Application) pForm1-> Caption = Scribble _ дочірнє;

}

Дивним виглядає відсутність у вищевказаному коді яких згадок про багатодокументна (MDI) Нова форма створюється як дочірнє вікно програми Властивість Form Style встановлено в fsMDIChild, І тому при створенні форма автоматично стає дочірнім вікном багатодокументного додатки Як ви бачите, вся робота по створенню форми як дочірньої для головної форми робиться за вас компонентом як таким

Другий рядок коду просто привласнює властивості Caption форми значення «Scribble – дочірнє» цю назву і буде відображено на панелі заголовка дочірнього вікна, коли воно зявиться на екрані Після того як наберете зазначені рядки коду, скомпілюйте і запустіть додаток Виберіть команду меню Файл – Новий, і, з красивим відступом від попереднього, зявиться нове дочірнє вікно

Як ви, напевно, помітили, перший дочірнє вікно, яке зявляється на екрані відразу при запуску програми, не має заголовка «Scribble – дочірнє», оскільки воно було створено автоматично і не пройшло через процес, передбачений вибором команди Файл д Новий Для вирішення цієї проблеми є два шляхи Скасуйте автоматичне створення дочірньої форми в своєму додатку і починайте роботу програми з порожнього батьківського вікна – такий варіант широко поширений в програмах Windows Друге рішення лежить у привласненні початкового значення властивості Caption вже під час проектування програми і приєднання до нього унікального значення змінної, що відповідає номеру дочірнього вікна, при створенні вікон під час виконання Стандартний в Windows варіант – використання деякого імені («Scribble – Дочірнє », наприклад) і номера дочірнього вікна (по порядку створення) Так, наприклад, перше вікно матиме назву «Scribble – дочірнє 1», друге –

«Scribble – дочірнє 2» і т д

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

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

Для того щоб прибрати дані з дочірніх форм, нам доведеться змінити код для дочірніх форм

(Form1) Ось змінений код для вихідного файлу:

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

#include &ltvcl\vclh&gt

#pragma hdrstop

#include &quotUnit1h&quot

#include &quotMainFormh&quot

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

#pragma resource &quot*dfm&quot TForm1 *Form1

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

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

FbMouseDown = FALSE

}

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

void __fastcall TForm1::OnMouseDown(TObject *Sender, TMouseButton Button,

TShiftState Shift, int X, int Y)

{

FbMouseDown = TRUE

/ / Переміститися в початкову точку

Canvas-&gtMoveTo(X,Y)

/ / Вводимо в головну форму нові дані

/ / Зауважте: ми очищаємо всі існуючі точки

Form2-&gtClearPoints Form2-&gtAddPoint( X,Y )

}

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

void __fastcall TForm1::OnMouseMove(TObject *Sender, TShiftState Shift,

int X, int Y)

{

if ( FbMouseDown )

{

Canvas-&gtLineTo( X,Y )

/ / Оновлюємо головну форму новими даними

Form2-&gtAddPoint( X,Y )

}

}

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

void __fastcall TForm1::OnMouseUp(Toblect *Sender, TMouseButton Button,

TShiftState Shift, int X, int Y)

{

FbMouseDown = FALSE

}

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

void __fastcall TForm1::OnPaint(TObject *Sender)

{

if ( Form2-&gtNumberOfPoints() &gt 0 )

{

int X = 0, Y = 0

/ / Отримуємо першу точку Form2-> GetPoint (0, X, Y) Canvas-> MoveTo (X, Y)

/ / Проходимо по кожній точці, отримуємо її з

/ / Головної форми і перемальовували

for ( int i=1i&ltForm2-&gtNumberOfPoints()++i )

{

Form2-&gtGetPoint( i,X,Y ) Canvas-&gtLineto( X,Y )

}

}

}

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

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

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

#ifndef Unit1H

#define Unit1H

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

#include &ltvcl\Classeshpp&gt

#include &ltvcl\Controlshpp&gt

#include &ltvcl\StdCtrlshpp&gt

#include &ltvcl\Formshpp&gt

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

class TForm1 : public TForm

{

__published: // IDE-managed Components

void __fastcall OnMouseDown(TObject *Sender, TMouseButton Button,

TShiftState Shift, int X, int Y)

void __fastcall OnMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)

void __fastcall OnMouseUp(TObject *Sender, TMouseButton Button,

TShiftState Shift, int X, int Y)

void __fastcall OnPaint(TObject *Sender) private: // User declarations

BOOL FbMouseDown

public: // User declarations

__fastcall TForm1(TComponent* Owner)

}

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

extern TForm1 *Form1

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

#endif

Отже, ми прибрали всі ці чудові рядки коду з опису класу Form1 і перемістили їх, додавши дивні виклики методів в клас Form2 Яка ж функція цих рядків у класі Form2 Ви зрозумієте, що ж насправді відбувається, якщо додасте нижченаведені рядки в заголовний файл Unit2h:

const int MaxPoints = 100 class TForm2 : public TForm

{

__published: // IDE-managed components TMainMenu *MainMenu

TMenuItem *File1

TMenuItem *New1 TMenuItem *Exit1 TMenuItem *Update1 TMenuItem *AllWindows1

void __fastcall New1Click(TObject *Sender) private: // User declarations

int FnPoint

int FPointX[MaxPoints+1] int FPointY[MaxPoints+1] public // User declarations

__fastcall TForm2(TComponent* Owner) void ClearPoint(void)

{

FnPoint = 0

}

void AddPoint(int X, int Y)

{

if ( FnPpoint &lt MaxPOints )

{

FPointX[FnPoint] = X FPointY[FnPoint] = Y FnPoint++

}

}

int NumberOfPoints(void)

{

return FnPoint

}

void GetPoint( int Index, int&amp X, int&amp Y )

{

if ( Index &gt= 0 &amp&amp Index &lt FnPoint )

{

X = FPointX[Index] Y = FPointY{index]

}

}

}

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

extern TForm2 *Form2

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

#endif

Чи не здається вам наведений код знайомим Повинен би Велика частина його просто скопійована зі старої форми Scribble і упакована в методи цього обєкта Цей процес називається инкапсуляцией (Encapsulation) і є важливим моментом в програмуванні на C + + Інкапсуліруя доступ до зміни і відновлення даних в методи обєкта, ми захищаємо дані від псування, яку можуть здійснити обєкти Крім того, оскільки ми прибрали дані з безпосередньо змінюються блоків програми, ми залишили відкритою можливість змінювати спосіб зберігання даних Уявіть, наприклад, що дані більше не зберігаються у вигляді простого статичного масиву, як зараз Уяви ті, що вони зберігаються у вигляді якогось динамічного масиву або навіть хеш-таблиці (hash table) Можливо, нарешті, що точки насправді зберігаються на диску Безвідносно того, як зберігаються точки насправді, подібне уявлення дозволить нам заховати справжній формат даних від інших обєктів Абсолютно не важливо, як перетвориться обєкт Form2 з точки зору даних, адже поки сигнатура (параметри і типи значень, що повертаються функцій) методів ClearPoints, AddPoint, NumberOfPoints  іGetPoint  не змінюється, обєктуForm1  нема чого знати про це Це і є

«Маскування даних» в С + + Самі дані заховані в методах, які використовуються для звернення до даних Маскування даних в чистому вигляді застосовується в концепції властивостей компонентів VCL, які ми розглянемо дещо пізніше Я завів цю розмову тільки тому, що багато хто чомусь вважають концепцію властивості не обєктно-орієнтованої і незручною Як ми побачимо трохи далі, це зовсім не так

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

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

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

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

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

void __fastcall TForm2::AllWindowsClick(TObject *Sender)

{

for ( int i=0 i&ltMDIChildCount ++i )

{

Form1 *pForm = static_cast&ltTForm1 *&gt(MDIChildren[i]) if ( pForm )

pForm-&gtInvalidate()

}

}

Що ж тут відбувається У форми є властивість MDIChildCount, яке дорівнює поточному кількістю відкритих дочірніх вікон Ця властивість є насправді у всіх форм, але його значення дорівнює 0, якщо стиль форми не є fsMDIForm Крім кількості дочірніх вікон, у форми є властивість, зване MDIChildren, яке є динамічним масивом покажчиків на форми Ми проходимо по всіх дочірнім формам нашої батьківської форми і оновлюємо їх, використовуючи метод Invalidate

Якщо програмування під Windows не є для вас звичним, то модель малювання вікна здасться вам трохи дивною Малювання повязане зі скасуванням дії (invalidation) частин форм Скасування дії означає, що операційній системі надсилається повідомлення про те, що частина вікна (або вікно цілком) треба перемалювати Хто завгодно може повідомити вікна, що воно має бути перерисовано, просто викликавши метод Invalidate цього вікна (або форми)

Останнє, про що варто згадати у звязку з нашим невеликим шматочком коду, – це оператор static_cast Функція static_cast є новою для C + +, вона зявилася тільки в останній версії стандарту ANSI C + + Функція static_cast намагається привести обєкт до заданого типу Загальний вигляд запису оператора static_cast виглядає наступним чином:

T *pT = static_cast&ltT *&gt(someobjpointer)

де T – Це тип (як TForm1 в прикладі вище), що визначений у системі, а someobjpointer – Заданий покажчик Зверніть увагу на те, щоб цей параметр був покажчиком, інакше ви отримаєте помилку

Якщо перетворення пройшло успішно, повертається значення – це коректний покажчик на обєкт типу T Якщо перетворення не було успішним, повертається значення NULL Тому перевірте повернене значення на рівність NULL перед тим, як використовувати метод Invalidate для цього обєкта Це основна смислове перевірка, яка доступна вам у вашому додатку Якщо ви працюєте з покажчиками, перед зверненням перевіряйте їх значення на рівність NULL

Залишилася остання річ, яку ми повинні зробити, щоб завершити додаток Scribble

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

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

Додайте новий обробник для пункту меню Файл д Вихід і додайте в нього наступні рядки: void __ fastcall TForm2 :: ExitClick (Tobjest * Sender)

{

Application-&gtTerminate()

}

Обєкт Application (Додаток) – це глобальний інтерфейс із завданням в операційній системі, яка відповідає нашому додатком Метод додатки Terminate звільняє всі існуючі форми, покажчики і керуючі елементи і потім закриває всі вікна програми Application-&gtTerminate() – Це найкращий метод для завершення роботи програми, і він може безпечно викликатися майже що з будь-якого місця в програмі Не треба просто закривати вікна, сподіваючись, що все добре використовуйте метод Terminate

Форма може бути створена без заголовка Що більш важливо, початкові параметри форми можуть бути змінені програмно до того, як форма буде відображена на екрані Це здійснюється за допомогою методу форми CreateParams (Створити параметри)

Форми мають безліч властивостей Наприклад, властивістьCaption  (Заголовок) управляє текстом, відображеним на панелі заголовка форми Властивість Canvas (Полотно) використовується для малювання в клієнтської області форми

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

опосередковано, асоційованими їх з подією Це дозволяє динамічно змінювати обробники подій під час виконання

Файли опису форми (Form Definition Files, DFM) можна переглянути в редакторі як звичайні текстові файли

Копіювання проекту має проводитися окремо від збереження проекту під новим імям при використанні команди File д Save Project As (зберегти проект як)

У CBuilder легко і просто використовувати растрові малюнки Вони можуть бути завантажені за допомогою методу LoadFromFile (Завантажити з файлу) і намальовані за допомогою методу Draw (Намалювати) обєкта Canvas

Форми багатодокументна додатків (Multiple Document Interface, MDI) – це, в принципі, звичайні форми зі специфічним значенням властивості Form Style (Стиль форми) – fsMDIForm Дочірні вікна точно такі ж, але у них значення властивості Form Style встановлено в fsMDIChild

За допомогою методу Application-&gtTerminate() рекомендується закінчувати роботу програми От і все з другої главою У наступному розділі ми почнемо вивчення графіки в CBuilder на

прикладі створення невеликої забавної іграшки для скрашіванія дозвілля

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

*

*