Находение минимального и максимального числа в массиве
Цель работы - создать программу,которая находит минимальное и максимальноечисла в введенном массиве.
Описание плана разработки программы
1. Открыть новый проект.
2. Разместить на форме экземпляры компонентов: Button, Edit, Label.
3. Выполнить следующие действия:
Таблица 23. | ||||
Выделенный объект | Вкладка окна | Имя свойства/ | Действие | |
Object Inspector | имя события | |||
Form1 | Properties | Caption | Установка имени формы «Поиск» | |
Events | OnCreate | Очистить значения свойств Text | ||
текстовых полей | ||||
Button1 | Properties | Caption | Введите название «Очистить» | |
Events | Onclick | Очистить значения свойств Text | ||
текстовых полей | ||||
Button2 | Properties | Caption | Введите название «Закрыть» | |
Events | Onclick | Обработка события закрытия | ||
формы | ||||
Button3 | Properties | Caption | Введите название «Поиск» | |
Events | Onclick | Обработка события нахождения | ||
минимального и максимального | ||||
чисел во введенном массиве | ||||
Edit1 | Properties | Caption | Очистить значение свойства Text | |
Edit2 | Properties | Caption | Очистить значение свойства Text | |
Edit3 | Properties | Caption | Очистить значение свойства Text |
|
|
в Введите переменные
s, ss: string ; a: array [1..15] of integer; I, j, k, max, min, p, code : integer.
в Сохраните проект, запустите и протестируйте его.
Листинг подпрограмм
procedure Tform1.FormCreate(Sender: Tobject);
Begin
Edit1.Text := ‘’;
Edit2.Text := ‘’;
Edit3.Text := ‘’;
end;
procedure Tform1.Button1Click(Sender: Tobject); begin
Edit1.Text := ‘’;
Edit2.Text := ‘’;
Edit3.Text := ‘’;
end;
procedure Tform1.Button2Click(Sender: Tobject); begin
close;
end;
procedure Tform1.Button3Click(Sender: Tobject); begin
s :=Edit1.Text;
s := concat (s, #32);
i := 0;
while Length(s) > 0 do
Begin
i := i+1;
p := pos (#32,s);
В := copy (s,1,p-1); Val (ss,k,code);a[i] := k; delete(s,1,p);
end;
max := a[1];
For j := 1 to i do
if max < a[j] then max := a[j];
min := a[1];
For j := 1 to i do
if min > a[j] then min := a[j];
Edit3.Text := IntToStr (max);
Edit2.Text := IntToStr (min);
end;
Рис. 46.
Практическая работа № 24
«Текущее время и текущая дата»
Цель работы - создать программу,которая выводит текущее время и текущую дату. Описание плана разработки программы
• Открыть новый проект.
• Разместить на форме экземпляры компонентов: Button, Edit, Label.
• Выполнить следующие действия:
Таблица 24. | ||||
Выделенный объект | Вкладка окна | Имя свойства/ | Действие | |
Object Inspector | имя события | |||
Form1 | Properties | Caption | Установка имени формы «Таймер» | |
Button1 | Properties | Caption | Введите название «Текущее время» | |
Events | Onclick | DateTime:=Time; | ||
Edit1.Text:=TimeToStr(DateTime); | ||||
Button2 | Properties | Caption | Введите название «Текущая дата» | |
Events | Onclick | Edit2.Text:=DateToStr(Date); | ||
Edit1 | Properties | Caption | Очистить значение свойства Text | |
Edit2 | Properties | Caption | Очистить значение свойства Text |
|
|
Рис. 47.
Листинг подпрограмм
Var
DateTime : TdateTime;
procedure Tform1.Button1Click(Sender: Tobject); begin
DateTime:=Time;
Edit1.Text:=TimeToStr(DateTime);
end;
procedure Tform1.Button2Click(Sender: Tobject); begin
Edit2.Text:=DateToStr(Date);
end;
end.
68
Практическая работа № 25
«Электронные часы»
Цель работы - написать программу«Электронные часы»,в окне которойотображается текущее время, дата и день недели.
Рис. 48.
Описание плана разработки программы
в Открыть новый проект.
в Разместить на форме экземпляры компонентов: Label, Timer.
в Выполнить следующие действия:
3.1. Ввести константы, отвечающие за названия дней недели и месяцев.
3.2. Объявить процедуру ShowTime вручную для доступа к компонентам формы напрямую.
3.3. Процедура ShowTime отображает текущее время.
|
|
3.4. Процедура FormTime обрабатывает событие Paint.
3.5. Процедура Timer1Timer обрабатывает сигнал таймера.
3.6. Процедура FormCreate обрабатывает событие OnCreate.
Листинг программы:
unit Unit1;
Interface
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
Type
TForm1 = class(TForm)
Timer1: TTimer;
Label1: TLabel; // время
Label2: TLabel; // дата и день недели
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure ShowTime;
private
{ Private declarations } public
{ Public declarations } end;
Var
Form1: TForm1;
Implementation
Const
stDay : array[1..7] of string[11] =
('воскресенье','понедельник','вторник',
'среда','четверг','пятница','суббота');
stMonth : array[1..12] of string[8] =
('января','февраля','марта',
'апреля','мая','июня','июля',
'августа','сентября','октября',
'ноября','декабря');
{$R *.dfm}
procedure TForm1.ShowTime;
var Time : TDateTime; //текущее время
Begin
Time := Now(); // получить системное время Label1.Caption := FormatDateTime('hh:mm:ss',Time); end;
procedure TForm1.Timer1Timer(Sender: TObject); begin
ShowTime; // отобразить время
end;
procedure TForm1.FormCreate(Sender: TObject); var
Present: TDateTime; // текущая дата и время
Year, Month, Day : Word; // год, месяц и число, как
В отдельные числа
Begin
Present:= Now; // получить текущую дату DecodeDate(Present, Year, Month, Day); Label2.Caption := 'Сегодня '+IntToStr(Day)+ ' ' +
|
|
stMonth[Month] + ' '+ IntToStr(Year)+
года, '+ stDay[DayOfWeek(Present)];
В настроить и запустить таймер
Timer1.Interval := 1000; // период сигналов таймера 1 с Timer1.Enabled := True; // пуск таймера
end;
procedure TForm1.FormPaint(Sender: TObject);
Begin
ShowTime; // отобразить часы
end;
end.
Практическая работа № 26
Графика
Для рисования статичных рисунков используется компонент PaintBox (панель System). Этот компонент размещается на форме в виде прозрачного пунктирного квадрата, и его пределах можно рисовать. Рисование выполняется обращением к свойству Canvas (графическая канва) этого компонента: PaintBox1.Canvas. У него в свою очередь есть свойство Pixels (PaintBox1.Canvas.Pixels), которое представляет собой матрицу, двумерный массив заданного размера - поточечный образ канвы, каждый элемент - отдельная точка. В Pixels[] отсчет точек (пикселов экрана) начинается с 0.
Координаты x, y отсчитываются от верхнего левого угла, то есть он считается точкой с координатой (0, 0), увеличение по оси x идет слева направо, а по оси y - сверху вниз. Для конкретной точки указывается цвет. Функция RGB() формирует цвет комбинацией интенсивности красного, зеленого и синего (интенсивность задается числом от 0 до 255).
Например, черный - RGB(0,0,0), красный - rgb(255,0,0), синий - rgb(0,0,255), белый - rgb(255,255,255).
Цель работы - создать программу,выполняющую следующие действия:1. Разместить на форме компонент PaintBox.
2. Заполнить доступную канву 300 красными точками в случайных позициях по нажатиям на некоторую кнопку.
3. Для выхода из программы необходимо щелкнуть мышью на закрывающей кнопке в строке заголовка.
4. Записать код в обработчике нажатия.
Рис. 49.
procedure TForm1.Button1Click(Sender: TObject);
var i,x,y: Integer;
Begin
randomize;
for i := 1 to 300 do
Begin
x := random(100);
y := random(100);
PaintBox1.Canvas.Pixels[x,y] := RGB(255,0,0);
End
end;
5. Изменить RGB(255,0,0) на RGB(random(255),random(255),random(255) )
Рис. 50.
В Заполнить фон черным цветом перед началом выполнения программы с помощью метода канвы FillRect. Метод вызывается с указанием прямоугольной области заливки цветом: FillRect(Rect(0, 0, 100, 100)) // координаты верхнего левого и правого нижнего углов Вложенное слово Rect формирует данное типа "прямоугольник". Перед вызовом FillRect
надо указать цвет заливки: PaintBox1.Canvas.Brush.Color := RGB(0,0,0);
Рис. 51.
procedure TForm1.Button1Click(Sender: TObject);
var i,x,y: Integer;
Begin
PaintBox1.Canvas.Brush.Color := RGB(0,0,0);
PaintBox1.Canvas.FillRect(Rect(0,0,100,100));
for i := 1 to 300 do
Begin
x := random(100);
y := random(100);
PaintBox1.Canvas.Pixels[x,y] := RGB(random(255),random(255),random(255)); end
end;
В Заполнить канву случайными разноцветными линиями разной толщины. Линия рисуется
с помощью методов (сначала задается начальная точка, потом конечная):
PaintBox1.Canvas.MoveTo(10,10);
PaintBox1.Canvas.LineTo(50,50);
Цвет линии и толщина задаются свойством канвы Pen ( карандаш). Pen.Color - цвет карандаша), Pen.Width - толщина линии в пикселах (по умолчанию - 1).
Рис. 52.
for i := 1 to 300 do
Begin
PaintBox1.Canvas.Pen.Color := RGB(random(255),random(255),random(255)); PaintBox1.Canvas.Pen.Width := random(3)+1; x := random(100);
y := random(100);
PaintBox1.Canvas.MoveTo(x,y);
x := random(100);
y := random(100);
PaintBox1.Canvas.LineTo(x,y);
End
3. Заполнить канву эллипсами случайным образом (круги, окружности - частный случай эллипса). Эллипсы рисуются методом Ellipse() с четырьмя параметрами - координатами верхнего левого и правого нижнего углов прямоугольника, в который эллипс вписывается. Кайма эллипса рисуется в соответствии с параметрами свойства Pen канвы, а заливается эллипс внутри цветом кисти Brush канвы.
Рис. 53.
for i := 1 to 300 do
Begin
4.цвет и ширина каймы будущего эллипса
PaintBox1.Canvas.Pen.Color := RGB(random(255),random(255),random(255)) ; PaintBox1.Canvas.Pen.Width := random(3)+1;
цвет заливки внутренности эллипса
PaintBox1.Canvas.Brush.Color := rgb(random(255),random(255),random(255)) ;
координаты углов прямоугольника, в который вписывается эллипс x := random(150);
y := random(150); x2 := random(150); y2 := random(150);
вписываем эллипс
PaintBox1.Canvas.Ellipse(x,y,x2,y2);
end;
Сделать канву на весь экран. Заполнить разноцветными прямоугольниками в случайных позициях и случайных размеров с помощью FillRect().
Создать графический образ так называемого множества Жюлиа.
procedure TForm1.Button1Click(Sender: TObject);
var RE,IM,RE1,IM1: REAL ;
V,X,Y : INTEGER;
В вывод точки заданного цвета procedure PUTPIXEL(x,y,c:Integer); var cc: TColor;
Begin
case c mod 8 of 0:cc:=clBlack; 1:cc:=clRed;
2:cc:=clLime;
3:cc:=clYellow;
4:cc:=clBlue;
5:cc:=clFuchsia;
6:cc:=clAqua;
7:cc:=clWhite; end;
PaintBox1.Canvas.Pixels[x,y] := cc; end;
procedure QWA ; begin
RE1:=RE*RE-IM*IM; IM1:=2*RE*IM; RE:=RE1;
IM:=IM1;
end;
procedure KUB; begin
RE1:=RE*(RE*RE-3*IM*IM); IM1:=IM*(3*RE*RE-IM*IM); RE:=RE1;
IM:=IM1; end ;
Begin
PaintBox1.Canvas.Brush.Color := rgb(0,0,0);
PaintBox1.Canvas.FillRect(Rect(0,0,640,480));
X:=-320 ;
REPEAT Y:=-240 ;
REPEAT V:=0 ; RE:=-1.+0.001*X ; IM:=0+0.001*Y ; REPEAT KUB; RE:=RE+1.00003 ; IM:=IM+1.01828201638 ; if RE*RE > 50 then break;
if IM*IM > 50 then break;
V:=V+1 ;
UNTIL V>40 ;
if ( ABS(RE) > 10 ) or ( ABS(IM) > 1000)
Then
Begin
PUTPIXEL((X+320),(Y+240),TRUNC(V)) ;
End
else PUTPIXEL((X+320),(Y+240),0);
Y:=Y+1 ;
UNTIL Y > 241 ;
X:=X+1 ;
UNTIL X>320 ;
End;
Практическая работа № 27
«Олимпийский флаг»
Цель работы - создать программу,которая на поверхности формы рисуетолимпийский флаг.
Рис. 54.
Листинг программы:
unit Unit1;
Interface
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;
Type
TForm1 = class(TForm)
procedure FormPaint(Sender: TObject);
private
{ Private declarations } public
{ Public declarations } end;
Var
Form1: TForm1;
Implementation
{$R *.dfm}
procedure TForm1.FormPaint(Sender: TObject);
Begin
with Canvas do
Begin
В полотнище
Canvas.Pen.Width := 1; Canvas.Pen.Color := clBlack; Canvas.Brush.Color := clCream; Rectangle(30,30,150,115);
Pen.Width := 2;
Brush.Style := bsClear; // область внутри круга
а не закрашивать
Pen.Color := clBlue; Ellipse(40,40,80,80); Pen.Color := clBlack; Ellipse(70,40,110,80); Pen.Color := clRed; Ellipse(100,40,140,80); Pen.Color := clYellow; Ellipse(55,65,95,105); Pen.Color := clGreen; Ellipse(85,65,125,105);
end;
end;
end.
Практическая работа № 28
«Узоры»
Цель работы - создать программу,выполняющую следующие действия без участияпользователя:
• После запуска программы в окне изображаются рисунки, созданные самой программой по заранее заданным правилам.
• Картинка обновляется «сама собой». Интервал таймера может быть любым. Он зависит от компьютера, на котором работает программа.
• Для выхода из программы необходимо щелкнуть мышью на закрывающей кнопке в строке заголовка.
Рис. 55.
Описание плана разработки программы
• Открыть новый проект.
• Разместить на форме экземпляры компонентов: область рисования PaintBox, таймер Timer.
• Область рисования представить в виде клеток (точек или пикселов). Каждая клетка покрашена в свой цвет. В ходе программы цвета меняются.
• Описать предварительно константы в окне кода пред ключевым словом: Const size = 40;
csize = 12;
Colors: array [1..16] of TColor =
(clRed, clGreen, clYellow, clBlue, clWhite, clGray, clFuchsia, clTeal, clNavy, clMaroon, clLime, clOlive, clPurple, clSilver, clAqua, clBlack);
Константа size задает число клеточек по каждому направлению, константа csize – число используемых цветов. Массив Colors (константа) определяет цвета.
В разделе описаний после ключевого слова var описывается массив клеток
Points: array[1..size, 1..size] of Integer;
• Выполнить следующие действия:
Таблица 25. | ||||
Выделенный объект | Вкладка окна | Имя свойства/ | Действие | |
Object Inspector | имя события | |||
Form1 | Properties | Caption | Установка имени формы «Узор» | |
Events | OnCreate | В процедуре обеспечить неповторимость | ||
случайных чисел с помощью процедуры | ||||
Randomize. Провести инициализацию | ||||
массива пикселов. | ||||
PaintBox1 | Properties | Height | Задать значение 320 | |
(Вкладка System) | Width | Задать значение 320 | ||
Выделенный объект | Вкладка окна | Имя свойства / | Действие | |
Object Inspector | имя события | |||
Canvas | Свойства и методы этого свойства | |||
обеспечивают рисование. | ||||
Метод Rectangle рисует прямоугольник с | ||||
заданными вершинами. Цвет контура | ||||
задается свойством Pen.Color, а цвет | ||||
закраски – свойством Brush.Color. | ||||
Timer1 | Properties | Interval | Задать значение 100 (одна десятая | |
(Вкладка System) | секунды) | |||
Events | OnTimer | В созданной процедуре-заготовке | ||
Timer1Timer описать переменные c (color), | ||||
up (up), d (down), l (left), r (right). Новые | ||||
значения цветов записываются в | ||||
отдельном массиве NewPoints. Написать | ||||
правила, по которым будут меняться цвета. |
7. Сохраните проект, запустите и протестируйте его.
Листинг подпрограммы
procedure TForm1.FormCreate(Sender: TObject);
var i, j : Integer;
Begin
Randomize;
for i := 1 to size do {инициализация массива пикселов} for i := 1 to size do
Points[i, j] := 1 + Random (csize); {Минимально возможное значение элемента массива равно 1}
end;
procedure TForm1.Timer1Timer (Sender: TObject);
var i, j : Integer;
c, l, r, u, d : Integer;
newPoints: array [1..size, 1..size] of Integer;
Begin
{Вычислить, какого цвета будет клетка на следующем шаге} for i := 1 to size do
for j := 1 to size do
Begin
c := Points[i, j] + 1;{Вычисляется «следующий цвет» и запоминается в переменной с} if c > csize then c := 1; {После последнего цвета идет первый}
{Вычисляются индексы для клеток, примыкающих к данной сверху, снизу, слева и справа. Края узора как бы «склеены» друг с другом} u := i – 1;
if u = 0 then u := size;
d := i + 1;
if d > size then d := 1;
l := j – 1;
if l = 0 then l := size;
r := j + 1;
if r > size then r := 1;
newPoints [i, j] := Points [i, j]; {Если среди «соседей» цвет отсутствует, то клетка остается без изменений}
{Если хотя бы один из «соседей» имеет такой цвет, клетка перекрашивается} if (Points [u, j] = c) or (Points [d, j] = c) or (Points [i, l] = c) or (Points [i, r] = c)
then newPoints [i, j] := c;
end;
c := 320 div size; {Выбирается размер клетки так, чтобы узор занимал, по возможности, всю область рисования}
{Обновляется узор на экране}
for i := 1 to size do
for j := 1 to size do
Begin
Points [i, j] := newPoints [i, j];
{Настроить цвет контура прямоугольника и цвет закраски} PaintBox1.Canvas.Pen.Color := Colors[Points[i, j]]; PaintBox1.Canvas.Brush.Color := Colors[Points[i, j]]; {Выполнить рисование}
PaintBox1.Canvas.Rectangle (c*(i - 1), c*(j - 1), c*i – 1, c*j – 1);
{Параметры метода Rectangle подобраны так, чтобы между клетками оставался небольшой зазор. Чтобы клетки располагались вплотную друг к другу, заменить (c*(i - 1), c*(j - 1), c*i – 1, c*j – 1) на (c*(i - 1), c*(j - 1), c*i , c*j }
end;
end;
Практическая работа № 29
Перемещение рисунка
Цель работы - создать программу,в которой на поверхности окна перемещаетсяслучайным образом изображение веселой рожицы. Пользователь должен сделать щелчок кнопкой мыши по изображению. Программа должна завершить работу после того, как пользователь сделает 10 щелчков кнопкой мыши.
Начало игры осуществляется по нажатию на кнопку Ok.
Свойство WordWrap компонента Label – признак того, что слова, которые не помещаются в текущей строке, автоматически переносятся на следующую строку (значение свойства AutoSize должно быть False).
Рис. 56.
Листинг программы:
unit Unit1;
Interface
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
Type
TForm1 = class(TForm)
Timer: TTimer;
Label1: TLabel;
Button1: TButton;
procedure TimerTimer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Button1Click(Sender: TObject);
private
{ Private declarations } public{ Public declarations }
{ объявление процедур помещено сюда, чтобы процедуры имели прямой доступ к форме, на которой они рисуют}
procedure PaintFace (x,y: integer); {рисует рожицу}
procedure EraseFace(x,y: integer); {стирает рожицу}
end;
Var
Form1: TForm1;
fx,fy: integer; { координаты рожицы}
n: integer; { количество щелчков кнопкой мыши}
p: integer; { количество попаданий}
Implementation
{ рисует рожицу}
procedure TForm1.PaintFace(x,y: integer);
Begin
Canvas.Pen.Color := clBlack; { цвет линий}
Canvas.Brush.Color := clRed; { цвет закраски}
{ рисуем рожицу}
Canvas.Ellipse(x,y,x+30,Y+30); { лицо} Canvas.Ellipse(x+9,y+10,x+11,y+13); { левый глаз} Canvas.Ellipse(x+19,y+10,x+21,y+13); { правый глаз} Canvas.Arc(x+4,y+4,x+26,y+26,x,y+20,x+30,y+20); {улыбка}
end;
{ стирает рожицу}
procedure TForm1.EraseFace(x,y: integer);
Begin
{ зададим цвет границы и цвет закраски, совпадающий с цветом формы.} { По умолчанию цвет формы - clBtnFace }
Canvas.Pen.Color := clBtnFace; { цвет окружности}
Canvas.Brush.Color := clBtnFace; { цвет закраски}
Canvas.Ellipse(x,y,x+30,y+30);
end;
{$R *.dfm}
procedure TForm1.TimerTimer(Sender: TObject); begin
EraseFace(fx,fy);
{ новое положение рожицы}
fx:= Random(ClientWidth-30); { 30 - это диаметр рожицы} fy:= Random(ClientHeight-30); PaintFace(fx,fy);
end;
procedure TForm1.FormCreate(Sender: TObject);begin
{ исходное положение рожицы} fx:=100;
fy:=100;
Randomize; { инициализация генератора случайных чисел}
end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
Begin
inc(n); { кол-во щелчков}
if (x > fx) and (x < fx+30) and (y > fy) and (y < fy+30)
Then begin
{ щелчок по рожице} inc(p);
end;
if n = 10 then
Begin
{ игра закончена}
Timer.Enabled := False; { остановить таймер}
ShowMessage('Щелчков: 10. Попаданий: ' + IntToStr(p)+'.');
EraseFace(fx,fy);
Label1.Visible := True;
Button1.Visible := True;
{ теперь кнопка и сообщение снова видны} end;
end;
procedure TForm1.Button1Click(Sender: TObject); begin
Label1.Visible := False; { скрыть сообщение}
Button1.Visible := False; { скрыть кнопку}
Timer.Enabled := True; { пуск таймера}
end;
end.
Практическая работа № 30
Рисунок
Цель работы - создать программу,выводящую на форму приведенный ниже рисунок.По нажатию на клавишу «Лучи» происходит смена направления лучей. Изменить программу так, чтобы лучи изменяли направления без нажатия клавиши.
Рис. 57.
3. Добавьте в форму компоненты Image и Button.
4. Создайте обработчик события нажатия. Важнейшим свойством компонента Image является свойство Canvas:TCanvas (холст). Это свойство само является объектом. У Canvas есть методы и свойства. Это свойства и методы рисования на холсте.
1 Pen: Tpen (перо):рисование линий,границ фигур и т.п.производится пером.
Важнейшие свойства пера – Color: Tcolor (цвет), Width: Integer (ширина), Style: TpenStyle (стиль).
2 Brush:Tbrush (кисть):закраска фигур,заднего фона надписей и т.п.производитсякистью. Важнейшие свойства кисти – Color: Tcolor (цвет), Style: TbrushStyle (стиль).
3 Font: Tfont (шрифт):надписи на холсте выполняются с учетом значений его свойстваFont. При этом задний фон за надписью закрашивается текущим значением кисти. Для того чтобы закраски не было, нужно установить прозрачный стиль кисти: Brush.Style := bsClear, но затем не забудьте сделать кисть непрозрачной: Brush.Style := bsSolid, иначе фигуры, которые вы будете в дальнейшем рисовать, тоже окажутся незакрашенными.
Важнейшие свойства шрифта – Name: string (имя), Size: Integer (размер), Color: Tcolor (цвет). Вы также использовали два метода холста:
4 Rectangle(X1, Y1, X2, Y2: Integer) (прямоугольник):рисует прямоугольник,закрашивая его кистью и обводя пером (в нашем случае, для того чтобы рамки не было видно, мы сделали цвет кисти и пера одинаковым). В качестве параметров задаются координаты верхнего левого X1, Y1 и нижнего правого X2, Y2 углов относительно верхнего левого угла холста.
5 TextOut(X, Y: Integer; const Text: string) (вывести текст):рисует текст согласнозаданному шрифту и закрашивая задний фон согласно заданной кисти (в нашем случае эта закраска незаметна, поскольку текст рисуется на том же фоне, что и текущее значение кисти). В качестве параметров задаются координаты верхнего левого угла текста X, Y относительно верхнего левого угла холста и текст надписи Text.
4. Нарисуйте градиентно закрашенное синее небо отдельными линиями, каждую следующую линию рисуя более светлой. Таким образом, рисование выполняется в цикле. Необходимо определить локальную переменную. В цикле меняются значения цветов, устанавливается перо в точку и чертится линия из этой точки в другую.
MoveTo(X, Y: Integer) (передвинуть перо):передвигает позицию пера в точку холста вкоординаты X, Y. При этом на холсте ничего не рисуется;
LineTo(X, Y: Integer) (чертить линию):чертит линию из точки,в которой находилосьперо, в точку X, Y, используя текущее перо. При этом перо тоже перемещается в эту точку.
Местоположение пера хранится в свойстве холста PenPos: Tpoint. Запись в эту переменную полностью эквивалентна вызову метода MoveTo. Цвет можно задавать, используя константы цвета clBlack, clNavy, clGreen и т.д. – полный список констант находится в выпадающем списке свойства Color в Инспекторе Объектов. Цвет также можно задать, используя функцию RGB (Red, Green, Blue: byte), в параметрах Red, Green и Blue указываются значения интенсивности красной, зеленой и синей компоненты цвета (от 0 до 255 каждая).
5. Добавить на небо солнце. Нарисовать эллипс с линиями-лучами. Лучи нарисовать случайным образом, для этого необходимо использовать генератор случайных чисел.
Круги и эллипсы рисуются с помощью метода холста Ellipse(X1, Y1, X2, Y2: Integer). Как и прямоугольник, эллипс закрашивается текущей кистью и обводится текущим пером. В качестве параметров X1, Y1, X2, Y2 необходимо указать левый верхний и нижний правый углы прямоугольника, в который «вписан» эллипс. Если Y2 – Y1 = X2 – X1 (то есть прямоугольник является квадратом), эллипс рисуется как круг.
Датчик случайных чисел – функция random выдает число типа double в диапазоне от 0 до 1.
6. Нарисовать облака. Можно воспользоваться картинкой из файла. Нарисовать в стандартном редакторе Paint облако: а) установить атрибуты картинки – ширина 100, высота 50; б) закрасить картинку черным цветом – этот цвет в программе будет прозрачным; в) нарисовать облако, используя инструмент Распылитель и различные оттенки серого; г) проследите, чтобы левая нижняя точка картинки осталась черной (именно по этой точке автоматически определяется прозрачный цвет).
7. Сохранить картинку в файл.
8. Добавить в форму еще один Image, щелкнуть по нему мышкой и загрузить в него картинку. Сделать его прозрачным можно, установив свойство Transparent. Поскольку он вспомогательный, лучше, чтобы он не был виден во время работы программы, поэтому отключите ему свойство Visible.
9. Добавить компонент Timer. Установите его интервал 100.
10. На вкладке событий Инспектора Объектов напротив события OnTimer в выпадающем списке выберите имя обработчика события Button1Click. Таким образом устанавливается уже существующий обработчик для еще одного события.
11. В программе каждые сто миллисекунд будет вызываться событие и происходить перерисовка картинки, как если бы мы нажимали каждый раз кнопку. Замедлить интервал между перерисовкой картинки можно, увеличив интервал таймера.
12. При рисовании часто требуется использовать более сложные объекты, чем просто комбинации линий прямоугольников и эллипсов. Может возникнуть необходимость использования готового растрового изображения. Кроме того, может понадобиться копирование изображения из одного Image на другой. Для этого используется метод холста Draw(X, Y: Integer; Graphic: Tgraphic). Этот метод практически копирует графический объект на холст в область с координатами верхнего левого угла X,Y. Графическим объектом Graphic могут быть битовые картинки, иконки и метафайлы. Для нас важным является его применение к копированию картинок из одного Image в другой. Это делается следующим образом:
ImageA.Canvas.Draw(X, Y, ImageB.Picture.Bitmap)
При этом все, что нарисовано на ImageB, будет скопировано на ImageA. Если ImageB.Transparent = true, то картинка копируется с прозрачным фоном.
Вместо ImageA и ImageB соответственно подставьте нужные вам имена компонентов, фигурирующие в вашей программе:
Image1.Canvas.Draw(130 + random(2), 20 + random(2), Image2.Picture.Bitmap); Image1.Canvas.Draw(100 + random(2), 50 + random(2), Image2.Picture.Bitmap); Image1.Canvas.Draw(170 + random(2), 80 + random(2), Image2.Picture.Bitmap);
Таким образом, для рисования можно использовать любые картинки из файла – облака, домики, персонажей, логотипы и т.п.
Листинг программы
procedure Tform1.Button1Click(Sender: Tobject); var i:integer;
Begin
Image1.Canvas.Pen.Color := clGreen;
Image1.Canvas.Brush.Color := clGreen;
Image1.Canvas.Rectangle(0, 200, 300, 300);
Image1.Canvas.Font.Color := clWhite;
Image1.Canvas.Font.Size := 30;
Image1.Canvas.Font.Name := ‘Arial’;
Image1.Canvas.TextOut(10, 250, ‘Delphi’);
for i := 0 to 200 do
Begin
Image1.Canvas.Pen.Color := RGB(I, I, 255);
Image1.Canvas.MoveTo(0, i);
Image1.Canvas.LineTo(300, i);
end;
Image1.Canvas.Pen.Color := clRed;
Image1.Canvas.Brush.Color := clYellow;
Image1.Canvas.Ellipse(20, 20, 60, 60);
Image1.Canvas.Pen.Color := clYellow;
for i := 1 to 20 do
Begin
Image1.Canvas.MoveTo(40, 40);
Image1.Canvas.LineTo(5 + random(70), 5 + random(70));
end;
end;
end.
Практическая работа № 31
Построение графика
Цель работы - cоздать программу построения графика,в которой устанавливаетсямасштаб, в цикле осуществляется построение графика функции, рисуются оси координат и печатаются на них числовые шкалы.
Рис. 58.
Описание плана разработки программы
2. Открыть новый проект.
3. Разместить на форме экземпляры компонентов: кнопка Button, область рисования
PaintBox.
4. Выполнить следующие действия:
Таблица 26. | ||||
Выделенный объект | Вкладка окна | Имя свойства/ | Действие | |
Object Inspector | имя события | |||
Form1 | Properties | Caption | Установка имени формы «График | |
функции» | ||||
Button1 | Properties | Caption | Введите название «График» | |
Events | Onclick | Написать процедуру, рисующую | ||
график по точкам | ||||
PaintBox1 | Properties | Canvas | Соединение линиями получаемых | |
точек | ||||
Button2 | Properties | Caption | Введите название «Выход» | |
Events | Onclick | Close; | ||
3. Сохраните проект, запустите и протестируйте его.
Листинг программы
procedure TForm1.Button1Click(Sender: Tobject);
function f(x:integer):integer;
var c:integer;
Begin
c:=round(10*sin(0.1*x));
f:=c;
end;
var x:integer;
Begin
PaintBox1.Canvas.LineTo(0,150);7
PaintBox1.Canvas.LineTo(410,150);
x:=0;
for x:=0 to 350 do
Begin
PaintBox1.Canvas.LineTo(x, f(x)+150);
end;
end;
procedure Tform1.Button2Click(Sender: Tobject); begin
Close;
end;
end.
Практическая работа № 32
«Градусник»
Цель работы - создать программу,которая переводит значение температуры поЦельсию в значения температуры по Фаренгейту. Введите графический объект изображения значения температуры.
4. Поместите на форму два поля ввода Edit и четыре кнопки.
Рис. 59.
5. Ввести число в левое поле. По нажатию на кнопку «по Фаренгейту» в правом поле выводится преобразованное число. По нажатию кнопки «Очистить» очищаются поля ввода.
6. Ограничьте вводимые температуры диапазоном от 0°C до 100°C (если введено значение, превышающее 100°C или 212°F, то при нажатии кнопки в полях ввода должно отобразиться 100 и 212 соответственно).
7. Отобразить столбик термометра графически. Добавьте компоненты Image.
8. Сделать видимой только ту кнопку, которая необходима для преобразования.
Рис. 60.
Листинг программы
unit Unit1;
Interface
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ExtCtrls;
Type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Image1: TImage;
Image2: TImage;
Label1: TLabel;
Label2: TLabel;
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
Private
{ Private declarations } public
{ Public declarations } end;
Var
Form1: TForm1;
Implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject); begin
Edit1.Text := '';
Edit2.Text := '';
Image1.Canvas.Pen.Color := clRed;
Image1.Canvas.Brush.Color := clWhite;
Image1.Canvas.Rectangle(10,1,23,360);
Image2.Canvas.Pen.Color := clBlue;
Image2.Canvas.Brush.Color := clWhite;
Image2.Canvas.Rectangle(10,1,23,360);
end;
procedure TForm1.Button2Click(Sender: TObject);
var a, b, c : real;
Begin
a := StrToFloat(Edit1.Text);
if (a > 0) or (a < 100) then b := 1.8 * a + 32;
if a > 100 then b := 212;
if a < 0 then b := 32;
Edit2.Text := FloatToStr(b);Image1.Canvas.Pen.Color := clRed; Image1.Canvas.Brush.Color := clWhite; Image1.Canvas.Rectangle(10,1,23,360); Image1.Canvas.Pen.Color := clRed; Image1.Canvas.Brush.Color := clRed; Image1.Canvas.Rectangle(10,round(360-a),23,360); Image2.Canvas.Pen.Color := clBlue; Image2.Canvas.Brush.Color := clWhite; Image2.Canvas.Rectangle(10,1,23,360); Image2.Canvas.Pen.Color := clBlue; Image2.Canvas.Brush.Color := clBlue; Image2.Canvas.Rectangle(10,round(360-b),23,360);
end;
procedure TForm1.Button1Click(Sender: TObject);
var a, c, d : real;
Begin
c := StrToFloat(Edit2.Text);
if (c > 32) or (c < 212) then d := ( c - 32)/1.8;
if c < 32 then d := 0;
if c > 212 then d := 100;
Edit1.Text := FloatToStr(d);
Image2.Canvas.Pen.Color := clBlue;
Image2.Canvas.Brush.Color := clWhite;
Image2.Canvas.Rectangle(10,1,23,360);
Image2.Canvas.Pen.Color := clBlue;
Image2.Canvas.Brush.Color := clBlue;
Image2.Canvas.Rectangle(10,round(360-c),23,360);
Image1.Canvas.Pen.Color := clRed;
Image1.Canvas.Brush.Color := clWhite;
Image1.Canvas.Rectangle(10,1,23,360);
Image1.Canvas.Pen.Color := clRed;
Image1.Canvas.Brush.Color := clRed;
Image1.Canvas.Rectangle(10,round(360-d),23,360);
end;
procedure TForm1.Button3Click(Sender: TObject); begin
Edit1.Text := '';
Edit2.Text := '';
Image1.Canvas.Pen.Color := clRed;
Image1.Canvas.Brush.Color := clWhite;
Image1.Canvas.Rectangle(10,1,23,360);
Image2.Canvas.Pen.Color := clBlue;
Image2.Canvas.Brush.Color := clWhite;
Image2.Canvas.Rectangle(10,1,23,360);
end;
procedure TForm1.Button4Click(Sender: TObject); begin
Close;
end;
procedure TForm1.Edit1Enter(Sender: TObject);
Begin
Button2.Visible := true;
Button1.Visible := False;
end;
procedure TForm1.Edit2Enter(Sender: TObject);
Begin
Button1.Visible := True;
Button2.Visible := False;
end;
end.
Практическая работа № 33
Вывод табличных данных
На одной из знаменитых гравюр Альбрехта Дюрера изображен магический квадрат. Одним из его свойств является то, что суммы по всем столбцам, строкам и диагоналям равны.
Цель работы - создать программу,рассчитывающую суммы по столбцам и строкамвводимых чисел.
Рис. 61.
2. Добавить на форму сетку – компонент StringGrid. Этот компонент служит для ввода и вывода табличных данных.
3. Необходимо ввести данные и описать событие реагирования на их ввод. В свойстве Options установите пункт Editing, иначе сетка будет доступной только для чтения. Теперь при запуске программы можно вводить текст.
4. Щелкнув мышкой в Инспекторе Объектов, описать обработчик события OnSelectCell, которое возникает, когда пользователь выбирает какую-либо ячейку для редактирования.
5. Теперь при запуске программы и выборе ячейки в заголовке формы отображается информация о столбце и строке ввода.
6. Таким образом, в разделе uses возникла ссылка на модуль Grids, в котором описаны компоненты сеток. В описании класса формы добавилась переменная – ссылка на компонент сетки, а также описание метода – обработчика события. Сам обработчик описан уже в разделе implementation.
7. Обработать событие, возникающее, когда пользователь пытается выделить какую-нибудь ячейку.
procedure Tform1.StringGrid1SelectCell(Sender: Tobject; Acol, Arow: Integer;
var CanSelect: Boolean);
Begin
Caption := ‘Выделена клетка (‘ + IntToStr(Acol) + ‘:’ + IntToStr(Arow) + ‘) ‘;
end;
3. качестве параметров обработчик получает (кроме Sender) номер столбца, номер строки и переменную CanSelect, которую можно изменить внутри обработчика, так как она передается как var.
Рис. 62.
Можно, например, запретить выделение ячеек третьего столбца. Для этого вставьте в этот обработчик еще строчку: CanSelect := (Acol <> 3); В этом случае CanSelect будет равен false, если Acol = 3.
6. Настроить сетку в зависимости от значения констант, которые надо объявить в interface. Теперь при запуске программы сетка имеет размер, заданный в константе, и выглядит значительно аккуратнее. Если изменить значение константы, то при запуске и размер сетки будет соответствующим.
7. Установить размер сетки согласно значению констант Num и сSize, объявленных в interface:
const Num = 4;
cSize = 30;
……
procedure Tform1.FormCreate(Sender: Tobject);
Begin
MyGrid.DefaultColWidth := cSize;
MyGrid.DefaultRowHeight := cSize;
MyGrid.ColCount := Num;
MyGrid.RowCount := Num;
MyGrid.Width := Num * (cSize + 1) + 3;
MyGrid.Height := Num * (cSize + 1) + 3;
MyGrid.Font.Size := cSize div 2;
end;
Рис. 63.
5. приведенном участке кода изменяются ширина и высота сетки, установленные по умолчанию, а также количество строк и столбцов сетки. Добавление единицы к ширине каждой ячейки связано с наличием линий между ячейками, а добавление тройки ко всей сумме – наличием бордюра вокруг сетки. В последней строчке устанавливается соответствующий величине клетки размер шрифта.
2. Для расчета суммы по столбцам и строкам вводимых чисел написать собственную процедуру и две функции.
Функции будут рассчитывать сумму в строке и столбце , получая их номер в качестве параметра . Процедура будет в цикле вызывать эти функции и соответствующим образом заполнять клетки.
Теперь надо создать обработчик для нажатия на саму форму и описать в нем вызов расчета. Собственная процедура стоит в коде раньше, чем обработчик, из которого она вызывается. Когда описывается собственная процедура, нужно обращаться к компонентам через форму.
При запуске программы требуется ввести числа в сетку и кликнуть на саму форму. Function ColSum(n: integer): integer;
Var
9. integer; begin Result := 0;
for I := 1 to Num – 1 do Result := Result + StrToInt (Form1.MyGrid.Cells[n, i]); end;
function RowSum(n: integer): integer;
Var
2. integer; begin Result := 0;
for I := 1 to Num – 1 do Result := Result + StrToInt(Form1.MyGrid.Cells[I, n]); end;
procedure Calculate;
var i: integer;
Begin
for I := 1 to Num – 1 do
Begin
Form1.MyGrid.Cells[I, 0] := IntToStr(ColSum(i)); Form1.MyGrid.Cells[0, i] := IntToStr(RowSum(i)); end;
end;
3. данной программе используется свойство Cells, компонента сетки. Это свойство имеет тип двумерного массива строк. Счет в этом массиве начинается с нуля. Фиксированные (серые) клетки, с точки зрения индексирования массива, ничем не отличаются от прочих. В нашем случае фиксированы первая строка и первый столбец (в массиве они имеют соответствующие нулевые координаты). Поэтому при расчете суммы проходят от 1 (а не от 0) до Num – 1 (при индексировании с нуля последний столбец/строка имеют, понятно, номер Num – 1).
Однако, если произойдет ввод какой-нибудь буквы, сразу возникнет исключительная ситуация. Она, очевидно, возникает из-за невозможности перевода буквы в число в функции StrToInt. Если нежелательно, чтобы при возникновении исключительной ситуации программа в Delphi переходила в режим отладки, можно отключить флажок Menu => Tools => Debugger Options => Language Exceptions => Stop on Delphi Exceptions. Теперь программа будет выполняться так, как если бы она выполнялась из-под Windows. Теперь каждый раз, когда вводится нечисловой символ, программа не останавливается, а только появляется стандартное окно Windows с сообщением об ошибке.помощью обработки исключений можно избежать появления этого окна. Для этого надо добавить в функцию конструкцию try..except. Таким образом «опасная» команда (или целый блок) помещается внутрь конструкции try..except..end или try..finally..end:
function StrToVal(s: string): integer; begin
if S = ‘’ then Result := 0 else try
Result := StrToInt(s); except
Result := 0;
Form1.Caption := ‘Вводить надо числа!’; end;
end;
Если возникает исключительная ситуация, т.е. введено нечисловое значение, считается, что введен ноль, а также выводится сообщение об этом пользователю. Еще нужно добавить вывод информации, что все в порядке. А также удалить код внутри обработчика Click формы. В результате, если введено неправильное значение, то окно ошибки не появляется, а в Caption формы выводится напоминание.
Практическая работа № 34
«Игра»
Цель работы - создать программу–игру.Игрок управляет пушкой зенитки,егобоевое задание – справиться с нашествием воздушных шаров. Воздушные шары несут бомбы, которые они сбросят, как только окажутся над пушкой. Необходимо не допустить этого и уничтожить их все на подлете. Снаряды не ограничены, но следующий выстрел можно делать только после того, как выпущенный снаряд поразит цель, упадет на землю или уйдет из зоны видимости.
В игре участвуют:
5. воздушные шары,
6. знитная пушка,
7. пушечный снаряд,
8. бомба,
9. внешняя среда.
Для шаров введен специальный тип TBalloon., в котором содержатся данные о координатах шара, его скорости, состоянии и цвете. Массив переменных Balloons типа TBalloon будет содержать полную информацию обо всех шарах. Индексирование идет, начиная с нуля. Общее число шаров в массиве задается соответствующей константой.
Кроме того, к шарам относятся константы, определяющие:
2. количество шаров,
3. их возможные цвета,
4. возможную высоту над землей (всего предполагается четыре уровня),
5. интервал между шарами и их радиус.
Type
TBalloon = record
x, y, v, Explosion: integer;
Color: TColor;
end;
Const
BallCount = 10;
BallColors: array [0 .. 9] of TColor = (clRed, clGreen, clNavy, clMaroon, clPurple, clOlive, clLime, clYellow, clFuchsia, clSilver);
BallAltitude: array [0 .. 3] of integer = (240, 160, 200, 120);
BallInterval = 40;
BallRadius = 15;
V = 150;
g = -9.8 * 3;
dt = 0.1;
Var
Form1: TForm1;
x, y, Vx, Vy, BombY, BombV: double;
Angle, GunPosition, GunExplosion: integer;
Balloons: array [0 .. BallCount - 1] of TBalloon;
Зенитная пушка описывается переменными:
4. угол наклона пушки,
5. ее положение
6. ее состояние.
Пушечный снаряд описывается переменными:
5. координатами,
5. текущей скоростью,начальной скоростью при выстреле.
Бомба, сбрасываемая с воздушного шара, имеет:
6. координату,
7. скорость.
Для расчета положений объектов нужно знать ускорение падения и шаг по времени . В качестве состояния шара и пушки мы используем переменные TBalloon. В
определенный момент времени каждый элемент должен находиться в каком- то состоянии, определяющем то, как элемент выглядит на экране. Шары и пушка могут быть боеспособными, взрывающимися и уничтоженными.
Если Explosion = 0 - шар боеспособен , если Explosion = 10, то он уничтожен, а значения от 1 до 9 обозначают фазы взрыва. Чтобы инициировать взрыв боеспособного шара, нужно присвоить Explosion := 1. То же самое касается и пушки.
Состояние, в котором скорость снаряда равна нулю: Vx = 0 и Vy = 0. В этом случае считают, что можно сделать новый выстрел. Пока же снаряд летит (то есть скорость его не нулевая), новый выстрел сделать нельзя.
Бомба будет сбрасываться шаром, когда он поравняется с пушкой. Таким образом, X - координата бомбы всегда равна X - координате пушки. Следовательно, необходимо хранить только Y-координату бомбы. Бомба не сброшена, если BombY = 1000. Если BombY < 1000, то она считается сброшенной и начинает падать.
Поместите на форму TrackBar, Button, Image и Timer и настройте их параметры. Timer: Interval = 100; Image: Width = 440, Heigth = 260; Button: Caption = ‘Новая игра’;
TrackBar: Min = -90, Max = 90, Frequency = 10.
Image - сражение в реальном времени. Timer - реальное время. Button - запуск новой игры. TrackBar - управление зенитной пушкой.
4. обработчике нажатия на кнопку "Новая игра" необходимо обнулить параметры, расставить пушку и шары. Для каждого шара устанавливается случайное направление движения: v = 1 или –1. В зависимости от направления, определяется высота, на которой находится шар (на одном и том же уровне шары летят в одну сторону). По x-координате шары расставляются так, чтобы они шли с примерно равным интервалом в направлении пушки из-за границ экрана.
Каждый шар Balloons[i], элемент массива Balloons, имеет тип записи TBalloon, и для того, чтобы получить доступ к его элементам, нужно писать: Balloons[i].Explosion := 0, Color := BallColors[random(10)] и т.д. Конструкция with Balloons[i] do begin .. end позволяет избежать повторения.
procedure TForm1.Button1Click(Sender: TObject); var
6. integer; begin
Caption := 'Нашествие'; TrackBar1.Position := 0; GunPosition := 170 + random(100); Vx := 0;
Vy := 0; GunExplosion := 0;
for i := 0 to BallCount – 1 do with Balloons[i] do
Begin
if random < 0.5 then v := –1 else v := 1;
y := BallAltitude[1 + v + random(2)] + random(10); x := 220 - v * (220 + i * BallInterval + random(20)); Explosion := 0;Color := BallColors[random(10)];
end;
BombY := 1000;
end;
8. обработчик события формы OnCreate вводится датчик случайных чисел, устанавливается клиентский размер формы (ClientWidth := 455; ClientHeight := 315;). Размер клиентской области формы в приложениях определяется автоматически как Width и Height формы минус ширина заголовка и бордюров.
procedure TForm1.FormCreate(Sender: TObject); begin
Randomize;
ClientWidth := 455;
ClientHeight := 315;
Button1.Click;
end;
Пушка танка будет управляться с помощью компонента TrackBar. Выстрел производится нажатием пробела на клавиатуре. При этом фокус ввода должен быть у TrackBar. В обработчике OnKeyPress реализуется выстрел, задавая начальную скорость и положение снаряду, а также издавая звук выстрела.
Процедура, проигрывающая этот звук из wav-файла , описана в модуле, который необходимо подключить в разделе uses. В модуле MMSystem имеется функция PlaySound, с помощью которой можно проигрывать файлы wav. Для асинхронного воспроизведения (приложение не приостанавливает работу на время воспроизведения, а проигрывает его в фоновом режиме) вызов выглядит так:
PlaySound(PChar('имяфайла.wav'), 0, SND_ASYNC).
стандартных звуках Microsoft Office можно подобрать звуки для выстрела и взрыва.
4. зависимости от версии программы, эти файлы хранятся в C:\Windows\Media\ Microsoft Office 2000, C:\Program Files\Microsoft Office\Office\Media или в какой-то подобной папке.
Найдите звуки для выстрела (условно назовем GunShot.wav) и взрыва (условно назовем Explode.wav) и скопируйте их в папку, в которой сохранен проект.
procedure TForm1.TrackBar1KeyPress(Sender: TObject; var Key: Char); var
5. integer; begin
if (Key = ' ') and (Vx = 0) and (Vy = 0) and (GunExplosion = 0) then begin
Try
PlaySound(PChar('GunShot.wav'), 0, SND_ASYNC); except
end;
Vx := V * Sin(Angle * pi / 180); Vy := V * Cos(Angle * pi / 180);
x := GunPosition + 15 * Sin(Angle * pi / 180); y := 20 + 15 * Cos(Angle * pi / 180);
end;
if (Key = 'Q') then
Begintry
PlaySound(PChar('Explode.wav'), 0, SND_ASYNC); except
end;
for i := 0 to BallCount - 1 do
if Balloons[i].Explosion = 0 then
Balloons[i].Explosion := 1;
Caption := 'Уничтожен';
end;
end;
В обработчике изменения положения бегунка TrackBar меняем наклон пушки.
procedure TForm1.TrackBar1Change(Sender: TObject); begin
Angle := TrackBar1.Position;
end;
Выстрел происходит, если:
2. нажат пробел;
3. снаряд готов (Vx = 0) и (Vy = 0);
4. пушка боеспособна (GunExploion = 0).
Процедура MoveAll, вызываемая каждый такт таймера, отвечает за то, чтобы все процессы шли своим чередом. Вставьте ее сразу после implementation.
procedure MoveAll;
var i: integer;
Begin
for i := 0 to BallCount - 1 do
with Balloons[i] do
if Explosion = 0 then
x := x + v
Else begin
if Explosion < 10 then
inc(Explosion);
end;
if (Vx <> 0) or (Vy <> 0) then
Begin
x := x + Vx * dt;
y := y + Vy * dt;
Vy := Vy + g * dt;
end;
if BombY < 1000 then
Begin
BombY := BombY + BombV * dt;
BombV := BombV + g * dt
end;
if (GunExplosion > 0) and (GunExplosion < 10) then inc(GunExplosion);
end;
Процедура пододвигает все шары, которые живы (у них Explosion = 0), в направлении вектора их скорости. Остальные шары, если они находятся в фазе взрыва (0 < Explosion < 10), переходят в следующую фазу.
Если снаряд выпущен (Vx <> 0) или (Vy <> 0), то его координата и скорость изменяются согласно законам природы.
Если бомба сброшена (BombY < 1000), то она также подчиняется закону всемирного тяготения.
Если танк находится в фазе взрыва (0 < GunExplosion < 10), он переходит в следующую фазу.
Ошибки, возникающие в обработчике таймера или процедурах, которые вызываются из обработчика, не останавливают таймер и, значит, через секунду возникают опять. Чтобы их остановить, приходится использовать Ctrl-Alt-Del…
В этой процедуре мы работаем с массивом. Одной из самых частых ошибок, которые не так-то просто найти, является выход за границы массива. Для предотвращения подобных ситуаций включите проверку на выход из диапазона допустимых значений (Project => Options => Compiler => Runtime errors => Range checking), которая по умолчанию отключена.
Перемещения сами по себе могли бы продолжаться бесконечно. Необходимо проконтролировать:
не попал ли снаряд в шар, следовательно, взорвать его;
не уничтожены ли все шары, следовательно, выдать надпись о победе;
не поравнялся ли шар с пушкой, следовательно, сбросить бомбу;
не упал ли снаряд и не вышел ли он из зоны контроля, следовательно, перезарядить пушку;
не упала ли бомба на пушку, следовательно, закончить игру. Для контроля за передвижениями предусмотрена процедура:
procedure CheckCollisions;
Var
i, j: integer;
HappyEnd: boolean;
Begin
for i := 0 to BallCount - 1 do
with Balloons[i] do
Begin
if (Explosion = 0) then
Begin
if (sqr(x - Unit1.x) + sqr(y - Unit1.y) < sqr(BallRadius)) then begin
Try
PlaySound(PChar('Explode.wav'), 0, SND_ASYNC); except end;
Explosion := 1;
Unit1.x := 0;
Unit1.y := 0;
Unit1.Vx := 0;
Unit1.Vy := 0;
HappyEnd := (GunExplosion = 0);
for j := 0 to BallCount - 1 do
HappyEnd := HappyEnd and (Balloons[j].Explosion > 0); if HappyEnd then
Form1.Caption := 'Победа!';
end;
if (x = GunPosition) and (BombY = 1000) and (GunExplosion = 0) then begin
BombY := y - BallRadius - 5;
BombV := 0;
end;
end;
end;
if (y < 0) or (x < 0) or (x > 440) then
Begin
x := 0;
y := 0;
Vx := 0;
Vy := 0;
end;
if BombY < 10 then
Begin
BombY := 1000;
GunExplosion := 1;
Try
PlaySound(PChar('Explode.wav'), 0, SND_ASYNC); except end;
Form1.Caption := 'Увы...';
end;
end;
В этом блоке возможная ошибка связана с использованием with … do begin … end. X-координата снаряда хранится в глобальной переменной x, X-координата
воздушного шара – в переменной Balloons[i].x. Однако когда пишут код внутри with Balloons[i] do begin … end,то именно к координате шара обращаются просто как кx.Еслинужно добраться до глобальной переменной, то теперь уже перед ней нужно ставить уточнение: Unit1.x, где Unit1 – имя модуля.
Рисование отдельных элементов баталии также разумно поместить в специализированные для этого процедуры.
Художественные образы шаров, пушки и взрыва передаются с помощью процедур:
procedure DrawBalloon(x, y: integer; Color: TColor); begin
with Form1.Image1.Canvas do
Begin
Pen.Color := clBlack;
Brush.Color := Color;
Ellipse(x - BallRadius, y - BallRadius, x + BallRadius, y + BallRadius);
Pen.Color := clWhite;
Brush.Color := clWhite;
Ellipse(x - BallRadius div 2 - 3, y - BallRadius div 2 - 3, x - BallRadius div 2 + 3, y - BallRadius div 2 + 3);
Pen.Color := clBlack;
Brush.Color := clOlive;
Rectangle(x - 5, y + BallRadius + 5, x + 5, y + BallRadius + 10); MoveTo(x - 5, y + BallRadius + 5); LineTo(x - BallRadius, y);
MoveTo(x, y + BallRadius + 5);
LineTo(x, y);
MoveTo(x + 5, y + BallRadius + 5);
LineTo(x + BallRadius, y);
end;
end;
procedure DrawGun;
Begin
with Form1.Image1.Canvas do
Begin
if (Vx = 0) and (Vy = 0) then
Pen.Color := RGB(0, 70, 0) else Pen.Color := clBlack;
Brush.Color := Pen.Color;
Pen.Width := 5;
MoveTo(GunPosition, 240);
LineTo(GunPosition + round(15 * sin(Angle * pi / 180)), 240 - round(15 * cos(Angle * pi / 180)));
Pen.Width := 1;
Ellipse(GunPosition - 8, 232, GunPosition + 8, 248); Rectangle(GunPosition - 10, 240, GunPosition + 10, 260);
end;
end;
Процедура DrawExplosion обеспечивает доступ к координатам снаряда.
procedure DrawExplosion(x, y, Phase: integer);
Var
i, xx, yy, Size: integer;
a, b: double;
Begin
with Form1.Image1.Canvas do
for i := 0 to Phase * 10 do
Begin
a := random * 2 * pi;
b := random * sqr(Phase) / 3 + 5;
xx := x + round(l * sin(a));
yy := y + round(l * cos(a));
Size := round(sqr(10 - Phase) / 8 + 2);
Pen.Color := RGB(random(100), 0, 0);
Brush.Color := Pen.Color;
Ellipse(xx - random(Size) - 1, yy - random(Size) - 1, xx + random(Size), yy + random(Size));
end;
end;
Кроме того, пушка меняет цвет, когда готов очередной снаряд. В довершение, нужно соединить все написанное воедино.
Процедуры рисования объединяются в процедуре, рисующей все поле боя:
• небо,
• шары,
• пушка,
• ядро,
• бомба.
Объединять все вместе обработчик таймера.procedure DrawBattleField;
Var
i: integer; begin
with Form1.Image1.Canvas do for i := 0 to 259 do
Begin
Pen.Color := RGB(i div 2, i div 2, 255); MoveTo(0, i);
LineTo(440, i); end;
for i := 0 to BallCount - 1 do with Balloons[i] do
if Explosion = 0 then DrawBalloon(x, 260 - y, Color) else if Explosion < 10 then DrawExplosion(x, 260 - y, Explosion);
if GunExplosion = 0 then DrawGun else if GunExplosion < 10 then DrawExplosion(GunPosition,240, GunExplosion);
with Form1.Image1.Canvas do begin
Pen.Color := clMaroon; Brush.Color := clRed;
if (Vx <> 0) or (Vy <> 0) then Ellipse(round(x) - 2, 260 - round(y) - 2, round(x) + 3, 260 -round(y) + 3);
if (BombY <> 1000) then Ellipse(GunPosition - 2, 260 - round(BombY) - 2, GunPosition + 3,260 - round(BombY) + 3);
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject); begin
MoveAll;
CheckCollisions;
DrawBattleField;
end;
Рис. 64.
Практическая работа № 35
«Тест»
Цель работы - создать программу,которая тестирует учащегося по информатике иматематике.
Проект должен содержать последовательность форм, реализующих диалог с тестируемым учащимся.
На первой форме происходит регистрация учащегося.
Рис. 65.
Фрагмент программы (unit1):
uses Unit2;
{$R *.dfm}
procedure TForm1.Button2Click(Sender: TObject); begin
Close;
end;
procedure TForm1.Button1Click(Sender: TObject);
Begin
Form2.Label3.Caption:=Form1.Edit1.Text;
Form2.ShowModal;
end;
На второй форме предлагается выбрать один из тестов.
Рис. 66.
Фрагмент программы (unit2):
uses Unit3, Unit6;
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject); begin
Form3.ShowModal;
end;procedure TForm2.Button2Click(Sender: TObject); begin
Form2.Close;
end;
procedure TForm2.Button3Click(Sender: TObject); begin
Form6.Edit2.Text:='';
Form6.ShowModal;
end;
На третьей форме предлагается проути тест по информатике.
Рис. 67.
Фрагмент программы (unit3):
uses Unit4, Unit2;
{$R *.dfm}
procedure TForm3.Button1Click(Sender: TObject); begin
k:=0;
if (Form3.Edit1.Text='монитор') or (Form3.Edit1.Text='Монитор') or (Form3.Edit1.Text='МОНИТОР') then k:=k+1;
if (Form3.Edit2.Text='Клавиатура') or (Form3.Edit2.Text='клавиатура')
or (Form3.Edit2.Text='КЛАВИАТУРА') then k:=k+1;
if Form3.Edit3.Text='8' then k:=k+1;
Form4.Label2.Caption:=IntToStr(k);
if k=0 then Form4.Label1.Caption:='Очень плохо' else
if k=1 then Form4.Label1.Caption:='Плохо' else
if k=2 then Form4.Label1.Caption:='Хорошо' else
if k=3 then Form4.Label1.Caption:='Очень хорошо';
Form3.Edit1.Text:='';
Form3.Edit2.Text:='';
Form3.Edit3.Text:='';
Form4.ShowModal;
end;
procedure TForm3.Button2Click(Sender: TObject); begin
Form3.Close;
end;
На следующей форме отображается результат тестирования и предложение о промотре ответа.
Рис. 68.
Фрагмент программы (unit4):
uses Unit1, Unit5, Unit3, Unit2;
{$R *.dfm}
procedure TForm4.Button2Click(Sender: TObject); begin
Form4.Close;
end;
procedure TForm4.Button1Click(Sender: TObject); begin
Form4.Close;
Form3.Close;
end;
procedure TForm4.Button3Click(Sender: TObject); begin
Form5.ShowModal;
end;
На следующей форме отображаются правильные ответы.
Рис. 69.
Фрагмент программы (unit5):
uses Unit4, Unit3, Unit2, Unit1;
{$R *.dfm}
procedure TForm5.Button1Click(Sender: TObject); begin
Form4.Close;
Form3.Close;
Form2.Close;
Form1.Close;
Form5.Close;
end;
Если учащийся выбрал тест по математике, то ему предлагается проверить свои знания таблицы умножения. На следующей форме случайным образом выбираются числа. Учащийся должен ввести значение произведения в текстовое поле. С помощью кнопки «проверка» выясняется правильность введенного ответа . Если ответ правильный, то можно сгенерировать следующий пример. После нескольких примеров можно проверить свой рейтинг.
Рис. 70.
Фрагмент программы (unit6):
uses Unit7, Unit1;
{$R *.dfm}
procedure TForm6.Button1Click(Sender: TObject); var n,i:integer;
Begin
randomize;
a:=random(10)-0;
b:=random(10)-0;
Form6.Label1.Caption:=IntToStr(a);
Form6.Label2.Caption:=IntToStr(b);
Form6.Edit2.Text:='';
Form6.Label6.Caption:='';
end;
procedure TForm6.Button2Click(Sender: TObject); begin
if (a*b=StrToInt(Form6.Edit2.Text)) then
Begin
Form6.Label6.Caption:='Правильно';
m:=m+1;
r:=r+1;
q:=q+1;
End
Else
Begin
Form6.Label6.Caption:='Не правильно';
r:=r-1;
q:=q+1;
end;
Form6.Label1.Caption:='';
Form6.Label2.Caption:='';end;
procedure TForm6.Button3Click(Sender: TObject); var
c:real;
Begin
Form7.Label2.Caption:=Form1.Edit1.Text;
Form7.Label1.Caption:='Вы ответили на '+IntToStr(q)+' вопросов, из них правильно '+IntToStr(m);
Form7.Label4.Caption:='Ваш рейтинг = '+IntToStr(r); c:=m/q;
if c=0 then Form7.Label3.Caption:='Очень плохо' else
if (c>0)and(c<0.5) then Form7.Label3.Caption:='Плохо' else if c=0.5 then Form7.Label3.Caption:='Надо доучить' else
if (c>0.5) and (c<1) then Form7.Label3.Caption:='Хорошо' else if c=1 then Form7.Label3.Caption:='Молодец!';Form7.ShowModal;
end;
При нажатии на кнопке «Ваш рейтинг» на следующей форме появляется результаты рейтенга. Тестирование можно завершить.
Рис. 71.
Фрагмент программы (unit7):
uses Unit6;
{$R *.dfm}
procedure TForm7.Button1Click(Sender: TObject); begin
Form7.Close;
Form6.Close;
end;
Обратите внимание на подключение модулей в строке Uses. Таким образом, происходит обращение к соответствующей форме. Для отображения формы используется функция
function ShowModal: Integer;
Данная функция позволяет показывать форму в работе режима диалога.
Практическая работа № 36
«Проигрыватель»
Цель работы - создать программу-проигрыватель файлов мультимедиа,снабженныйсистемой визуализации. Для начала многооконность будет реализована посредством стандартных диалогов. Проигрыватель файлов мультимедиа, проигрывающий различные форматы, а также сопровождающий музыкальные файлы визуализацией.
1. Создать на диске папку (например C:\MyDelphi\MyMPlayer), в которой будет создан проект, скопировать в эту папку несколько музыкальных файлов и клипов. Для демонстрации полноценной работы проигрывателя понадобятся мультимедийные файлы wav, mid, wma, mp3, avi, которые можно найти в соответствующих папках.
Видеофайлы:
C:\Program Files\Borland\Delphi5\Demos\Coolstuf\
Аудиофайлы: C:\Windows\Media\
C:\Program Files\Microsoft Office\Office10\Media\ C:\Мои документы\Мои музыкальные записи\
2. Создать простейшую программу проигрывания аудиофайлов (см. практическая работа № 10). Для этого поместить на форму кнопку, медиапроигрыватель, диалог загрузки.
Рис. 72.
3. Настроить фильтр диалога на файлы мультимедиа, соответственно заполнив таблицу. Убрать ненужные нам кнопки проигрывателя, отключив их в Инспекторе Объектов (VisibleButtons). В обработчике нажатия на кнопку описать загрузку файла.
Рис. 73.
OpenDialog – диалог загрузки
Основное свойство – FileName: string, основной метод – Execute. При вызове из программы метода Execute происходит вывод на экран диалога. Параметры вывода определяются свойствами компонента: Title, Options, Filter и др. Если пользователь выберет файл для открытия и нажмет "Открыть", то в свойство FileName компонента будет записано имя этого файла в формате string, а результатом метода Execute будет значение true. Иначе, если пользователь нажмет в диалоге кнопку "Отмена", результат Execute будет false, т.е. Execute является булевой функцией.
MediaPlayer –медиапроигрыватель.
Основное свойство – FileName: string, основные методы – Play, Pause, Stop. После того как в свойство FileName помещено имя файла мультимедиа, этот файл нужно открыть с помощью метода Open ( если установлено свойство AutoOpen, то открытие происходит автоматически, но это не всегда хорошо, поскольку, если FileName не задано или задано неверно, то при автооткрытии произойдет ошибка).
Когда файл открыт, он может быть воспроизведен. Это можно сделать с помощью кнопок самого компонента , либо вызвав метод Play. То же касается остановки и паузы – методов Stop и Pause. Для настройки внешнего вида компонента используется множество свойств, к примеру, можно скрыть часть кнопок, настраивая свойство VisibleButtons.
4. В обработчике нажатия на Button1 вызывается метод диалога Execute, и если он выдает результат true (пользователь выбрал файл и нажал "Открыть"), то медиапроигрывателю передается имя этого файла и файл открывается. Теперь пользователь может воспроизвести его, нажав кнопки проигрывателя.
procedure TForm1.Button1Click(Sender: TObject); begin
if OpenDialog1.Execute then
Begin
MediaPlayer1.FileName := OpenDialog1.FileName; MediaPlayer1.Open;
end;
end;
5. При запуске программы пользователь видит кнопку и проигрыватель. Проигрыватель не является активным, поскольку файл, который он должен воспроизводить, не открыт.
Рис. 74.
При нажатии на кнопку активизируется диалог. Параметры диалога соответствуют значениям свойств, заданных предварительно в Инспекторе Объектов. К примеру, выбранный фильтр звуковых файлов скрывает все файлы с отличающимся расширением.
После выбора в музыкальной папке файла при нажатии кнопки "Открыть" проигрыватель стал доступным. Файл открыт, и можно воспроизвести его.
Если необходимо воспроизвести видеофайл, то при запуске автоматически будет создано отдельное окно, в котором отобразится изображение.
6. Проигрыватель готов. Необходимо оформить пользовательский интерфейс. Поместите на форму панель, а на ней расположите компонент Image, растянутый на всю панель. Добавьте таймер. Сохраните модуль как MainUnit и проект как MyMPlayer в приготовленную папку.
Рис. 75.
Дайте каждому компоненту подходящее название. Обработчик кнопки поменяйте согласно последним изменениям и добавьте растяжение видеоэкрана. Для того чтобы видеофайлы воспроизводились не в отдельном окне, а в заданном месте, например, на Panel1, необходимо соответствующим образом установить свойство медиапроигрывателя Display. Для того чтобы установить и растянуть нужным образом изображение, нужно установить свойство DisplayRect:
MPlayer.DisplayRect := Rect(0, 0, ScreenPanel.Width, ScreenPanel.Height);
где Rect(x1, y1, x2, y2: integer):TRect – функция, преобразующая четыре числа к формату TRect – прямоугольник, а свойство DisplayRect имеет именно этот формат.
Для того чтобы переименовать компоненты измените свойство Name. Настройте параметры компонентов:
1) MainForm: TmainForm
Caption = ‘Мультимедиа-проигрыватель’
ClientWidth = 402
ClientHeigth = 290
2) LifeTimer: Ttimer Enabled = false Interval = 100
3) MediaOpenDlg: TOpenDialog
Options: ofFileExist = true
Title = ‘Загрузить файл мультимедиа’
4) LifeImage: TImage
Align = alClient
5) ScreenPanel: TPanel Align = alTop Caption = ‘’ Width = 402 Heigth = 252
6) MediaOpenBtn: TButton Captoin = ‘Открыть’
7) MPlayer: TMediePlayer Display = ScreenPanel VisibleButtons = [btPlay, btPause, btStop]
7. Необходимо создать единую форму для воспроизведения звуковых и видеофайлов. Причем воспроизведение звуковых файлов тоже будет сопровождаться анимацией. В качестве этого сопровождения используется игра "Жизнь".
Для этого добавим соответствующий "рассчитывающий" и "рисующий" код.
Опишем константы, определяющие размер поля, введем новый тип – массив клеток и объявим глобальную переменную этого типа.
Const
XSize = 40; YSize = 25; type
TLifeCells = array [0 .. XSize - 1, 0 .. YSize - 1] of boolean; var
MainForm: TMainForm;
A: TLifeCells;
Создадим процедуру, случайным образом заполняющую массив.
procedure RandomCells;
Var
i, j: integer;
Begin
for i := 0 to XSize - 1 do
for j := 0 to YSize - 1 do
A[i, j] := random < 0.5;
end;
Это процедура случайного заполнения поля. Булева переменная присваивается логически, а не с помощью условного оператора if random < 0.5 then A[I,j] := true else A[i.j] := false.
Создадим функцию, определяющую число живых клеток-соседей у данной клетки. function NumOfCells(x, y: integer): integer;
Var
i, j, xx, yy: integer;
Begin
Result := 0;
for i := -1 to 1 do
for j := -1 to 1 do
Begin
xx := x + i; yy := y + j;
if xx = -1 then xx := XSize - 1;
if yy = -1 then yy := YSize - 1;
if xx = XSize then xx := 0;
if yy = YSize then yy := 0;
if A[xx, yy] then inc(Result);
end;
if A[x, y] then dec(Result);
end;
Это функция подсчета живых соседей. Обратите внимание на переменные xx и yy. Подобным образом реализуется "сшивка" верхнего и нижнего, левого и правого краев. В конце исключается сама клетка из числа соседей: if A[x, y] then dec(Result);
Создадим процедуру, рисующую поле клеток.
procedure DrawCells;
Var
i, j: integer;begin
with MainForm.LifeImage.Canvas do
Begin
Brush.Color := сlBlue;
Pen.Color := Brush.Color;
Rectangle(0, 0, XSize * 10, YSize * 10);
Brush.Color := clRed;
for i := 0 to XSize - 1 do
for j := 0 to YSize - 1 do
if A[i, j] then Rectangle(i * 10, j * 10, i * 10 + 10, j * 10 + 10); end;
end;
Опишем обработчик таймера; каждый такт у нас будет происходить перерасчет живых клеток по правилам игры.
procedure TMainForm.LifeTimerTimer(Sender: TObject); var
i, j: integer;
B: TLifeCells; begin
for i := 0 to XSize - 1 do for j := 0 to YSIze - 1 do case NumOfCells(i, j) of
2: B[i, j] := A[i, j];
3: B[i, j] := true;
else B[i, j] := false;
end;
A := B;
DrawCells;
end;
Каждый такт таймера пересчитываются живые клетки. Алгоритм игры, как известно, состоит в следующем. Если у живой клетки два или три соседа, то она остается живой, если меньше двух , – погибает от одиночества, если больше трех, – гибнет от тесноты. Рождается клетка, если у нее ровно три соседа . С помощью оператора case реализуются правила. Использование локального массива B необходимо. Если записывать сразу в A, то клетки нового поколения будут также считаться при учете соседей, что недопустимо : каждому – свое. В конце, однако, нужно скопировать новое поколение, содержащееся в B, в массив A. Простые массивы можно копировать присвоением: A := B.
Модифицируется обработчик нажатия кнопки под новые задачи. Проанализируйте расширение загружаемого файла, и, если загружен видеофайл, Image становится невидимым, освобождая экран для ролика , в противном случае, наоборот, выводится картинку, на которой идет игра, заполняется поле клеток и запускается таймер.
procedure TMainForm.MediaOpenBtnClick(Sender: TObject); begin
if MediaOpenDlg.Execute then
Begin
MPlayer.FileName := MediaOpenDlg.FileName;
MPlayer.Open;
MPlayer.DisplayRect := Rect(0, 0, ScreenPanel.Width, ScreenPanel.Height); MPlayer.Play;
if ExtractFileExt(MPlayer.FileName) = '.avi' then LifeImage.Visible := false else begin
LifeImage.Visible := true;RandomCells;
LifeTimer.Enabled := true;
end;
end;
end;
Экран вывода "растягивается " на всю панель. Добавлен автоматический запуск воспроизведения. В зависимости от расширения воспроизводимого файла, LifeImage, на котором происходит "Жизнь", либо прячется (в случае '.avi'), либо выводится (в других случаях).
Рис. 76.
8. Необходимо предоставить пользователю возможность настройки цветов. На форму добавляем три компонента – два диалога выбора цвета FieldColorDlg: TColorDialog (Color = clNavy), CellColorDlg: TColorDialog (Color = clYellow) и одну кнопку SetColorBtn: TButton (Caption = ‘Цвета’).
В обработчике нажатия на эту кнопку нужно описать вызов диалогов.
Рис. 77.
ColorDialog (основное свойство Color: TColor,основной метод– Execute) -диалогвыбора цвета. Если пользователь выбрал цвет и нажал "ОК", результат этого метода – true, если пользователь нажал "Отмена", то результат false.
procedure TMainForm.SetColorBtnClick(Sender: TObject); begin
if MessageDlg('Изменить цвета?', mtConfirmation, [mbYes, mbNo], 0) = mrNo then exit;
if MainForm.FieldColorDlg.Execute then ScreenPanel.Color := MainForm.FieldColorDlg.Color;MessageDlg('Теперь измените цвет клеток', mtInformation, [mbOk], 0); CellColorDlg.Execute;DrawCells;
end;
MessageDlg(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons;
HelpCtx: Longint): Word; - вызов окна сообщения. Это служебное окно.
Msg – текст сообщения.
DlgType – тип диалога. Возможные значения: mtWarning, mtError, mtInformation, mtConfirmation, mtCustom.
Buttons – используемые кнопки. Переменная типа "множество", возможные элементы: mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore, mbAll, mnNoToAll, mbYesToAll, mbHelp.
HelpCtx – индекс контекстной справки . В данном примере индекс равен нулю. При написании проектов с развернутой справочной системой указывается реальный индекс.
MessageDlg возвращает число, равное одной из следующих констант: mrNone, mrAbort, mrYes, mrOk, mrRetry, mrNo, mrCancel, mrIgnore, mrAll. Эти константы – так называемый модальный результат (modal result) нажатия на соответствующую кнопку диалога.
В данной программе проверяется, равен ли модальный результат mrNo, т.е. нажата ли кнопка "Нет"; если нажата, то вызывается exit, и программа немедленно выходит из текущей процедуры-обработчика.
Функции MessageDlg и Execute Delphi позволяет вызывать как процедуры: MediaOpenDlg.Execute вместо if MediaOpenDlg.Execute then …
При этом невозможно проконтролировать, какие кнопки были нажаты: "OK" или "Отмена".
Далее необходимо откорректировать процедуру рисования, затем запустить программу, загрузить музыкальный файл и настройте цвета. Наконец, необходимо использовать цвета диалогов при рисовании.
Внесите изменения в DrawCells:
…
with MainForm.LifeImage.Canvas do
Begin
Brush.Color := MainForm.FieldColorDlg.Color; Pen.Color := Brush.Color;
Rectangle(0, 0, XSize * 10, YSize * 10); Brush.Color := CellColorDlg.Color; Brush.Color := MainForm.CellColorDlg.Color;
……….
Рис. 78.
Рис. 79.
9. На данный момент форма может быть масштабирована во время работы приложения. Для того чтобы зафиксировать размер формы, необходимо установить соответствующее свойство BorderStyle. Кроме того, нужно запретить разворачивание формы на весь экран (это также нежелательно).
Перечислим основные свойства и события формы.
Свойства
BorderIcons: TBorderIcons –иконки заглавной панели формы,тип свойства–множество, возможные элементы: biSystemMenu, biMinimize, biMaximize, biHelp (в данном случае нужно отключить biMaximize, чтобы форму нельзя было развернуть).
BorderStyle:ТBorderStyle –стиль бордюраbsDialog, bsSingle, bsNone, bsSizeable,bsToolWindow, bsSizeToolWin. Если установить bsNone, то форма будет без заглавной панели, а значит и без кнопки закрытия программы. Следовательнр, выходить из программы возможно либо с помощью Alt-F4, либо предусмотреть дополнительную кнопку с методом
Close.
ClientWidth, ClientHeigth: integer –ширина и высота клиентской области формы.
FormStyle: TFormStyle –стиль формы.Наиболее важным значением являетсяfsStayOnTop. Если установлено это значение, то форма будет находиться над остальными формами, даже если она не активна, и пересекается с активной на данный момент формой.
Position: TPosition –расположение формы.Здесь задаются различные начальныеположения формы, например, задать положение по центру экрана (poScreenCenter). При запуске программы она окажется в центре.
WindowState: TWindowState –состояние окна.Возможные значения: wsNormal,wsMinimized, wsMaximized. С помощью этого свойства можно разворачивать и сворачивать форму.
События
OnActivate, OnDesactivate(Sender: TObject) –события,возникающие,когда формаактивируется и дезактивируется (при этом в форму переходит или ее покидает фокус ввода).
OnCloseQuery(Sender: TObject; var CanClose: Boolean) –событие,возникающее припопытке закрыть форму. Например, некоторая программа спрашивает: "Вы хотите завершить программу?". Это – результат действия подобного события. Делается это в обработчике подобным образом: CanClose := MessageDlg('Exit now?', mtConfirmation, [mbYes, mbNo], 0) = mrYes.
OnCreate, OnDestroy(Sender: TObject) –событие,необходимое для описаниядействий, требуемых в начале или в конце работы приложения (открытие и закрытие файлов, чтение и сохранение настроек, инициализация переменных и т.п.).
OnHide, OnShow(Sender: TObject) –вызываются,когда форма становится видимойили невидимой (при присвоении соответствующего значения свойства Visible).
OnResize(Sender: TObject) –происходит,когда форма растягивается или сжимается.Здесь описывают изменение размеров и расположение компонентов на форме.
10. Продолжить оформление медиапроигрывателя.
1) Для того чтобы случайное заполнение было более случайным, в событии формы
OnCreate добавить Randomize.
procedure TMainForm.FormCreate(Sender: TObject); begin
Randomize;
RandomCells;
end;
2) Также желательно зациклить воспроизведение медиафайла, описать обработчик события медиапроигрывателя OnNotify. У MediaPlayer есть два свойства – Position: LongInt и Length: LongInt. Это, соответственно, текущая позиция в записи и длина записи. Событие проигрывателя OnNotify возникает при завершении различных управляющих методов MediaPlayer. Состояние проигрывателя можно узнать из свойства Mode.
Когда запись будет доигрываться до конца, будет вызываться метод Play, запускающий ее с начала. При остановке проигрывателя «перематываем» запись на начало.
if Position = Length then Play
procedure TMainForm.MPlayerNotify(Sender: TObject); begin
with MPlayer do case Mode of mpPlaying: if Position = Length then Play;
mpStopped: Rewind;
end;
end;
3) Установить название приложения и выбрать ему иконку. В главном меню открыть Project => Options. На вкладке Application, задать название приложения (это название, в частности, будет отображаться снизу на панели задач Windows), а также загрузить подходящую иконку. Стандартную иконку можно найти в папке C:\Program Files\Common Files\Borland Shared\Images\Icons, создать свою иконку – в редакторе Delphi (меню Tools => Image Editor) или в любом другом редакторе ресурсов.
Рис. 80.
Рис. 81.
11. Проанализируем недостатки: не выводится название проигрываемого файла, компоненты на форме не очень-то гармонируют друг с другом, неизвестно, сколько процентов записи проиграно на данный момент, нельзя устанавливать скорость визуализации, нет возможности редактирования и сохранения позиций игры "Жизнь".
Создайте копию проекта. Добавить в проект новую форму для управления воспроизведением медиафайла. Для создания новой формы щелкните на кнопку меню. Есть возможность сделать это и в пункте меню File => New… Там же можно создать форму с помощью мастера.
Добавьте на форму пять кнопок SpeedButton, TrackBar и таймер.
Рис. 82.
Кнопка SpeedButton отличается от обычной кнопки, во-первых, тем, что может содержать картинку, а во-вторых, тем, что может оставаться нажатой.
Рис. 83.
Основные свойства – Glyph:TPicture ( картинка), Down:boolean (нажата), основное событие – OnClick . У этой кнопки есть еще несколько важных свойств. Для того чтобы кнопка могла быть нажата, ее свойство Group: integer должно быть больше нуля. В этом случае все кнопки с одинаковым значением группы становятся переключателями – если нажать одну, остальные отщелкиваются. Это может быть нежелательно в случае одной кнопки с ненулевой группой – один раз нажав, ее нельзя отключить. В этом случае поможет свойство AllowAllUp: boolean. Современный вид кнопкам придает свойство Flat: boolean.
В программе откажемся от стандартного интерфейса MediaPlayer, и, сделав его невидимым, будем обращаться к нему через созданные кнопки. Коллекция иконок для кнопок находится в папке C:\Program Files\Common Files\Borland Shared\Images\Buttons\.
Настройка TrackBar проводится с помощью свойств ThumbLength: integer (длина бегунка), TickMarks: TTickMark (положение рисок линейки), TickStyle: TTickStyle (стиль рисок).
Настройте форму и компоненты. Измените имена компонент.
1) ControlForm: TControlForm Caption = ‘медиафайл не загружен’
BorderStyle = bsToolWindow ClientHeight = 24 ClientWidth = 402
2) NewSpBtn: TSpeedButton AllowAllUp = true
Flat = true Glyph: rety.bmp GroupIndex = 1
3) PosTrk: TTrackBar ThumbLength = 15 TickMarks = tmBoth TickStyle = lsNone
4) PosTimer = TTimer
Enabled = false
Interval = 500
5) MediaOpenSpBtn: TSpeedButton Flat = true
Glyph: MdOpen.bmp
6) PlaySpBtn: TSpeedButton AllowAllUp = true
Flat = true
Glyph: vcrplay.bmp GroupIndex = 1
7) PlaySpBtn: TSpeedButton AllowAllUp = true
Flat = true
Glyph: vcrpause.bmp GroupIndex = 1
8) StopSpBtn: TSpeedButton AllowAllUp = true
Flat = true
Glyph: vcrstop.bmp GroupIndex = 1
12. Когда требуется обратиться к каким-то переменным, функциям, типам, объектам, описанным в другом модуле, необходимо описать ссылку на этот модуль в разделе uses. Однако тонкость состоит в том, что uses может располагаться и в разделе interface, и в разделе implementation. При запуске приложения новое окно должно находиться под главным окном. Но если описать ссылки двух модулей друг на друга в разделах interface, возникнет так называемая ошибка круговой ссылки. В рамках Pascal два модуля не могут использовать интерфейс друг друга. Ссылка в интерфейсе нужна для того, чтобы при описании типов, классов, переменных интерфейса использовать типы и константы, описанные в других модулях. В данном интерфейсе используется, к примеру, класс TForm, TSpeedButton, TTrackBar, TTimer, описанные, соответственно, в модулях Forms, Buttons, ComCtrls, ExtCtrls. То есть использование других модулей в интерфейсе дает возможность, прежде всего, описать новые типы с помощью уже описанных типов. Именно поэтому запрещена круговая ссылка. Тогда потенциально возможно было бы описать: TypeA = array[0.. 4] of TypeB – в одном модуле и TypeB = array [0..99] of TypeA – в другом. То есть ignotum per ignotius –неизвестное через еще более неизвестное(лат.).
Что же касается использования не типов, но конкретных переменных и объектов, фигурирующих в других формах, то это использование происходит как раз в implementation,
и тут круговые ссылки вполне допустимы. При работе с несколькими формами важно также учитывать порядок их создания. Это касается обработки событий OnCreate – обращаться можно только к созданным формам.
Var ControlFom: TControlFom;
Implementation
{$R *.DFM}
procedure TControlFom.FormCreate (Sender: Tobject); begin
Top := MainForm.Top + MainForm.Height + 4;
Left := MainForm.Left;
end;
End.
Свои свойства Left и Top вторая форма подстраивает под те же свойства первой формы. При попытке запуска программы, однако, выводится сообщение о том, что не указан модуль , в котором описана первая форма.
Рис. 84.
Если нажать кнопку Yes, то в раздел uses автоматически добавится ссылка на нужный модуль. Однако , система не всегда автоматически работает. Лучше добавлять ссылки самостоятельно. В данном случае – в раздел implementation.
Implementation
uses MainUnit;
Здесь идет обращение к MainForm, и данная форма должна быть к этому моменту (то есть моменту создания ControlForm) уже созданной.
По умолчанию при создании приложения полагается , чтобы при запуске выводилась только главная форма. Однако в данном случае в программе должны быть видны обе формы. Обязательно, у ControlForm установить свойство Visible := true. Иначе форма будет не видна при запуске программы.
Рис. 85.
Можно описать тот же код , с точностью до перемены ссылок, в обработчике MainForm.OnCreate главной формы. Для того чтобы выбрать нужный модуль, нажмите на кнопку панели инструментов (выбрать модуль для редактирования). Соседняя кнопка служит для выбора форм (выбрать форму для редактирования). Следующая кнопка – переключатель модуль/форма.
Рис. 86.
Первая форма создается раньше второй. Следовательно, и событие OnCreate у нее возникает еще до того, как создана вторая форма, и значит попытка доступа к ней (попытка установить ее положение) вызовет ошибку.
13. Оставим главной форме только предназначение экрана. Удалите код внутри обработчиков кнопок, а также сами кнопки.
procedure TMainForm.MediaOpenBtnClick (Sender : TObject); begin
end;
procedure TMainForm.SetColorBtnClick (Sender : TObject); begin
end;
Установите медиапроигрывателю Visible := false, переместите его поверх панели. Если панель в форму добавлена позже проигрывателя, то проигрыватель окажется под панелью. Поэтому предварительно поменяйте порядок – щелкните правой кнопкой мыши на проигрыватель и выберите "Bring To Front".
Рис. 87.
Теперь измените клиентскую высоту формы. Экран готов.
Рис. 88.
Теперь предстоит описать обработчики компонентов второй формы. Таймер будет передвигать бегунок, отображая процент проигранной записи.
procedure TControlForm.PosTimerTimer(Sender: TObject); begin
PosTrkBar.Position := MainForm.MPlayer.Position; end;
procedure TControlForm.PosTrkBarChange(Sender: TObject); begin
if not PosTimer.Enabled then MainForm.MPlayer.Position := PosTrkBar.Position;
end;
5. обработчике кнопки загрузки помещается код, похожий на тот, что уже писали. Код относится к компонентам главной формы. Из-за этого необходимо указывать вторую форму, когда обращаются к ее компонентам, хотя и так находятсяся в обработчике второй формы.
Обратите внимание на два таймера – один запускает визуализацию, а другой двигает бегунок. Передвижения бегунка действенны, только когда воспроизведение остановлено – PosTimer.Enabled := false. Иначе происходит конфликт – таймер меняет позицию бегунка, а
бегунок в ответ меняет позицию проигрывателя. Если необходимо менять позицию во время воспроизведения, придется вводить дополнительные проверки.
Когда запись остановлена, можно поменять ее позицию тем же бегунком. Кнопки управления программно запускают и останавливают проигрыватель. Пока файл не загружен, их следует отключить, иначе при нажатии на них произойдет ошибка. Последняя кнопка определит, проигрывать ли запись в цикле.
procedure TControlForm.PlaySpBtnClick(Sender: TObject); begin
MainForm.MPlayer.Play;
PosTimer.Enabled := true;
end;
procedure TControlForm.PauseSpBtnClick(Sender: TObject); begin
MainForm.MPlayer.Pause;
PosTimer.Enabled := false;
end;
procedure TControlForm.StopSpBtnClick(Sender: TObject); begin
MainForm.MPlayer.Stop;
PosTimer.Enabled := false;
end;
Запуская и останавливая проигрыватель, мы запускаем и останавливаем таймер.
Необходимо внести изменения в код в модуле MainUnit, событие OnNotify проигрывателя:
procedure TMainForm.MPlayerNotify(Sender: TObject); begin
if ControlForm.RewSpBtn.Down then
with MPlayer do
if NotifyValue = nvSuccessful then
Begin
Notify := true;
Play;
end;
end;
Здесь происходит проверка, зажата ли кнопка " цикличного воспроизведения" во второй форме. При открытии файла необходимо включить все кнопки и бегунок (изначально Enabled := false), запустить таймеры, настроить PosTrkBar на длину записи и вывести название воспроизводимого файла в Caption формы:
procedure TControlForm.MediaOpenSpBtnClick(Sender: TObject); begin
with MainForm do
if MediaOpenDlg.Execute then
Begin
MPlayer.FileName := MediaOpenDlg.FileName;
MPlayer.Open;
MPlayer.Display := ScreenPanel;
MPlayer.DisplayRect := Rect(0, 0, ScreenPanel.Width, ScreenPanel.Height); MPlayer.Play;
LifeImage.Visible := not (ExtractFileExt(MPlayer.FileName) = '.avi'); LifeTimer.Enabled := true;
ControlForm.PosTimer.Enabled := true; ControlForm.PosTrkBar.Max := MPlayer.Length; ControlForm.PosTrkBar.Enabled := true; ControlForm.PlaySpBtn.Enabled := true; ControlForm.PauseSpBtn.Enabled := true; ControlForm.StopSpBtn.Enabled := true; ControlForm.Caption := MediaOpenDlg.Filename;
end;
end;
2. Добавить к медиапроигрывателю игру «жизнь». Для управления визуализацией потребуется отдельная форма. С помощью этой формы можно очищать, заполнять и редактировать конфигурации клеток игры «Жизнь». Более того, появляется возможность сохранять интересные комбинации в специальные файлы с введенным нами расширением
.lif. Кроме того, можно будет управлять скоростью «жизни» и, что уже реализовывалось, задавать цвет поля и клеток.
Создайте новую форму, сохраните ее модуль, поместите на нее пять кнопок Button, одну SpeedButton, один TrackBar, две надписи Label и диалоги загрузки и сохранения. Измените параметры компонент:
LifeSaveDlg: TSaveDialog DefaultExt = ‘lif’
Filter = ‘файлы игры «Жизнь» (*.lif)|*.lif’ Title = ‘Загрузить позицию игры’
LifeOpenDlg: TOpenDialog DefaultExt = ‘lif’
Filter = ‘файлы игры «Жизнь» (*.lif)|*.lif’ Options.ofFileMustExist = true
Title = ‘Сохранить текущую позицию игры’
Рис. 89.
3. модуле второй формы добавьте строки, при открытии файла выводящие или скрывающие третью форму и отпускающие кнопку.
procedure TControlForm.MediaOpenSpBtnClick(Sender: TObject); begin
with MainForm do
if MediaOpenDlg.Execute then
Begin
MPlayer.FileName := MediaOpenDlg.FileName;
MPlayer.Open;
MPlayer.Display := ScreenPanel;
MPlayer.DisplayRect := Rect(0, 0, ScreenPanel.Width, ScreenPanel.Height); MPlayer.Play;
LifeImage.Visible := not (ExtractFileExt(MPlayer.FileName) = '.avi'); LifeForm.Visible := LifeImg.Visible; LifeForm.EditSpBtn.Down := false;
LifeTimer.Enabled := true; ControlForm.PosTimer.Enabled := true; ControlForm.PosTrkBar.Max := MPlayer.Length; ControlForm.PosTrkBar.Enabled := true; ControlForm.PlaySpBtn.Enabled := true; ControlForm.PauseSpBtn.Enabled := true; ControlForm.StopSpBtn.Enabled := true; ControlForm.Caption := MediaOpenDlg.Filename;
end;
end;
На новой форме LifeForm располагаются кнопки LifeOpenBtn, LifeSaveBtn, FillBtn, ClearBtn, SetColorBtn, EditSpBtn, SpeedTrkBar. Настройте компоненты новой формы:
LifeForm: TLifeForm
BorderStyle = bsToolWindow
Caption = ‘Визуализация’
ClientWidth = 402
ClientHeight = 56
EditSpBtn: TSpeedButton
AllowAllUp = true
Caption = ‘редактировать’
GroupIndex = 1
SpeedTrkBar:TTrackBar
Frequency = 50
Max = 1000
Min = 1
Position = 100
ThumbLength = 15
TickMarks = tmTopLeft
Рис. 90.
5. обработчике загрузки медиафайла необходимо добавить следующие строки.
LifeForm.Visible := LifeImg.Visible;
Если LifeImg видимый, т.е. нужна визуализация для звукового файла, то форма управления визуализацией тоже выводится, если же LifeImg спрятан (воспроизводится видеофайл), то и присутствие формы управления визуализацией излишне.
LifeForm.EditSpBtn.Down := false;
Кнопка EditSpBtn будет отвечать за редактирование клеток (если она нажата, включен режим редактирования). Во время редактирования таймер LifeTimer должен быть отключен. Поскольку здесь, при открытии, мы включаем этот таймер, то режим редактирования должен быть отключен и кнопка отпущена.
…
MPlayer.Play;
LifeImg.Visible := not (ExtractFileExt(MPlayer.FileName) = '.avi'); LifeForm.Visible := LifeImage.Visible; LifeForm.EditSpBtn.Down := false;LifeTimer.Enabled := true; ControlForm.PosTimer.Enabled := true;
….
Необходимо описать обработчики событий для новых компонентов. Определим при создании формы ее местоположение.
5. модуле LifeUnit:
var LifeForm: TLifeForm;
Implementation
uses MainUnit, ControlUnit;
procedure TLifeForm.FormCreate(Sender: TObject); begin
Top := ControlForm.Top + ControlForm.Height + 4; Left := ControlForm.Left;
end;
При нажатии на кнопки очистки и заполнения мы используем процедуры, описанные в модуле главной формы.
5. модуле LifeUnit:
procedure TLifeForm.ClearBtnClick(Sender: TObject); var
i, j: integer;
Begin
for i := 0 to XSize - 1 do
for j := 0 to YSize - 1 do
A[i, j] := false;
DrawCells;
end;
procedure TLifeForm.FillBtnClick(Sender: TObject); begin
RandomCells;
DrawCells;
end;
Однако для того, чтобы подобный вызов был возможен, необходимо в главном модуле объявить эти процедуры в интерфейсе. Извне доступно только то, что объявлено в интерфейсе. В MainUnit необходимо "вывести" в интерфейс объявление процедур:
Var
MainForm: TMainForm;
4. TLifeCells; procedure RandomCells; procedure DrawCells;
Implementation
uses ControlUnit;
{&r *.DFM}
ТrackBar устанавливает интервал для таймера, задавая тем самым скорость визуализации. А кнопка редактирования переключает режим редактирования, останавливая и включая таймер.
procedure TLifeForm.FillBtnClick(Sender: TObject); begin
RandomCells;
DrawCells;
end;
procedure TLifeForm.SpeedTrkBarChange(Sender: TObject); {Меняет скорость«жизни»} begin
MainForm.LifeTimer.Interval := SpeedTrkBar.Position; end;
procedure TLifeForm.EditSpBtnClick(Sender: TObject);{включает/выключает режим редактирования} begin
MainForm.LifeTimer.Enabled := not EditSpBtn.Down; end;
Само редактирование клеток происходит в главном модуле, в обработчике OnMouseDown компонента LifeImg.
procedure TMainForm.LifeImgMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
Begin
if LifeForm.EditSpBtn.Down then
A[X div 10, Y div 10] := not A[X div 10, Y div 10]; DrawCells;
end;
В uses нужно описать ссылку на LifeUnit.
При запуске программы получается примерно такая картинка.
Рис. 91.
Теперь можно редактировать позиции.Вначале при загрузке и сохранении картинок и прочих файлов использовались специальные методы объектов, в которые происходила загрузка. Теперь произведем эти операции вручную, пользуясь процедурами работы с типизированными файлами.
Типизированные файлы содержат записи определенного типа. К примеру, file of integer может хранить произвольное количество переменных integer; file of TLifeCells – произвольное количество переменных типа TLifeCells. Однако для наших целей достаточно только одной записи. При работе с типизированными файлами используются следующие процедуры.
AssignFile(var F; FileName: string) –связывает файловую переменнуюFс текстовым именемфайла. Это действие необходимо сделать перед всеми последующими операциями.
Reset(F) –открывает существующий файл,связанный с переменнойF,и устанавливаетпозицию чтения-записи в начало.
Rewrite(F) –создает файл,соответствующий файловой переменнойF.
Read(F, V) –читает из файла,связанного сF,данные в типизированную переменнуюV.Позиция файла увеличивается на один файловый компонент, байтовый размер которого равен размеру типа переменной (для integer это 4 байта).
Write(F, V) –записывает в файл,связанный сF,типизированную переменнуюV.Позицияфайла увеличивается на один файловый компонент.
Seek(F, N: LongInt) –перемещает позицию файла к номеруN,начальная позиция приN = 0. CloseFile(var F) –закрывает файлF.
5. главном модуле описан тип TFileCells:
{Private declaration}
Public
{Public declaration}
end;
Const
XSize = 40;
YSize = 25;
Type
TFileCells = array [0 .. XSize – 1, 0 .. YSize – 1] of boolean;
Var
MainForm: TMainForm;
A: TFileCells;
4. обработчике OnClick кнопки LifeOpen определяем файл такого же типа. Если файл выбран в диалоге, ассоциируем имя файла с переменной, устанавливаем позицию для чтения
5. начало и считываем из файла данные в переменную A, описанную в MainUnit и хранящую положения клеток.
procedure TLifeForm.LifeOpenBtnClick(Sender: TObject); var
b file of TLifeCells; begin
if LifeOpenDlg.Execute then
if FileExists(LifeOpenDlg.FileName) then
Begin
AssignFile(F, LifeOpenDlg.FileName); Reset(F);
Read(F, A);
CloseFile(F);
DrawCells;
end;
end;
Подобное чтение корректно, поскольку типы файла и переменной A совпадают.
При записи в файл ситуация похожая , только вдобавок проводится проверка, существует ли файл. Если нет, то он создается; если да, то должны спросить, действительно ли пользователь хочет его перезаписать. Если он просто ошибся, то закрываем файл и выходим из обработчика; если нужно переписать, открываем его и устанавливаем позицию записи в начало. Затем производится запись переменной и закрытие файла.
procedure TLifeForm.LifeSaveBtnClick(Sender: TObject); var
f: file of TLifeCells; begin
if LifeSaveDlg.Execute then begin
AssignFile(F, LifeSaveDlg.FileName);
if not FileExists(LifeSaveDlg.FileName) then Rewrite(F)
else if MessageDlg('Перезаписать?', mtWarning, [mbYes, mbNo], 0) = mrYes then Reset(F)
else begin CloseFile(F); exit;
end; Write(F, A); CloseFile(F); end;
end;
Работа с нетипизированными файлами похожа на работу с типизированными. Отличия в том, что объявляются такие файлы просто var F: file; (без of …), при открытии – Reset(F, 1) – нужно указать размер блока записи (который по умолчанию равен 128), чтение
3. запись происходят с помощью процедур BlockRead, BlockWirite(var F: File; var Buf; Count: Integer), где Buf – переменная, в которую (или из которой) идет запись, Count – число блоков записи (размер блока был определен в Reset). Если надо писать произвольные данные (к
примеру, a: integer; b: boolean; c: TLifeCells; d: string[20]), сделайте следующее.
При записи:
Rewrite(F, 1);
BlockWrite(F, a, SizeOf(a));
BlockWrite(F, b, SizeOf(b));
BlockWrite(F, c, SizeOf(c));
BlockWrite(F, d, SizeOf(d));
CloseFile(F);
При чтении, соответственно:
Reset(F, 1);
BlockRead(F, a, SizeOf(a));
BlockRead(F, b, SizeOf(b));
BlockRead(F, c, SizeOf(c));
BlockRead(F, d, SizeOf(d));
CloseFile(F);
4. Чтобы решить проблему цвета, необходимо сделать специальное собственное диалоговое окно, позволяющее выбрать цвет. Раньше мы вызывали стандартные диалоги.
Диалог –это обычная форма,которая,однако,вызывается специальным методомShowModal и возвращает модальный результат. Модальный вызов приводит к тому, что при выведенном диалоге нельзя переключиться ни к одной другой форме приложения, пока не будет нажата одна из модальных кнопок диалога, после чего диалог закроется и управление вернется в приложение. Модальным кнопкам даже не надо описывать обработчики. Просто надо установить свойство ModalResult не равным mrNone.
Создайте новую форму, сохраните модуль как ColorUnit. Добавьте на нее две фигуры
Shape (CellShape: TShape, FieldShape: TShape), кнопку «Утвердить» (ModalResult = mrOk), кнопку «Отмена» (ModalResult = mrCancel).
Рис. 92.
Настройте форму. В частности, задайте ее позицию и определите модальный результат для кнопок.
ColorForm: TColorForm
BorderStyle = bsToolWindoiw
Caption = выберите цвета
Position = poScreenCenter
2. обработчике нажатия на фигуры Shape опишите вызов диалогов. Обработчики для кнопок можете не описывать.
3. модуле ColorUnit – обработчики нажатия на FieldShape и CellShape:
procedure TColorForm.FieldShapeMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
Begin
MainForm.FieldColorDlg.Execute;
FieldShape.Brush.Color := MainForm.FieldColorDlg.Color;
end;
procedure TColorForm.CellShapeMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
Begin
MainForm.CellColorDlg.Execute;
CellShape.Brush.Color := MainForm.CellColorDlg.Color; end;
3. обработчике кнопки "задать цвета" на форме визуализации опишите модальный вызов этого нового диалога.
4. модуле LifeUnit описываем обработчик SetColorBtn:
procedure TLifeForm.ColorBtnClick(Sender: TObject); var
C1, C2: TColor;
Begin
C1 := MainForm.FieldColorDlg.Color;
C2 := MainForm.CellColorDlg.Color;
ColorForm.FieldShape.Brush.Color := C1;
ColorForm.CellShape.Brush.Color := C2;
if ColorForm.ShowModal = mrCancel then
Begin
MainForm.FieldColorDlg.Color := C1;
MainForm.CellColorDlg.Color := C2;
end;
end;
3. данном случае вызывается форма ColorForm – диалог установки цвета. Если в нем нажата кнопка "Отмена", то значения цветов восстанавливаются. Они специально для этого перед вызовом сохраняются в C1 и C2.
4. Пользователь проигрывателя может случайно закрыть окно формы управления. Следователь, придется перезапускать программу.
Можно решить эту проблему следующим образом. При попытке закрытия спросить пользователя, хочет ли он совсем выйти из программы. И если хочет – закрыть главную форму.
procedure TControlForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin
if MessageDlg('Выйти из программы?', mtWarning,[mbYes, mbNo], 0) = mrYes then MainForm.Close else CanClose := false;
end;
Этой конструкцией закрывается главная форма из формы управления. То же событие можно обработать и в главной форме, каждый раз спрашивая о желании выйти.
Запустите программу.
Рис. 93.
Подведем итоги. Для создания многооконности необходимо:
4. Создать очередную форму.
5. Модули, предназначенные пользователю, поместить в interface, а модули, предназначенные программистуто, поместить в uses.
6. Необходимо помнить о круговых ссылкахи и избегать ignotum per ignotius. В интерфейс поместить только необходимое.
7. В OnCreate делать описание, не забывая о порядке создания форм в файле проекта.
8. Программа заканчивается, когда закрывается главная форма. Остальные формы приложения могут закрываться сколько угодно.
9. Диалоги: вызов ShowModal, результат – ModalResult нажатой кнопки.
10. Выбрать нужную форму или модуль для редактирования можно с помощью кнопок панели инструментов или клавишами Ctrl-F12 и Shift-F12. Переключение модуль-форма – просто клавишей F12.
ПРИЛОЖЕНИЕ 1
Дата добавления: 2019-09-13; просмотров: 211; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!