With Image1.Canvas do begin
Pen.Color:=clBlack; // Установка цвета карандаша
Brush.Color:=clGreen; // Уставнока цвета кисти
xmax:=Image1.Width; // Чтение максимальной координаты по x
ymax:=Image1.Height; // Чтение максимальной координаты по y
{Строим оси координат}
yo:=ymax div 2;
MoveTo(0,yo); LineTo(xmax,yo);
MoveTo(0,0); LineTo(0,ymax);
Pen.Color:=clRed; // Установка цвета карандаша
Pen.Width:=2; // Установка толщины карандаша
hx:=(xomax-xomin)/xmax; // Масштабные коэффициенты устанавли-
hy:=(yomax-yomin)/ymax; // вающие шаг (в пикселах) по X и по Y
{Вывод графика}
h:=(xk-xn)/(m-1);
x:=xn;
y:=f(x); // Первая точка
MoveTo(Round(x/hx),Round(yo-y/hy));
for i:=1 to m do begin
x:=x+h;
y:=f(x);
LineTo(Round(x/hx),Round(yo-y/hy));
end;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
Begin
ClipBoard.Assign(Image1.Picture); // Копировать в буфер обмена
end;
procedure TForm1.Button3Click(Sender: TObject);
Begin
xn:=StrToFloat(Edit1.Text);
xk:=StrToFloat(Edit2.Text);
m:=StrToInt(Edit3.Text);
xomin:=StrToFloat(Edit4.Text);
xomax:=StrToFloat(Edit5.Text);
yomin:=StrToFloat(Edit6.Text);
yomax:=StrToFloat(Edit7.Text);
{Установка осей}
With Chart1 do begin
LeftAxis.Automatic:=False;
LeftAxis.Minimum:=yomin;
LeftAxis.Maximum:=yomax;
BottomAxis.Automatic:=False;
BottomAxis.Minimum:=xomin;
BottomAxis.Maximum:=xomax;
SeriesList[0].Clear;
h:=(xk-xn)/(m-1); x:=xn;
for i:=1 to m do begin
y:=f(x);
SeriesList[0].AddXY(x,y);
x:=x+h;
end;
end;
end;
procedure TForm1.Button4Click(Sender: TObject);
Begin
Chart1.CopyToClipboardMetafile(True); // Копировать в буфер обмена
end;
End.
9.4. Выполнение индивидуального задания
Постройте график соответствующей функции от x для вариантов из темы 3. Таблицу данных получить изменяя параметр x с шагом h. Ввод исходных данных организовать через окна TEdit. Самостоятельно выбрать удобные параметры настройки.
По указанию преподавателя выберите вариант задачи. Решите задачу, и используя функции класса TCanvas нарисуйте соответствующие геометрические фигуры. Расположите все рисунки в центре TImage, так чтобы они занимали 2/3 области окна. Все исходные данные имеют действительный тип. Используйте масштабирование.
1. Даны три числа а, b, с. Необходимо определить, существует ли треугольник с такими длинами сторон.
2. Даны четыре числа а, b, с, d. Необходимо определить, существует ли четырехугольник с такими длинами сторон.
3. Отобразить взаимное расположение двух окружностей радиусов R1и R2с центрами в точках (x1 , y1 ), (х2, у2 ) соответственно.
4. Отобразить взаимное расположение окружности радиуса R с центром в точке (x0 , у0 ) и прямой, проходящей через точки с координатами (x1 , y1 ) и (х2 , у2 ) (пересекаются, касаются, не пересекаются).
5. Определить количество точек с целочисленными координатами, лежащих внутри окружности радиуса R с центром в точке (х0 , у0 ).
6. Найти координаты точек пересечения двух окружностей радиуса R1и R2с центрами в точках (х1 , у1 ) и (х2 , у2 ) соответственно.
7. Найти координаты точки, симметричной данной точке М с координатами (х1 , у1) относительно прямой Ах+Ву+С=0.
8. Даны две точки М1(х1 , у1 ), М2(х2, у2 ) и прямая Ах+By+С=0. Необходимо найти на этой прямой такую точку М0(х0 , у0 ), чтобы суммарное расстояние от нее до двух данных точек было минимально.
9. Даны три точки с координатами (х1 , у1 ), (х2 , у2 ), (х3 , у3 ), которые являются вершинами некоторого прямоугольника со сторонами, параллельными осям координат. Найти координаты четвертой точки.
10. Даны координаты четырех точек (х1 , у1 ), (х2 , у2 ), (х3 , у3 ), (х4 , у4 ). Необходимо определить, образуют ли они выпуклый четырехугольник.
11. Даны координаты четырех точек (х1 , у1 ), (х2 , у2 ), (х3 , у3 ), (х4 , у4 ). Необходимо определить, образуют ли они: а) ромб; б) квадрат; в) трапецию.
12. Даны координаты двух вершин (х1 , у1 ) и (х2 , у2 ). некоторого квадрата. Необходимо найти возможные координаты других его вершин.
13. Даны координаты двух вершин (х1 , у1 ) и (х2 , у2 ) некоторого квадрата, которые расположены на диагонали, и точка (х3, у3 ). Необходимо определить, лежит или не лежит точка внутри квадрата.
14. Даны координаты трех вершин (х1 , у1 ), (x2 , y2 ), (х3 , у3 ) треугольника. Необходимо найти координаты точки пересечения его медиан.
15. Даны координаты трех вершин (х1, у1 ), (x2 , y2 ), (х3 , у3 ) треугольника. Необходимо найти длины его высот.
Тема 10. Программирование с Использованием объектов и классов
Цель лабораторной работы: Изучить особенности объектно-ориентированного программирования (ООП). Написать и отладить программу с использованием классов.
10.1. Понятие объекта и класса
Основным понятием ООП является объект, который в Delphi представляет собой переменную структурированного типа, описываемого с помощью ключевого слова Class. Подобно обыкновенной записи типа Record, переменная типа Class под одним именем объединяет как данные различных типов (поля), так и процедуры и функции обработки этих данных (методы). Такое объединение данных и процедур их обработки, называется инкапсуляция.
В Delphi типы объектов называются классами, а сами объекты являются динамическими переменными (символ « ^ » не используется).
10.2. Наследственность и полиморфизм
Свойство наследственности заключается в том, что любой класс может быть порожден от другого класса с наследованием всех свойств. Если класс B порожден от класса A, то класс А называют – «класс-родитель», а B – «класс-потомок». Порожденный класс автоматически наследует поля и методы своего родителя. Прародителем всех классов в Delphi является класс TObject.
Свойство полиморфизма позволяет использовать одинаковое название метода для решения сходных но несколько отличающихся у разных родственных классов задач. В результате в объекте-родителе и объекте-потомке возможно существование двух одноименных методов реализующих различные алгоритмы.
10.3. Создание, уничтожение и операция присваивания объектов
Как всякая динамическая переменная, объект перед началом работы с ним должен быть создан. Нужно выделить под него динамическую область памяти и инициализировать(т.е. подготовить к работе) созданный объект. Для этого в Delphi служит конструктор Create, который является методом класса TObject. Применяется конструктор следующим образом:
<Имя-переменной-типа-класс> := <тип-класса> . Create;
После окончания работы с объектом, выделенную под него память необходимо освободить, для чего служат деструкторыкласса TObject Destroy или Free. Метод Free удобнее использовать, так как он, в отличие от метода Destroy перед освобождением памяти проверяет, не была ли она уже освобождена ранее, т.е. работает более корректно:
<Имя-переменной-типа-класс> . Free;
При необходимости в состав любого пользовательскогокласса могут быть введены свои методыСonstructorиDestructor,которые дополняют Createи Free новыми функциями.
Переменной родительского типа можно присвоить значение переменной типа потомка. Обратное же присваивание запрещено, т.к. при этом некоторые поля или методы могли бы оказаться несуществующими, т.е. у потомка их больше. Однако, если переменная родительского типа указывает на объект, фактически соответствующий переменной типа потомка, то при необходимости ее можно преобразовать к типу потомка с помощью оператора as и присвоить потомку.
10.4. Статический, виртуальный и динамический способы реализации полиморфизма
При объявлении в разделе Var и последующей работе с несколькими объектами каждый объект располагается по некоторому адресу. Причем все обычные поля копируются, а методы хранятся в одном экземпляре. Каждый раз, когда вызывается метод, ему через параметр-указатель с именем Self, передается адрес того экземпляра объекта, который обращается к методу.
Полиморфизм можно организовать по-разному: используя раннее связывание метода с полями объекта, которое происходит на этапе компиляции, и позднее связывание, которое осуществляется непосредственно в нужный момент при выполнении программы.
Статические методы характеризуются тем, что связывание метода с полями осуществляется во время компиляции (раннее связывание).
Виртуальные и динамические методы связываются во время выполнения программы (позднее связывание). Если метод объявлен виртуальным или динамическим, то нельзя менять типы и число параметров.
Для реализации позднего связывания поступают следующим образом. В потомке замещающий метод объявляется директивой override. Замещаемый одноименный метод родителя объявляется как динамический или виртуальный с помощью ключевых слов (dynamic) или (virtual). Вызов перекрытого метода родительского класса в одноименном методе потомка достигается с помощью зарезервированного слова Inherited (унаследованный).
Встретив объявления dynamic или virtual, компилятор создает таблицы соответствия DMT и VMT. В этих таблицах помещаются адреса точек входа методов. Адрес VMT “своего” класса хранится в каждом экземпляре объекта в особом, скрытом от программиста поле. Адрес DMT хранится в VMT. При каждом обращении к методу компилятор вставляет в соответствующую таблицу код, позволяющий извлечь затем из нее адрес точки входа в подпрограмму.
Отличие таблиц DMT и VMT в том, что DMT содержит адреса только тех методов, которые объявлены как dynamic в данном классе, а VMT содержит адреса всех виртуальных методов данного класса: как нововведенных, так и унаследованных от родителей.
При реализации позднего связывания в родительском классе часто используют абстрактные методы (abstract), т.е. такие виртуальные методы, тело которых не прописано. Классы, имеющие хотя бы один абстрактный метод, сами называются абстрактными. Объекты абстрактных методов не создаются.
10.5. Свойства
Правила ООП требуют, чтобы обращение к полям осуществлялось посредством методов, однако это не всегда удобно. Поэтому класс имеет свойства –специальный механизм, регулирующий доступ к полям. Свойства объявляются с помощью специальной конструкции «property… read… write…;».
Обычно свойство связано с некоторым полем и указывает те методы класса, которые должны использоваться при записи в это поле и при чтении из него.
Это делается, например, следующим образом:
Property x:TPole read GetPole write SetPole;
Метод Getpole служит для чтения, а SetPole – для записи. Если необходимо сделать доступ к полю только для чтения, то следует опустить write.
10.6. Пример написания программы
Задание: Составить родительский класс, который позволяет с помощью методов Show и Hide показывать и стирать объекты на экране. Написать классы-потомоки, который рисуют круг, квадрат, комбинацию круга и квадрата (человечек). Предусмотреть возожность перемещения объектов и изменения их размера.
Панель диалога представлена на рис. 10.1.
Рис. 10.1.
Текст модуля приведен на Листинге 10.1, а текст программы на Листинге 10.2.
Листинг 10.1.
Unit Unit2;
Interface
uses Graphics;
var ColrBack:TСolor;
Type
Tviz=class(Tobject) // Абстрактный родительский класс
ColrLine : Tcolor;
Canvas : Tcanvas;
x, y, r : word;
Procedure Ris;virtual;abstract; // Перекрываемый метод для рисования
Procedure Draw(bl:boolean);
procedure Show; // Показать изображение
procedure Hide; // Стереть изображение
procedure MovTo(dx,dy,dr:integer); // Сдвинуть и изменить размер
end;
TKrug=class(Tviz) // Класс рисования круга
x1,y1,x2,y2:word;
Constructor Create(x0,y0,r0:word; colrLine0:Tcolor;canvas0:Tcanvas);
Procedure Ris; override;
end;
TKvad=class(Tkrug) // Класс рисования квадрата
Procedure Ris; override;
end;
TKrPr=class(Tkrug) // Класс рисования круга на квадрате
dy1:word;
Constructor Create(x0,y0,r0,dy0:word; colrLine0:Tcolor;canvas0:Tcanvas);
Procedure Ris; override;
end;
Implementation //Ниже описываются тела всех методов
Procedure Tviz.Draw; // В зависимости от значения булевой
begin // переменной этот метод рисует картинки Ris
with Canvas do begin // либо цветом линии, либо цветом фона.
if bl then begin // В последнем случае происходит стирание
pen.color:=colrLine; brush.color:=colrLine
end
else begin
pen.color:=colrBack; brush.color:=colrBack
end;
Ris; // Процедура ris что-то рисует
end; end;
Procedure Tviz.Show;
begin
Draw(true);
end;
Procedure Tviz.Hide;
begin
Draw(false);
end;
procedure Tviz.MovTo;
begin
Hide;
x:=x+dx; y:=y+dy; r:=r+dr; // Переход к новым координатам
Show;
end;
Constructor TKrug.Create; // Начальные данные для рисования круга
begin // они такие-же как и для рисования квадрата,
colrLine:=colrLine0; // поэтому класс Tkvad наследует его
canvas:=canvas0;
x:=x0; y:=y0; r:=r0;
end;
Procedure Tkrug.Ris; // Рисование круга
Begin
x1:=x-r; x2:=x+r; y1:=y-r; y2:=y+r;
Canvas.Ellipse(x1,y1,x2,y2);
end;
Procedure Tkvad.ris; // Рисование квадрата
Begin
x1:=x-r; x2:=x+r; y1:=y-r; y2:=y+r;
Canvas.Rectangle(x1,y1,x2,y2);
end;
Constructor TKrpr.Create; // Начальные данные для рисования круга
Begin // на квадрате
dy1:=dy0;
Inherited Create(x0,y0,r0,colrLine0,canvas0); // Используется метод TKrug
end;
Procedure TkrPr.Ris; // Рисование квадрата под кругом
begin
Inherited ris // Используется родительский метод рисования круга
Canvas.Rectangle(x1,y2,x2,y2+dy1);
end;
end.
Листинг 10.2.
unit Unit10;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
Button7: TButton;
Button8: TButton;
BitBtn1: TBitBtn;
Image1: TImage;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
procedure Button7Click(Sender: TObject);
procedure Button8Click(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
private { Private declarations }
public { Public declarations }
end;
var Form1: TForm1;
implementation
{$R *.dfm}
uses unit2, Clipbrd;
var krug:Tkrug;
kvad:Tkvad;
krpr:Tkrpr;
okno1:Timage; // Введена переменная для сохранения записи
pxm1,pym1, xo,yo,ro:word;
procedure TForm1.Button1Click(Sender: TObject); // Нарисовать
begin
okno1:=Form1.Image1;
colrBack:=clWhite; // Цвет фона – белый
pxm1:=okno1.ClientWidth; // Считывание размеров окна
pym1:=okno1.ClientHeight;
with okno1.canvas do begin
pen.color:=colrBack;
brush.color:=colrBack;
Rectangle(0,0,Pxm1,Pym1); // Заливка всего окна цветом фона
end;
xo:=pxm1 div 2; yo:=pym1 div 2; // Вычисление координат центра окна
ro:=10; // Начальный размер круга и прямоугольника
Krug:=Tkrug.Create(xo,yo,ro,clBlack,okno1.canvas); // Цвет – черный
Kvad:=Tkvad.Create(xo+80,yo,ro,clBlack,okno1.canvas);
Krpr:=Tkrpr.Create(xo-80,yo,ro,2*ro,clBlack,okno1.canvas);
krug.Show; // Рисование круга
kvad.Show; // Рисование квадрата
Krpr.show; // Рисование комбинации круга и квадрата
end;
procedure TForm1.Button2Click(Sender: TObject);
begin // Увеличить круг
Krug.MovTo(0,0,3);
end;
procedure TForm1.Button3Click(Sender: TObject);
begin // Двигать квадрат вправо-вниз
Kvad.MovTo(3,3,0);
end;
procedure TForm1.Button4Click(Sender: TObject);
begin // Ход конем вправо-вниз
krpr.MovTo(10,0,0);
okno1.Update; // Прорисовка окна
sleep(200); // Задержка
krpr.MovTo(0,5,0);
end;
procedure TForm1.Button5Click(Sender: TObject);
begin // Уменьшить
Krug.MovTo(0,0,-3);
end;
procedure TForm1.Button6Click(Sender: TObject);
begin // Двигать влево-вверх
Kvad.MovTo(-3,-3,0);
end;
procedure TForm1.Button7Click(Sender: TObject);
begin // Ход конем влево-вверх
krpr.MovTo(-10,0,0);
okno1.Update;
sleep(200);
krpr.MovTo(0,-5,0);
end;
procedure TForm1.Button8Click(Sender: TObject);
begin // Только для TImage !!! сохранить картинку
Clipboard.Assign(Image1.Picture);
end;
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
krug.Free; kvad.Free; Krpr.Free;
end;
end.
10.7. Выполнение индивидуального задания
По указанию преподавателя выберите вариант задачи.
Описать класс-родитель и класс-потомок, имеющие методы, указанные в соответствующем варианте задания (потомок наследует или переопределяет методы родителя и приобретает новые). Предусмотреть необходимое количество кнопок для демонстрации каждого из методов объектов.
1. Нарисовать вращающееся колесо. Родительский класс – перемещающийся круг.
2. Нарисовать повозку (прямоугольник на 2 колесах). Родительский класс – перемещающийся прямоугольник.
3. Нарисовать ракету с пламенем из сопла. Родительский класс – перемещающийся отрезок.
4. Нарисовать рожицу двигающую глазами и открывающаю рот. Родительский класс – перемещающийся элипс.
5. Нарисовать солдатика, перемещающегося и отдающего честь. Родительский класс – перемещающийся прямоугольник.
6. Нарисовать кораблик, который может поднимать флаг. Родительский класс – перемещающийся прямоугольник.
7. Нарисовать автомобиль с открывающимися дверями и включающимися фарами. Родительский класс – перемещающийся прямоугольник.
8. Нарисовать сигнальщика, подающего различные сигналы. Родительский класс – перемещающийся прямоугольник.
9. Нарисовать самосвал, который может поднимать кузов. Родительский класс – перемещающийся прямоугольник.
10. Нарисовать самолет, который может при посадке выпускает шасси. Родительский класс – перемещающийся прямоугольник.
11. Нарисовать домик, в котором открываются двери и окна. Родительский класс – перемещающийся прямоугольник.
12. Нарисовать паровоз, который выпускает дым. Родительский класс – перемещающийся прямоугольник.
13. Нарисовать воздушний шарик, который может лопнуть. Родительский класс – перемещающийся эллипс
14. Нарисовать лифт, который доставляет людей на нужный этаж. Родительский класс – перемещающийся прямоугольник.
15. Нарисовать тележку, на которой перевозят различные грузы. Родительский класс – перемещающийся прямоугольник.
ПРИЛОЖЕНИЕ 1. Процедуры и функции для преобразования строкового представления чисел
Для работы со строками применяются следующие процедуры и функции (в квадратных скобках указываются необязательные параметры).
Подпрограммы преобразования строк в другие типы | ||
Function StrToFloat(St: String): Extended; | Преобразует символы строки St в вещественное число. Строка не должна содержать ведущих или ведомых пробелов | |
Function StrToInt(St: String): Integer; | Преобразует символы строки St в целое число. Строка не должна содержать ведущих или ведомых пробелов | |
Procedure Val(St: String; var X; Code: Integer); | Преобразует строку символов St во внутреннее представление целой или вещественной переменной X, которое определяется типом этой переменной. Параметр Code содержит ноль, если преобразование прошло успешно | |
Подпрограммы обратного преобразования | ||
Function FloatToStr( Value: Extended): String; | Преобразует вещественное значение Value в строку символов | |
Function FloatToStrF(Value: Extended; Format: TFloatFor-mat; Precision, Digits: Integer) : String; | Преобразует вещественное значение Value в строку символов с учетом параметров Precision и Digits (см. пояснения ниже) | |
Procedure Str(X [:width [:Decimals]]; var St: String); | Преобразует число Х любого вещественного или целого типа в строку символов St; параметры Width и Decimals, если они присутствуют, задают формат преобразования | |
Правила использования параметров функции FloatToStrF | ||
Значение Format | Описание | |
fFfExponent | Научная форма представления с множителем еХХ. Precision задает общее количество десятичных цифр мантиссы. Digits - количество цифр в десятичном порядке XX. | |
ffFixed | Формат с фиксированным положением разделителя целой и дробной частей. Precision задает общее количество десятичных цифр в представлении числа. Digits - количество цифр в дробной части. Число округляется с учетом первой отбрасываемой цифры: 3,14 | |
ffGeneral | Универсальный формат, использующий наиболее удобную для чтения форму представления вещественного числа. Соответствует формату ffFixed, если количество цифр в целой части меньше или равно Precision, а само число - больше или равно 0,00001, в противном случае соответствует формату ffExponent: 3,1416 | |
ffNumber | Отличается от ffFixed использованием символа - разделителя тысяч при выводе больших чисел (для русифицированной версии Windows таким разделителем является пробел) | |
ffCurrency | Денежный формат. Соответствует ffNumber, но в конце строки ставится символ денежной единицы (для русифицированной версии Windows - символы «р.»). Для Value = p*1000 получим: 3 141,60р | |
ПРИЛОЖЕНИЕ 2. Математические формулы
Язык Object Pascal имеет ограниченное количество встроенных математических функций (|x| ® abs (x), Arctg(x) ® ArcTan(x), ex ® Exp(x), p ® Pi, ® Sqrt(x), x2 ® Sqr(x), Ln(x), Cos(x), Sin (x) и др.). Поэтому при необходимости использовать другие функции следует применять известные соотношения или модуль Math. В таблице приведены выражения наиболее часто встречающихся функций.
Функция | Соотношение | Модуль Math |
LogN(a, x) | ||
Power(x,a) | ||
Tan(x) | ||
CoTan(x) | ||
ArcSin(x) | ||
ArcCos(x) | ||
Sinh(x) | ||
Cosh(x) | ||
1, если x>0; 0, если x=0; -1, если x<0 |
Литература
1. Архангельский А.Я. Программирование в Delphi 7. – М.: ЗАО “Издательство БИНОМ”, 2003.
2. Фаронов В.В. Delphi 6. Учебный курс. ‑М.: Издатель Молгачева С.В., 2001.
3.Дж.Гленн Брукшир. Введение в компьютерные науки. – «Вильямс» М, С-П, Киев. 2001.
4. А.К. синицын, С.В. Колосов, А.А. Навроцкий и др. Программирование алгоритмов в среде Delphi. Лаб. практикум. Ч. 1. – Мн., БГУИР, 2004.
5. Колосов С. В. Программирование в Delphi. Учеб. пособие – Мн., БГУИР, 2005.
Св. план 2005, поз.
Учебное издание
Синицын Анатолий Константинович,
Навроцкий Анатолий Александрович.
ОСНОВЫ АЛГОРИТМИЗАЦИИ
И ПРОГРАММИРОВАНИЯ
В СРЕДЕ DELPHI.
БАЗОВЫЕ ТИПЫ И ПРОСТЕЙШИЕ
АЛГОРИТМЫ
Лабораторный практикум по курсу
«Основы алгоритмизации и программирования»
для студентов 1 – 2-го курсов всех специальностей
Редактор
Корректор
Подписано в печать Формат 68x84 1/16.
Бумага офсетная. Печать ризографическая . Гарнитура “Times”
Усл. печ. л. 5,0. Уч. изд. л. 4,5. Тираж 500 экз. Заказ
Издатель и полиграфическое исполнение:
Учреждение образования
“Белорусский государственный университет информатики и радиоэлектроники”
Лицензия ЛП №156 от 05.02.2001.
Лицензия ЛП №509 от 03.08.2001.
220013, Минск, П. Бровки, 6