Лекция №

Вид материалаЛекция
Подобный материал:
1   2   3   4   5   6   7   8   9   10   11

CPoint(p.X() + 30, p.Y() + 30),

CPoint(p.X() - 30, p.Y() + 30),

CPoint(p.X() - 30, p.Y() - 30)

};

static CPolyline pl(sizeof(coords) / sizeof(coords[0]), coords); // и ломаную


FixedSet = p, c, e, pl; // помещаем в множество фигур FixedSet.


// Статически определяем 4 окружности, и

static CCircle cs[4] = {

CCircle(coords[0], 5),

CCircle(coords[1], 5),

CCircle(coords[2], 5),

CCircle(coords[3], 5)

};


// Добавляем их к множеству FixedSet.

FixedSet += cs[0], cs[1], cs[2], cs[3];

}

//---------------------------------------------------------------------------

// Закрытые функции

//---------------------------------------------------------------------------

void TfrmOOPExample::CreateFigures(CFigureSet &s, TTreeNode *node, bool recursive)

{

// Массив возмножных цветов фигур.

static const TColor Colors[] = {

clRed, clBlue, clGreen, clLime, clAqua, clWhite, clYellow, clOlive

};

// Число возможных цветов (элементов в массиве цветов).

const NColors = sizeof(Colors) / sizeof(Colors[0]);


// Перечисление типов фигур.

enum { Point, Circle, Ellipse, Polyline, Set, NFigures };

// Массив имен фигур, соответсвующий перечислению.

static const char *Names[NFigures] = {

"Точка", "Окружность", "Эллипс", "Ломаная", "Множество фигур"

};


int n, c, x, y, N;

CFigure *f; // адрес генерируемой фигуры

TTreeNode *nn; // ветка дерева, соответсвующая генерируемой фигуре


c = random(11) + 10; // число генерируемых фигур

x = PB->ClientWidth; // ширина и

y = PB->ClientHeight; // высота области, внутри которой генерируются фигуры

N = NFigures - !recursive; // число генерируемых типов фигур

// (если recursive = true, то генерируются все типы фигур,

// иначе - все, кроме Set)

// Генерируем c фигур.

while (c--) {

// Выбираем тип фигуры.

n = random(N);

// Добавляем ветку дерева с заголовком, содеращим имя фигуры.

nn = TV->Items->AddChild(node, Names[n]);

// Генерируем случайным образом фигуру типа n.

switch (n) {

case Point:

f = new CPoint(random(x), random(y));

break;

case Circle:

f = new CCircle(random(x), random(y), random(25));

break;

case Ellipse:

f = new CEllipse(random(x), random(y), random(25), random(25));

break;

case Polyline:

{

// Для ломаной создаем случайным образом массив узлов:

// Число узлов 1..10.

PointArray coords(random(10) + 1);

// Первый узел - случайное положение.

coords[0] = CPoint(random(x), random(y));

// Остальные узлы - случайное положение в пределах +-25 пикселей по

// вертикали и горизонтали от предыдущего узла.

for (unsigned i = 1; i < coords.Count(); i++) {

coords[i].X(coords[i - 1].X() + (random(50) - 25));

coords[i].Y(coords[i - 1].Y() + (random(50) - 25));

}

// И саму ломаную.

f = new CPolyline(coords);

}

break;

case Set:

// Создаем объект класса множество фигур,

f = new CFigureSet();

// и рекурсивно вызываем CreateFigures для заполнения этого множества;

// дальнейшая рекурсия запрещена.

CreateFigures(*(CFigureSet *)f, nn, false);

break;

}

// Случайным образом выбираем цвет для созданной фигуры,

f->Color(Colors[random(NColors)]);

// и добаляем ее в заданное множество.

s.Add(*f);

// В ветку дерева с именем фигуры помещаем адрес самой фигуры.

nn->Data = f;

}

}

//---------------------------------------------------------------------------

void TfrmOOPExample::FreeFigures(CFigureSet &s)

{

CFigureSet::Iterator i;

// Для всех фигур множества s:

for (i = s.First(); i != s.End(); i++) {

// Берем адрес фигуры.

CFigure *f = *i;


// Механизм Runtime Type Identifiaction (RTTI) - определение типа во время выполнения,

// позволяет определить реальный тип объекта, на который указывает некоторый указатель

// на полиморфный класс.

// В данном случае используется операция typeid, которая возвращает константную ссылку на

// объект типа type_info, описывающий тип аргумента. Аргументом может быть либо тип данных,

// либо разыменованный указатель, либо ссылка.

// Для класса type_info определены операции равенства и неравентсва, что позволяет проверить,

// является ли данный объект объектом данного типа, что мы и делаем:


// Если f указывает на множество фигур, то (до удаления самого множества) удаляем фигуры,

// содержащиеся в нем при помощи FreeFigures.

if (typeid(*f) == typeid(CFigureSet))

FreeFigures(*(CFigureSet *)f);


// Удаляем фигуру.

// Операция delete вызывает деструктор. Поскольку деструктор виртуальный, то

// для каждого класса-фигуры будет вызван свой деструктор, несмотря то, что

// f имеет тип CFigure*. В противном случае всегда вызывался бы деструктор класса CFigure.

delete f;

}

}

//---------------------------------------------------------------------------

void TfrmOOPExample::DrawFigure(CFigure &f)

{

TCanvas *c = PB->Canvas;

// Если переключатель Color включен, то

if (Color->Checked) {

// устанавливаем цвет пера на канве PB равным выбранному в ColorBox,

c->Pen->Color = ColorBox->Selected;

// и рисуем фигуру этим цветом.

f.Draw(c);

}

// Иначе

else

// изображаем фигуру ее собственным цветом.

f.ColorDraw(c);

}

//---------------------------------------------------------------------------

// События

//---------------------------------------------------------------------------

void __fastcall TfrmOOPExample::FormCreate(TObject *Sender)

{

// При создании формы создаем фигуры.

Create->Click();

}

//---------------------------------------------------------------------------

void __fastcall TfrmOOPExample::FormDestroy(TObject *Sender)

{

// При уничтожении формы удаляем созданные фигуры.

FreeFigures(RandomSet);

}

//---------------------------------------------------------------------------

void __fastcall TfrmOOPExample::PBPaint(TObject *Sender)

{

// Изображаем случайный и заданный наборы фигур.

DrawFigure(RandomSet);

FixedSet.ColorDraw(PB->Canvas);

}

//---------------------------------------------------------------------------

void __fastcall TfrmOOPExample::CreateClick(TObject *Sender)

{

// Отключаем мигание (см. ниже) выбранной фигуры (если включено).

FlashTimer->Enabled = false;


// Удаляем динамически созданные фигуры, которые помещены в множество RandomSet.

FreeFigures(RandomSet);

// Опустошаем это множество (удалаем указатели на уже несуществующие фигуры).

RandomSet.Clear();


// Очищаем дерево фигур,

TV->Items->Clear();

// добавляем в него корневую ветку,

TTreeNode *root = TV->Items->Add(NULL, "Случайные фигуры");

// соответствующую множеству фигур RandomSet.

root->Data = &RandomSet;


// Создаем фигуры.

CreateFigures(RandomSet, root, true);


// Раскрываем корневую ветку.

root->Expand(false);

// И рисуем созданные фигуры.

PB->Repaint();

}

//---------------------------------------------------------------------------

void __fastcall TfrmOOPExample::ColorClick(TObject *Sender)

{

// При переключении переключателя Color:

// Задаем видимость ColorBox-а и

ColorBox->Visible = Color->Checked;

// перерисовываем фигуры.

PB->Repaint();

}

//---------------------------------------------------------------------------

void __fastcall TfrmOOPExample::ColorBoxClick(TObject *Sender)

{

// При изменении цвета перерисовываем фигуры.

PB->Repaint();

}

//---------------------------------------------------------------------------

void __fastcall TfrmOOPExample::TVClick(TObject *Sender)

{

// При щелчке по дереву:

// Если какая-либо ветка дерева выбрана, то:

if (TV->Selected) {

// Берем адрес фигуры, которой соответствует ветка.

CFigure *f = (CFigure *)TV->Selected->Data;

// Если ветка действительно соответсвует некоторой фигуре, то:

if (f) {

// Если какя-то фигура уже мигает и стерта, то

if (FlashTimer->Enabled && !(Flashs % 2))

// изображаем ее.

DrawFigure(*Flash);

// Устанавливаем число счетчик мигания.

Flashs = 11;

// Устанваливаем фигуру, которая мигает.

Flash = f;

// Включаем таймер мигания.

FlashTimer->Enabled = true;

}

}

}

//---------------------------------------------------------------------------

void __fastcall TfrmOOPExample::FlashTimerTimer(TObject *Sender)

{

// Если уменьшенное значение счетчика мигания делится на 2, то

if (--Flashs % 2) {

// стираем фигуру.

PB->Canvas->Pen->Color = clBlack;

Flash->Draw(PB->Canvas);

}

// Иначе рисуем ее заново.

else

DrawFigure(*Flash);

// Если счетчик обнулился, выключаем мигание.

if (!Flashs)

FlashTimer->Enabled = false;

}

//---------------------------------------------------------------------------