Граф_ред С++ .ppt
- Количество слайдов: 21
Лекція 15 Дружні функції (заверш. ). Програмування графічного редактора 23. 04. 2012 Іван Хвищун
Основні правила використання дружніх функцій Друзі класу не є членами класу. Їх визначають поза класом, для якого вони оголошуються друзями, а про особливі відносини між ними і даним класом свідчить спеціальне оголошення із специфікатором оголошення friend. Оголошення дружнього класу означає, що в дружньому класі доступні всі компоненти оголошуваного класу. Дружні даному класу функції не є членами цього класу. Тому вони не можуть бути викликані з об'єкту-представника класу, для якого була оголошена другом дана функція, за допомогою операції доступу до члена класу.
Дружня функція може бути функцією-членом іншого раніше оголошеного класу. При цьому само визначення дружньої функції необхідно розташовувати після оголошення класу, іншому якого була оголошена дана функція. Це не дуже зручно і красиво, та зате працює. Дружня функція не має this-вказівника для роботи з класом, що містить її оголошення як дружню функцію. Дружба - це всього лише доповнення принципу інкапсулювання. Дружні відносини не успадковуються. Дружні функції не мають доступу до членів похідного класу, чиї базові класи містили оголошення цих функцій. Діти не відповідають за відносини своїх батьків.
Вказівник this Ми зазначали, що якщо деяка ф-ція є компонентою об’єкта, то її оператори можуть звертатись до членів-даних цього об’єкта за іменем, не додаючи ім’я об’єкта. Якщо ми створимо де-кілька об’єктів, то в кожному з них будуть однойменні члени-дані. Оскільки для всіх об’єктів одного класу є тільки 1 екземпляр кожної ф-ції-члена, то як цим ф-ціям знати членів-дані якого об’єкта їм потрібно обробляти. Ми знаємо, що в пам’яті кожному об’єкту створюється прихований вказівник this, який містить адресу початку об’єкта в пам’яті.
Правила використання вказівника this: § Кожному об’єкту при його оголошенні надають свій прихований вказівник this. § this-вказівник статичні ф-ції не мають. § this-вказівник оголошувати не потрібно. § this передається як прихований аргумент у всі нестатичні члени ф-ції свого об’єкта. § this-вказівник є локальною змінною і за межами свого об’єкта він є недоступним. § Звертатись до this-вказівника можна за іменем this або за адресою * this.
Програмування графічного редактора 1. Створимо папку My. Gr. RED, запустимо C++ Builder 2010 у віконному режимі і запишемо у нашу папку пустий проект. 2. Ставимо на форму 2 компоненти TImage, розташуємо їх у нижній лівій частині форми у вигляді двох квадратів розміром 20 х20 пікселів. Це будуть віконця для вибору основного і допоміжного кольорів. Назвемо їх Image 1 і Image 2. 3. Ще один TImage розташуємо так, щоб він займав майже всю площу форми. Це буде наш мольберт. Назвемо його Image 3.
4. Ставимо внизу форми ще одну компоненту TImage, на якій пізніше розмістимо палітру кольорів. 5. Тому вона повинна мати таку довжину, щоб на ній помістилося 10 квадратиків по 20 х20 пікселів. Назвемо її Image 4. 6. Ставимо на форму кнопку TSpeed. Button, розташувавши її у верхньому лівому куті форми і назвавши її SBBrush. Щоб кнопка фіксувалась у натисутому та відпущеному станах, встановимо значення її властивості Group. Index в 1, а Allow. All. Up в true. Завантажимо у властивість Glyph піктограму пензлика (Brush. bmp).
7. Нижче кнопки SBBrush ставимо ще одну компоненту Tspeed. Button з назвою SBColor. Вона відповідатиме за вказівник кольору піксела при малюванні. Також встановимо значення її властивості Group. Index в 1, а Allow. All. Up в true. Тепер тільки одна із цих двох кнопок буде у натиснутоу стані. Завантажимо у її властивість Glyph піктограму one 2 one. bmp. 8. Поставимо на форму Open. Picture. Dialog. 9. Поставимо на форму компоненту Main. Menu Створимо розділ Файл з підрозділом Відкрити.
з підрозділом Відміна. Назвемо цей підрозділ Undo.
Створимо обробники подій. 10. У заголовний файл модуля вставимо оператор: Graphics: : TBitmap * Bit. Map = new Graphics: : TBitmap; Цим ми створюємо об’єкт Bit. Map типу TBit. Map, у якому буде зберігатись зображення для його відновлення, в разі потреби, командою Відміна. 11. Для події On. Create форми створимо її обробник: // задаємо властивості пензля для основного і допоміжного кольорів Image 1 ->Canvas->Brush->Color = cl. Black; Image 2 ->Canvas->Brush->Color = cl. White; // заповнимо віконця основного і допоміжного кольорів Image 1 ->Canvas->Fill. Rect (0, 0, Image 1 -> Width, Image 1 -> Height)); Image 2 ->Canvas->Fill. Rect (0, 0, Image 2 -> Width, Image 2 -> Height)); // задаємо ширину елементів палітри кольорів int HW = Image 4 ->Width / 10;
//зафарбуємо елементи палітри кольорів for ( int i = 1; i <=10; i++) { switch (i) {case 1: Image 4 ->Canvas->Brush->Color = cl. Black; break; case 2: Image 4 ->Canvas->Brush->Color = cl. Aqua; break; case 3: Image 4 ->Canvas->Brush->Color = cl. Blue; break; case 4: Image 4 ->Canvas->Brush->Color = cl. Fuchsia; break; case 5: Image 4 ->Canvas->Brush->Color = cl. Green; break; case 6: Image 4 ->Canvas->Brush->Color = cl. Lime; break; case 7: Image 4 ->Canvas->Brush->Color = cl. Maroon; break; case 8: Image 4 ->Canvas->Brush->Color = cl. Red; break; case 9: Image 4 ->Canvas->Brush->Color = cl. Yellow; break; case 10: Image 4 ->Canvas->Brush->Color = cl. White; } Image 4 ->Canvas->Rectangle ( (i -1) * HW, 0, i *HW, Image 4 -> Height); }
// малюємо лінії на канві ( для прикладу) Image 3 -> Canvas -> Move. To (0, 0); Image 3 -> Canvas -> Line. To (Image 3 -> Width, Image 3 -> Height); Image 3 -> Canvas -> Move. To (0, Image 3 -> Height ); Image 3 -> Canvas -> Line. To (Image 3 -> Width, 0); Bit. Map -> Assign (Image 3 -> Picture); } Тут ми задали кольори вікон: основного (Image 1) – білий і допоміжного (Image 2) – чорний. Функцією Fill. Rect заливаємо вікна цими кольорами. Потім формуємо палітру кольорів з допомогою ф-ції Rectangle. Потім малюємо діагональні лінії на Image 3. Останній оператор запам’ятовує малюнок з Image 3 в об’єкті Bit. Map методом Assign.
12. Активізуємо на формі Image 3 і в Object Inspector, перейшовши на закладку Events, створимо обробник події От. Mouse. Down і запрограмуємо його так: if (( Sender == Image 4) || SBColor->Down) // режим установки основного и допоміжного кольорів { if (Button == mb. Left) { // установка основного кольору Image 1 ->Canvas->Brush->Color = ((TImage *)Sender) ->Canvas->Pixels[X][Y]; Image 1 ->Canvas->Fill. Rect (0, 0, Image 1 ->Width, Image 1 ->Height)); } else { // установка допоміжного кольору Image 2 ->Canvas->Brush->Color = ((TImage *)Sender)-> Canvas->Pixels[X][Y]; Image 2 ->Canvas->Fill. Rect(0, 0, Image 2 ->Width, Image 2 ->Height)); } }
else { X 0 = X; Y 0 = Y; if (SBPen->Down) { // режим олівця Image 3 ->Canvas->Move. To(X, Y); Image 3 ->Canvas->Pen->Color = Image 1 ->Canvas->Brush-> Color; } else if (SBLine->Down) // режим лінії { X 1 = X; Y 1 = Y; Image 3 ->Canvas->Pen->Mode = pm. Not. Xor; Image 3 ->Canvas->Pen->Color = Image 1 ->Canvas->Brush-> Color; } else if (SBBrush->Down)
// режим зафарбовуваня заданої області канви { if (Button==mb. Left) Image 3 -> Canvas->Brush->Color = Image 1 -> Canvas-> Brush->Color; else Image 3 -> Canvas->Brush->Color = Image 2 -> Canvas-> Brush->Color; Image 3 -> Canvas->Flood. Fill (X, Y, Image 3 ->Canvas-> Pixels[X][Y], fs. Surface); } else if (SBErase -> Down) { // режим стирання R = Rect (X-6, Y-6, X+6, Y+6); Image 3 -> Canvas -> Draw. Focus. Rect (R); Image 3 -> Canvas -> Brush -> Color = Image 2 -> Canvas -> Brush -> Color; Image 3 -> Canvas -> Fill. Rect (Rect(X-5, Y-5, X+5, Y+5)); }
else if (SBRect -> Down || SBRectang -> Down || SBFill. Rec -> Down) { // режим роботи з рамкою if (REnd) // стираємо поперенюд рамку { Image 3 ->Canvas->Draw. Focus. Rect(R); if ((X < R. Right) && (X > R. Left) && (Y > R. Top) && (Y < R. Bottom)) // режим початку перетягування фрагменту { // установка прапорців RDrag = true; REnd = false;
// запам’ятаємо початкове положення //фрагмента, який ми перетягуємо R 0 = R; // запам’ятаємо зображення Bit. Map->Assign(Image 3 ->Picture); // встановимо колір пензля Image 3 -> Canvas->Brush->Color = Image 2 -> Canvas -> Brush->Color; MCopy->Enabled = false; MCut->Enabled = false; } } else
// режим початкумалювання рамки фрагменту { RBegin = true; REnd = false; R. Top = X; R. Bottom = X; R. Left = Y; R. Right = Y; Image 3 ->Canvas->Draw. Focus. Rect (R); } } }
13. В закладці Event вікна Object Inspector запрограмуємо On. Destroy - обробник події форми: Bit. Map -> Free(); , який звільнить пам’ять після того, як наша програма завершиться. 14. Запрограмуємо обробку меню Відкрити: if (Open. Picture. Dialog 1 ->Execute()) { Image 3 ->Picture->Load. From. File (Open. Picture. Dialog 1 ->File. Name); Bit. Map->Assign(Image 3 ->Picture); } Ці оператори завантажують в компоненту Image 3 файл із малюнком, який користувач обирає у діалоговому режимі. Цей файл зразу ж записується в Bit. Map.
15. Запрограмуємо обробку меню Відміна: Image 3 -> Picture ->Assign(Bit. Map); Оператор відновлює на канві зображення, яке було записане в Bit. Map. 16. В обробник події On. Click для кнопок SBBrush і SBColor запишемо оператор: if (((TSpeed. Button *) Sender)->Down) Bit. Map->Assign(Image 3 ->Picture); Він запам’ятає в Bit. Map поточне зображеня після початку роботи з черговим інструментом.


