МГИЭТ(ТУ)
Кафедра ВТ
факультет МПиТК
Лабораторная работа №3
«Классы и их элементы»
(компилятор «Borland C++ Builder»)
Составил: ст.пр. Тельминов О.А.
10/2001 г.
Цель работы:изучить работу с классами и графикой в средеWindows.
Теоретическая часть: программирование классов
Пример программы: Использованы понятия С++: классы, исключения и компоненты C++Builder:TImage,TTimer, обработчик мыши.
Рис. П1 В процессе работы можно управлять наклоном отрезка (клавиатура или кнопки на форме) и скоростью мяча.
Рис. П2. После падения мяч можно перемещать мышью по горизонтали
Программа состоит из одной формы Form1 (файлыunit1.h–заголовочный,unit1.cpp–реализация функций,unit1.dfm–внешний вид формы) и одного модуля созданного командойFile|New|Unitи переименованного при сохранении вBall(файлыball.hиball.cpp).
Начнем рассмотрение с файла ball.h.
/
защита от
повторного использования
модуля
#define BallH
//-----------------------------------------------------------------#endif
class CBall
{
данные для
частного использования внутри класса:
координаты мяча и указатель на компонент
Image– изображение
int x,y;
TImage* Img;
public:
Прототипы всех
функций класса для манипуляций с мячом.
Функция-конструктор
CBallвызывается автоматически
при создании объекта этого класса. В результате
класс будет иметь указатель на изображения
для вывода на экран.
void MoveToY(int Y);
void MoveToX(int X);
void Hide();
void IncX(int dx){x=x+dx;};
int GetX(){return x;}
int GetY(){return y;}
CBall (TImage* _Img);
};
c
Класс для
управления отрезком.
Задаются
угол наклона, начальные, конечные,
центральная точки, длина и указатель
на изображение для вывода.
{
private:
double angle;
int x1,y1, x2,y2,
xc,yc,len2;
TImage* Img;
double AngleToRad() {return (angle*3.1415) / 180.0;};
Функции,
описанные в разделе public,
доступны внутри и вне класса.
Данные и
функции, описанные в разделе private– только внутри класса.
void Rotate(double dA);
void Hide();
int Naklon(){return 2*(angle>0)-1;}
int ComputeBallY(int x);
CSupport (TImage* _Img);
};
Далее рассмотрим реализацию функций классов CBall, Csupport. (ball.cpp)
//--------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <math.h>
#include "Ball.h"
//--------------------------------------------------
#pragma package(smart_init)
Полученный в конструкторе класса
указатель на изображения используется
для рисования мяча.
Свойство Canvasимеет
вложенные свойства линий обводки (Pen),
заливки (Brush), функции
рисования эллипса (Ellipse)
и др.
Перед именем каждой функции указан
идентификатор класса, к которому она
относится (CBall::)
CBall::CBall(TImage* _Img)
{
x=220;
y=0;
Img=_Img;
}
void CBall::Hide()
{
//стираем старое положение
Img->Canvas->Pen->Color = clWhite;
Img->Canvas->Brush->Color = clWhite;
Img->Canvas->Ellipse(x-10, y-10, x+10, y+10);
}
void CBall::MoveDeltaXY(int dx, int dy)
{
x+=dx;
y+=dy;
//рисуем в новом положении
Img->Canvas->Pen->Color = clBlue;
Img->Canvas->Brush->Color = clBlue;
Img->Canvas->Ellipse(x-10, y-10, x+10, y+10);
Img->Canvas->Pen->Color = clWhite;
Img->Canvas->Brush->Color = clWhite;
Img->Canvas->Ellipse(x-2-3, y-2-3, x+2-3, y+2-3);
}
void CBall::MoveToY(int Y)
{
y=Y;
MoveDeltaXY(0,0);
}
void CBall::MoveToX(int X)
{
x=X;
MoveDeltaXY(0,0);
}
CSupport::CSupport(TImage* _Img)
{
Img=_Img;
xc=(Img->Width) /2;
yc=(Img->Height)/2;
x1=x2=xc;
y1=y2=yc;
len2= 100;
angle=3;
Rotate(0);
}
void CSupport::Hide()
{
Img->Canvas->Pen->Width=3;
Img->Canvas->Pen->Color = clWhite;
Img->Canvas->MoveTo(x1,y1);
Img->Canvas->LineTo(x2,y2);
Img->Canvas->Pen->Width=1;
}
void CSupport::Rotate(double dA)
{
angle=angle+dA;
float alp = AngleToRad();
x1=xc-len2*cos(alp);
Функция
вычисляет такое положение мяча по Y,
чтобы он находился на отрезке. В качестве
входного параметра используется
координатаX.
x2=xc+len2*cos(alp);
y2=yc+len2*sin(alp);
Img->Canvas->Pen->Width=3;
Img->Canvas->Pen->Color = clRed;
Img->Canvas->Brush->Color = clRed;
Важно отметить, что при выходе Xза пределы краев отрезка происходитвыброс исключения(throw)
в виде целого числа.
В дальнейшем оно будет поймано и
обработано. С помощью
механизма исключений происходит
взаимодействие классов.
Img->Canvas->LineTo(x2,y2);
Img->Canvas->Pen->Width=1;
}
int CSupport::ComputeBallY(int x)
{
if ((x<x1) || (x>x2)) throw Naklon();
return yc+(y1-yc)*(xc-x)/(xc-x1);
}
Таким образом, рассмотрено описание и реализация классов для управления мячом и направляющим отрезком на изображении.
Перейдем к форме Form1 и работе с указанными классами. Ниже приведен листингunit1.h.
//------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
//----------------------------------------------------------------
#include "ball.h"
#include <ComCtrls.hpp>
class TForm1 : public TForm
{
__published: // IDE-managed Components
TImage *Image1;
TButton *Button2;
TButton *Button3;
TTimer *Timer1;
TLabel *Label2;
TTrackBar *TrackBar1;
TLabel *Label1;
TLabel *Label3;
void __fastcall FormDestroy(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
void __fastcall FormKeyPress(TObject *Sender, char &Key);
void __fastcall Timer1Timer(TObject *Sender);
void __fastcall Image1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y);
void __fastcall Image1MouseMove(TObject *Sender, TShiftState Shift,
int X, int Y);
void __fastcall Image1MouseUp(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y);
void __fastcall TrackBar1Change(TObject *Sender);
private: // User declarations
CBall* Ball;
CSupport* Doska;
int DirMoving;
bool MouseDn;
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------
#endif
Важно отметить следующие особенности:
работа с изображением (Image1);
анализ нажатых клавиш на клавиатуре (FormKeyPress);
использование компонента (Timer);
работа с мышью (…Mouse…);
применение бегунка (TrackBar1);
указатели на объекты CBall* Ball, CSupport* Doska инициализируются в конструкторе формыTForm1 и уничтожаются при высвобождении ресурсов формыFormDestroy;
Листинг unit1.cpp
//-------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <math.h>
#include "Unit1.h"
//-------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//-------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Form1->KeyPreview = true;
Timer1->Interval=100;
Image1->Canvas->Brush->Color = clWhite;
Image1->Canvas->FillRect(Rect(0, 0, Image1->Width, Image1->Height));
Ball = new CBall(Image1);
Doska = new CSupport(Image1);
DirMoving=true;
try
{
Ball->Hide();
Doska->Hide();
Ball->MoveToY(Doska->ComputeBallY(Ball->GetX()));
Фукнция
ComputeBallYможет выбросить
исключение (см. выше), поэтому она
заключена в блокtry{}.
Операторcatchпредназначен
для обработки исключений (в данном
случаеint). Действительно,
при падении мяча выбрасывается исключение
целого типа и обрабатывается в этомcatch.
}
catch (int d)
{
DirMoving=0;
}
}
//-------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
delete Ball;
delete Doska;
}
//-------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Снова блок try–catchдля обработки
возможного падения мяча. В этой функции
происходит поворот отрезка на угол с
дискретом 5 градусов.
try
{
Ball->Hide();
Doska->Hide();
if (((TButton*) Sender)->Caption=="Left") Doska->Rotate(-5);
else Doska->Rotate(+5);
Ball->MoveToY(Doska->ComputeBallY(Ball->GetX()));
}
catch (int d)
{
Ball->MoveDeltaXY(0,0);
Doska->Rotate(0);
DirMoving=0;
}
}
//-------------------------------------------------------------------
void __fastcall TForm1::FormKeyPress(TObject *Sender, char &Key)
{
if (Key=='a') Button2Click((TObject *)Button2);
if (Key=='s') Button2Click((TObject *)Button3);
}
Обработка
нажатий на клавиатуру. Важно,
чтобы KeyPreview
= true;
//-------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
Эта функция вызывается каждые
Timer1->Intervalмиллисекунд при условии, чтоTimer1->Enabled=true. Здесь
использована для перемещения мяча по
горизонтали.
Timer1->Enabled=DirMoving;
try
{
Ball->Hide();
Doska->Hide();
Doska->Rotate(0);
Ball->IncX((Doska->Naklon())*15*DirMoving);
Ball->MoveToY(Doska->ComputeBallY(Ball->GetX()));
}
catch (int d)
{
Doska->Rotate(0);
Ball->MoveToY(Image1->Height-11);
DirMoving=0;
Label2->Caption="Мяч-мышью по горизонтали";
}
}
//-------------------------------------------------------------
void __fastcall TForm1::Image1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
Обработчик
события опускания вниз кнопки мыши
if (abs(Ball->GetX() - X)<10)
if (!DirMoving)//признак того, что мяч упал
MouseDn=true;
}
//-----------------------------------------------------------------
v
Обработчик события перемещения мыши.
Факт, что кнопка мыши нажата или отпущена
в явном виде отсутствует, поэтому
используем свой флаг MouseDn,
который описан в классеTForm1,
проинициализирован в конструктореForm1 нулевым значением.
В функции Image1MouseDownон устанавливается, вImage1MouseMoveпроверяется, а вImage1MouseUp– сбрасывается.
int X, int Y)
{
if (MouseDn)
{
Ball->Hide();
Ball->MoveToX(X);
}
}
//-------------------------------------------------------------------
void __fastcall TForm1::Image1MouseUp(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
MouseDn=false;
}
//-------------------------------------------------------------------
void __fastcall TForm1::TrackBar1Change(TObject *Sender)
{
Изменяется
интервал срабатывания таймера при
изменении бегунка TrakBar1
(нач. знач.=300)
Timer1->Interval=TrackBar1->Position;
}
//-------------------------------------------------------------------
ВНИМАНИЕ! В компиляторе отключите останов программы при возникновении отключений (Tools|Debuggeroptions|Languageexceptions):