Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Visual1.doc
Скачиваний:
8
Добавлен:
07.03.2016
Размер:
4.35 Mб
Скачать

5.11. Виділення графічних об'єктів у прямокутній області

Приклад знаходиться у папці DISK\GDI\GDI9.

Створимо SDI програму з назвою RK. У файлі з класом виду створимо клас CShape для задання координат та властивостей об'єктів:

class CShape: public CRect

{

public:

CShape(): CRect()

{selected = 0;}

CShape(int L, int T, int R, int B)

:CRect(L, T, R, B)

{selected = 0;}

void Draw(CDC* dc);

BOOL GetSelect() { return selected; }

void SetSelect(BOOL t) { selected = t; }

BOOL selected;

};

Створений клас є похідним від CRect тому всі координати (top, left, right, bottom) беруться з цього класу. Кожен об’єкт може бути вибраним мишею для зберігання його стану введемо змінну selected. Всередині класу звертатися до цієї змінної будемо напряму а для зовнішніх програм, використовуючих цей об'єкт додамо функцію GetSelect. Усі функції окрім Draw невеликі, тому їх можна описати у самому класі. Виведення об'єкта на екран робимо наступним чином:

void CShape::Draw(CDC*dc)

{

CBrush br;

CBrush* br_st;

if(selected) br.CreateHatchBrush(4,RGB(255,0,0));

else br.CreateSolidBrush(RGB(255,255,255));

vr = dc->SelectObject(&br);

dc->Ellipse((CRect*)this);

dc->SelectObject(br_st);

}

Якщо об'єкт виділений то створюємо червоний пензлик з діагональною хрестовою заливкою а інакше створюємо білий. Далі малюємо овальну фігуру функцією Ellipse.

Кількість об'єктів задамо у NUM_SHAPES:

#define NUM_SHAPES 9

У клас виду додамо наступні змінні:

class CRKView : public CView

{

.............................................................

private:

CClientDC* cdc;

CPoint startPt, endPt;

CPen pen;

CShape shapes[NUM_SHAPES]; // Array of shapes

.............................................................

};

Де: cdc – контекст пристрою; startPt, endPt – початкова та кінцева координати виділення прямокутної області; pen – олівець для малювання виділення прямокутної області; shapes – масив об'єктів класу CShape.

У конструкторі класу напишемо наступний код:

CRKView::CRKView()

:pen(PS_DOT,1,RGB(255,0,0))

{

CShape r(10, 10, 60, 60);

CSize s(70, 30);

for (int i = 0; i < NUM_SHAPES; ++i,r+=s)

shapes[i] = r;

cdc = 0;

}

Спочатку заповнюємо змінну pen, потім створюємо тимчасовий об'єкт r. Щоб об'єкти були у різних місцях для задання відстані між об'єктами введемо змінну s. У циклі прирівнюємо кожен об'єкт з масиву shapes до r. Також у циклі робимо зсув об'єкту r на розмір s. Так як вікно ще не створено то і контексту воно не має отже cdc дорівнює 0.

Контекст cdc будемо видаляти у деструкторі класу виду.

CRKView::~CRKView()

{

delete cdc;

}

Додамо функцію на натиснення лівої кнопки миші у вікні виду:

void CRKView::OnLButtonDown(UINT nFlags, CPoint point)

{

SetCapture();

startPt = endPt = point;

}

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

Додамо функцію на переміщення миші, напишемо у ній такий код:

void CRKView::OnMouseMove(UINT nFlags, CPoint point)

{

if (nFlags != MK_LBUTTON) return;

cdc->Rectangle(startPt.x,startPt.y,endPt.x,endPt.y);

endPt = point;

cdc->Rectangle(startPt.x,startPt.y,endPt.x,endPt.y);

CView::OnMouseMove(nFlags, point);

}

У константі MK_LBUTTON міститься код натиснення на ліву кнопку миші. Якщо не натиснута ліва кнопка миші тоді виходимо з функції. На перший погляд не зрозумілим видається те, що виділення прямокутної області малюється 2 рази. Це пояснюється тим що ми бажаємо використати резиновий контур для виділення. У контексті поставимо режим малювання R2_NOTXORPEN (але не в цій функції). Малюємо прямокутник зі старими координатами. Змінюємо кінцеву координату та малюємо прямокутник з новими координатами. Отже 1-ше малювання рамки зі старими координатами стирає з екрану попередню рамку, а 2-ге малювання виводить нову.

Додамо функцію на відпускання лівої кнопки миші, напишемо у ній такий код:

void CRKView::OnLButtonUp(UINT nFlags, CPoint point)

{

if(abs(startPt.x - endPt.x) < 5 ||

abs(startPt.y - endPt.y) < 5)

{

ReleaseCapture();

Invalidate(false);

return;

}

cdc->Rectangle(startPt.x,startPt.y,endPt.x,endPt.y);

CRect outline(startPt, endPt);

outline.NormalizeRect();

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

shapes[i].SetSelect(

outline.PtInRect(shapes[i].CenterPoint()));

ReleaseCapture();

Invalidate(false);

CView::OnLButtonUp(nFlags, point);

}

Спочатку йде перевірка розмірів виділеної області. Якщо розмір виділення менший 5 пікселів по висоті або ширині тоді виводимо відповідне повідомлення користувачу. Далі через виклик функції Rectangle зтираємо рамку. Створюємо тимчасовий прямокутник outline на основі точок виділення. Функція NormalizeRect приводить прямокутник до нормального виду, тобто left стає менше right а top < bottom. Створюємо тимчасову змінну pr, у яку в циклі будемо записувати координати центрів об'єктів. Функція CenterPoint з класу CRect визначає центр прямокутника. Функція PtInRect визначає чи потрапляє вказана точка у прямокутник. Результат цієї перевірки ми вводимо у кожен із об'єктів shapes через функцію SetSelect. Отже всі об'єкти, центри яких потрапляють у виділення будуть відмічені. Для перемалювання вікна визиваємо Invalidate з параметром false, оскільки положення об'єктів у нас не змінюється а заливка в будь якому випадку буде робитись в залежності від нового виділення. Функція ReleaseCapture потрібна при закінченні виділення для того, щоб інші вікна могли отримувати повідомлення від миші. Після виклику SetCapture обов'язково потрібно буде викликати ReleaseCapture, інакше інші вікна не зможуть користуватись мишею.

Малювання об'єктів додамо у функцію OnDraw:

void CRKView::OnDraw(CDC* pDC)

{

CRKDoc* pDoc = GetDocument();

if(!cdc)

{

cdc = new CClientDC(this);

cdc->SetROP2(R2_NOTXORPEN);

cdc->SelectObject(&pen);

}

CPen* pen_st =

pDC->SelectObject(&CPen(1,2,RGB(0,0,0)));

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

shapes[i].Draw(pDC);

pDC->SelectObject(pen_st);

}

Спочатку створюємо контекст cdc, якщо його немає. Він потрібен для малювання рамки з виділенням прямокутної області. Створення контексту відбувається один раз при початковій появі вікна. Малювання об'єктів робимо у циклі через виклик функції Draw з класу CShape.

Результат роботи програми можна бачити на рис. 5.27.

Рис. 5.27. Результат роботи програми з резиновим контуром RK

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