Динамическое создание компонентов, или Палитра компонентов — для ленивых!

Во всех предыдущих уроках вы создавали интерфейс пользователя вручную, размещая компоненты на форме. Но может возникнуть такая ситуация, когда при различных действиях пользователя на форме должны располагаться различные компоненты, либо на форме необходимо разместить очень много одинаковых компонентов. В этом случае будет удобно динамически создавать требуемые компоненты в режиме Runtime (в режиме работы приложения) и размещать их нужным образом.

Задачи урока

  • Динамическое создание компонент.
  • Работа с компонентом RadioGroup.

Выполнение упражнения

В этом уроке мы напишем приложение-игру (рисунок 1).

Правила игры будут следующие: на форме появляется определённое количество частиц (от 30 до 120 штук) заданных размеров и двух цветов (цвета также задаются). Эти частицы хаотически движутся внутри игрового пространства.

Цель игры: щелчком мыши убрать частицы только одного цвета (выигрышного цвета). Если мышью игрок щёлкнет на проигрышный цвет, то игра закончится.

В первой части урока мы создадим интерфейс будущей игры, рассмотрим вопросы, связанные с динамическим созданием компонентов и установкой им требуемых свойств.

Во второй части урока мы научимся работать с массивом динамически созданных компонентов и доведём до конца идею игры.

а)image002 б) image004
Рисунок 1. Окно приложения

1. Дизайн приложения

  1. Поместите на форму компоненты, как показано на рисунке 2а, и установите значения их свойств согласно рисунку 2б.

а)image006 б) image008
Рисунок 2

Это будет основная форма игры. На ней расположены следующие компоненты:

  • Белый квадрат на форме — это компонент Shape.
  • Большое чёрное поле (Panel2) — это игровая область. На ней будут разноцветные движущиеся частицы. Они представляют собой компоненты Shape. Но почему мы поместили только один такой компонент на форму? Да потому, что помещать туда 120 штук, как минимум, безумие! Эти компоненты будут созданы динамически в момент работы приложения. А для чего нужен этот один, мы рассмотрим ниже.
  • Таймер необходим для перемещения частиц по полю. Установите свойство таймера Interval = 50.
  • На компоненте Panel1 расположены две кнопки: кнопка «Новая» нужна для задания параметров игрового процесса, кнопка «Создание» — для динамического создания компонентов.

Компонент Shape предназначен для оформления приложения графическими примитивами и принимает разные формы: прямоугольник, прямоугольник со скруглёными углами, квадрат, эллипс, круг. Для этого у него есть одноимённое свойство Shape. Свет и стиль контура фигуры и её заливки изменяются через составные свойства Pen и Brush.

Установите свойство Visible = False у компонентов Shape и Panel3. Эти компоненты не должны быть видны при запуске приложения.

У компонента Panel3 установите следующие параметры шрифта: жирный, размер 24. Этот компонент будет выводить сообщения о победе либо о поражении игрока.

  1. Создайте вторую форму: File ? New ? Form, или кнопкой image009 на панели инструментов.
  2. Поместите на вторую форму компоненты (рисунок 3а) и установите значения их свойств согласно рисунку 3б.

а)image011 б) image011
Рисунок 3

Эта форма будет отображаться при нажатии кнопки «Новая» главной формы. Здесь игрок может выбрать проигрышный и выигрышный цвета, количество и размер частиц.

Обратите внимание на новый компонент — RadioGroupimage014 (категория Standart). Этот компонент из той же серии, что и компоненты Panel и GroupBox, т. е. контейнер. Но в него нельзя помещать компоненты непосредственно из палитры компонентов! Он предназначен для хранения списка компонентов RadioButton, которые задаются через свойство Items (представляет собой многострочный редактор). Например, для задания трёх переключателей по выбору количества частиц необходимо заполнить редактор так:

image013
Рисунок 4

Следующим, пока незнакомым нам компонентом, является ColorDialog (категория Dialog). Этот компонент предназначен для выбора цвета.

  1. Измените имена компонентов следующим образом:

Имя, которое было

Имя, на которое

необходимо изменить

Для главной формы
Form1 FormGame
Panel1 PanelBar
Panel2 PanelGame
Panel3 PanelResult
Shape1 ShapeStar
Button1 (Новая) ButtonNew
Button2 (Выход) ButtonExit
Button3 (Создание) ButtonCreate
Timer1 Timer
Для формы параметров новой игры
Form2 FormNew
Button1 ButtonFonTrue
Button2 ButtonFonFalse
Button3 (Начать игру) ButtonNew
ColorDialog1 ColorDialog
Panel1 PanelColorTrue
Panel2 PanelColorFalse
RadioBox1 RadioSize
RadioBox2 RadioN

 

 

 

 

 

 

2. Начальные параметры игры

  1. Прежде всего, объявите глобальные переменные, которые будут использованы в игре (выделено жёлтым цветом):
var
  FormGame: TFormGame;
  Star:TShape;      // Шаблон для динамического создания компонентов Shape
  n,                // Число частиц в игре
  Size,             // Размер частиц (пикс)
  f:integer;        // Переменная, использующаяся в циклах
  ColorFalse,       // Проигрышный цвет
  ColorTrue:TColor; // Выигрышный цвет

Implementation

Листинг 1

Для чего нужна каждая переменная, понятно из комментариев.

  1. Создайте обработчик события OnCreate для главной формы и запишите в него следующие строки:
procedure TFormGame.FormCreate(Sender: TObject);
begin

  randomize;             // Активация генератора случайных чисел
  n := 30;               // Изначально число частиц в игре 
  Size := 10;            // Начальный размер частиц 
  colorFalse := Clred;   // Цвет проигрыша
  colorTrue  := ClGreen; // Цвет выигрыша

end;

Листинг 2

Поясним, что делает код:

  • активирует генератор случайных чисел;
  • задаёт количество частиц в игре и их размер;
  • задаёт цвета выигрышных и проигрышных частиц.
  1. Теперь пришло время динамического создания компонентов Shape — будущих частиц. Напишите обработчик события OnClick для кнопки ButtonCreate:
procedure TFormGame.ButtonCreateClick(Sender: TObject);
// Объявляем переменную для случайного выбора цвета 
Var color: Integer;						
begin

// Цикл для создания n компонент Shape 
  For f := 1 to n do begin 
    Star := TShape.Create(FormGame); 		// Создание компонента
    Star.Name := 'Sh'+IntToStr(f); 		    // Присвоение компоненту уникального имени
    Star.Width  := Size; 					// Размер по вертикали
    Star.Height := Size; 					// Размер по горизонтали
    Star.Top       := random(PanelGame.Height - Size);	// Случайное задание координаты X
    Star.Left      := random(PanelGame.Width  - Size);	// Случайное задание координаты Y
    Color := random(2);						// Случайное задание цвета
    if color = 0 then Star.Brush.Color := ColorFalse
                 else Star.Brush.Color := ColorTrue;
    Star.Parent  :=  PanelGame; 			   // Отображение на компоненте PanelGame
end; 

end;

Листинг 3

Поясним код:

  • динамически cоздаём заданное число частиц n в виде объектов класса Shape(выделено жёлтым). Создание нового объекта происходит с помощью вызова метода Create (переводится как «создать»), для класса TShape. В качестве параметра конструктору необходимо передать имя формы. В результате такого объявления:
    Star := TShape.Create(FormGame);
    При этом выделяется место в памяти для компонента класса TShape;
  • присваиваем каждому вновь созданному объекту уникальное имя sh*, где * означает порядковый номер объекта.
  • cозданный объект — фигура, имеет нулевую ширину и высоту, и поэтому мы задаём его размеры согласно значению переменной Size (выделено зелёным);
  • кроме нулевых размеров объект при динамическом создании имеет и нулевые координаты. А т. к. частицы «разбросаны» по всему игровому полю, то необходимо задать координаты частиц случайным образом так, чтобы они не выходили за пределы этого поля (выделено голубым);
  • частицы могут быть двух цветов (проигрышного и выигрышного). Поэтому с помощью генератора случайных чисел определяем, какого цвета будет очередная частица (выделено красным);
  • отображаем созданный компонент Star на панели PanelGame c помощью свойства Parent (выделено синим).
  1. Хотя частицы у нас уже создаются, и даже отображаются на экране, запускать приложение пока не рекомендуется. Дело в том, что созданные объекты располагаются в оперативной памяти компьютера, и после завершения работы приложения оттуда не удаляются.

После многократного динамического создания компонентов операционная система будет работать медленней и, в конце концов, выдаст сообщение о нехватке оперативной памяти.

Чтобы этого не произошло, нам нужно самим позаботиться об удалении динамически созданных компонентов из памяти. Для этого применяется метод Free (переводится как «свободный») для каждого из созданных компонентов.

Для того чтобы удалить динамически созданный компонент из памяти, к нему нужно сначала обратиться. На прямую обратится к нему мы не можем, так как до запуска программы он не существует. Поэтому мы будем использовать свойство FindComponent, через которое происходит поиск компонента по его имени.

Напишите обработчик события FormClose для главной формы:

Procedure TFormGame.FormClose(Sender: TObject; varAction: TCloseAction);
begin 

  For f:=1 to n do ( FindComponent( 'sh'+IntToStr(f) ) ).Free; 	// Очищаем память от динамически созданных компонентов

end;

Листинг 4

Это событие возникает в момент закрытия формы.

Здесь организован цикл поиска по имени динамически созданных компонентов, при помощи свойства FindComponent(‘sh’+IntToStr(f)), с последующим удалением их из оперативной памяти компьютера – free.

  1. Запустите приложение и один раз (!) нажмите на кнопку «Создание». В результате увидим примерно то, что показано на рисунке 5 (примерно — потому, что расположение частиц задаётся случайным образом). Но вот досада… частицы создаются, но на нажатие по ним кнопкой мыши они никак не реагируют. Закройте приложение.

image020
Рисунок 5

Возникает резонный вопрос: почему на кнопку «Создать» можно нажать только один раз? Да потому, что перед тем, как создать новый компонент с тем же самым именем, необходимо удалить старый (методом Free). Но эту проблему мы решим чуть позже.

Теперь вы научились динамически создавать компоненты в режиме RunTime.

3. Коротко о главном

Иногда требуемые компоненты удобно создавать динамически в режиме Runtime (в режиме работы приложения) и размещать их требуемым образом.

Создание нового компонента происходит с помощью вызова метода Create (Конструктор). В качестве параметра конструктору необходимо передать имя формы.

Динамически созданный объект имеет нулевую ширину, высоту и координаты: [0,0].

Отображение созданного компонента происходит через вызов свойства Parent и присвоение ему имени контейнера, на котором компонент будет размещён (например, форма). Для отображения динамически созданной формы необходимо вызвать метод Show (либоShowModal).

Перед окончанием работы приложения, либо перед повторным созданием компонентов с помощью одной и той же переменной, необходимо удалить созданные компоненты с помощью вызова метода Free.

Компонент RadioGroup (категория Standart) представляет собой контейнер. Но только в него нельзя помещать компоненты непосредственно из палитры компонентов. Он предназначен для хранения списка компонентов RadioButton, которые задаются через свойствоItems этого компонента.

Динамическое создание компонентов, или Как с ними работать?

Задачи урока

  • Работа с массивом динамически созданных компонентов.
  • Работа с компонентом RadioGroup.
  • Работа с компонентом ColorDialog.

Выполнение упражнения

Мы написали код только для отображения частиц с заданными свойствами. В этом уроке пора реализовать основную задумку игры: игрок должен убрать с поля частицы только одного цвета (щёлкая по частицам мышью). Если он справляется с заданием, то выводится надпись «Выигрыш!». Если игрок нажимает на частицу с «запретным» цветом, то игра прекращается и выводится сообщение «Вы проиграли!».

 а)image002  б) image013
Рисунок 1. Окно приложения

1. События динамически созданных компонентов

1. Загрузите проект, созданный в первом разделе урока.

2. Как же заставить каждую частицу реагировать на щелчок мыши? Для этого, как и в уроке № 7 — Управление событиями, мы событие OnMouseDown для всех частиц (компонентов Shape), реагирующее на щелчок мыши, «перенаправим» на то же самое событие, но только уже реально существующего на форме объекта ShapeStar (вот как раз для этого мы его и помещали на форму). А от какой именно частицы пришло событие, мы будем определять с помощью параметра Sender.

Напишите следующий обработчик события OnMouseDown для единственного расположенного на форме компонента ShapeStar:

procedure TFormGame.ShapeStarMouseDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);
// Переменная, определяющая, все ли выигрышные частицы убраны, если p = true, то все, и игрок выиграл
Var p:boolean;
begin

  TShape(Sender).visible:= false;          // Убираем с панели компонент, на который нажал игрок!
  // Определение проигрыша
  If TShape(Sender).Brush.Color = ColorFalse then begin
    PanelResult.Font.Color:=clred;        // Устанавливаем красный цвет для шрифта панели PanelResult 
    PanelResult.Caption:='Проигрыш!';     // Пишем на панели, что игрок проиграл
    PanelResult.Visible:=True;            // Показываем PanelResult
    PanelGame.Enabled:= False;            // Делаем неактивной игровую область (компонент PanelGame)
    Exit;                                 // Выходим из процедуры
  end; 

  // Определение выигрыша
  // Все ли убраны выигрышные частицы? (если все, то p = True, иначе False)
  p:= false;
  for f:= 1 to n do
    if (TShape( FindComponent('sh'+IntToStr(f)) ).visible = true) and 
       (TShape( FindComponent('sh'+IntToStr(f)) ).Brush.color = ColorTrue) then p:= true;  
  // Если убраны все, то выводим сообщение о победе игрока
  If not p then begin                     // not p эквивалентно записи p = false
    PanelResult.Font.Color:=clGreen;      // Устанавливаем зелёный цвет для шрифта панели PanelResult 
    PanelResult.Caption:='Вы выиграли!';  // Пишем на панели, что игрок выиграл
    PanelResult.Visible:=True;            // Показываем PanelResult
    PanelGame.Enabled:=False;             // Делаем неактивной игровую область (компонент PanelGame)
  End;
end;

Листинг 1

 

Поясним написанный код:

  • Вначале мы должны привести параметр Sender к типу объекта TShape. Потом установить у приведенного объекта свойство Visible в False (выделено жёлтым). Это необходимо для того, чтобы частица, по которой щёлкнул игрок, исчезла с поля.
  • Определяем проигрыш. Для этого просто сверяем цвет исчезнувшей частицы с «проигрышным» цветом (выделено зелёным). Если цвета совпадают, то выводим сообщение «Проигрыш» в панель PanelResult, предварительно отобразив её на экране. Для того чтобы игроку после проигрыша было недоступно игровое поле, делаем его неактивным. Далее выходим из процедуры обработки события с помощью оператора Exit для предотвращения выполнения ненужного кода, который следует далее в процедуре.
  • Если игрок нажал на «выигрышную» частицу, то условие предыдущего пункта не выполняется. Теперь нам нужно проверить, все ли частицы игрок убрал с поля? Для этого в цикле опрашиваем все оставшиеся на поле частицы на предмет наличия «выигрышного» цвета (выделено голубым). Если таких частиц не осталось, то выводим сообщение о победе игрока!

3. Итак, «мозг» игры реализован! Но остаётся одна проблема: как объяснить программе, что процедура ShapeMouseDown обработчика события OnMouseDown будет распространяться на все частицы? Очень просто! Достаточно при создании массива объектов Shape указать имя процедуры, которая будет выполняться при возникновении события OnMouseDown. Дополните код процедуры ButtonCreateClick следующей строчкой (выделена жёлтым):

if color = 0 then  Star.Brush.Color := ColorFalse
             else  Star.Brush.Color := ColorTrue;
Star.OnMouseDown  := ShapeMouseDown;   // Событие щелчка
Star.Parent       := PanelGame;        // Отображаем на компоненте PanelGame

 Листинг 2

Эта строка означает, что событие OnMouseDown динамически созданного компонента будет ссылатся на реально существующую процедуру ShapeStarMouseDown.

4. Запустите приложение и опять один раз! нажмите на кнопку «Создание». Теперь игра ожила! При нажатии на частицы кнопкой мыши они исчезают. Причём, если нажата частица с «проигрышным» цветом, то выводится сообщение о поражении, а если все частицы с «выигрышным» цветом убираются с поля, то выводится сообщение о победе.

 

2. Как начать игру заново?

Введём в игру возможность пользователю выбирать цвет частиц, их размер и количество. Как раз для этого мы и разработали вторую форму — FormNew.

1. Но для начала создайте обработчик события OnClick для кнопки ButtonNew главной формы:

procedure TFormGame.ButtonNewClick(Sender: TObject);
begin

  FormNew.ShowModal; 

end;

Листинг 3

Здесь мы модально показываем форму параметров новой игры.

2. Перейдите на форму FormNew (рисунок 2). Создайте обработчик события OnCreate для формы FormNew и запишите в нём следующий код:

procedure TFormNew.FormCreate(Sender: TObject);
begin

  PanelColorTrue.Color := colorTrue;
  PanelColorFalse.Color:= colorFalse;

end;

 Листинг 4

Эти строки означают, что соответствующие панели окрашены «проигрышным» и «выигрышным» цветами. Эти цвета можно поменять, нажав на соответствующую кнопку «Изменить».

image013
Рисунок 2

3. Для того чтобы их поменять, напишите обработчики события OnClick для этих кнопок:

procedure TFormNew.ButtonFonTrueClick(Sender: TObject);
begin

  // Выбираем выигрышный цвет
  if ColorDialog.Execute then colorTrue := ColorDialog.Color;
  PanelColorTrue.Color := СolorTrue;

end;

Листинг 5


 

procedure TFormNew.ButtonFonFalseClick(Sender: TObject);
begin

  // Выбираем проигрышный цвет
  if ColorDialog.Execute then colorFalse:= ColorDialog.Color;
  PanelColorFalse.Color:= colorFalse;

end;

 Листинг 6

Здесь, как и в случае с окном стандартного диалога открытия файла «Открыть», вызываем метод Execute, только вместо файлов выбираем цвет. Выбранный цвет записывается в соответствующую переменную и отображается на панели.

4. Запустите приложение и нажмите на кнопку «Новая». Появится вторая форма с окрашенными панелями. Нажмите на какую-нибудь кнопку «Изменить», при этом появится диалог выбора цвета (рисунок 3).

image023
Рисунок 3

Выберите в нём любой цвет и нажмите на кнопку «ОК». Диалоговое окно закроется, и панель, находящаяся напротив нажатой кнопки, окрасится в выбранный цвет. Закройте приложение.

5. Теперь осталось обработать нажатие на кнопку «Начать игру», чтобы игровое пространство сформировалось согласно выставленным параметрам. Напишите обработчик события OnClick для кнопки ButtonNew:

procedure TFormNew.ButtonNewClick(Sender: TObject);
var f:integer;
begin

  for f:=1 to n do
    (FindComponent('sh'+IntToStr(f))).Free;
  Case RadioN.ItemIndex of
    0: n := 30;
    1: n := 80;
    2: n := 120;
  end;
  Case RadioSize.ItemIndex of
    0: Size := 6;
    1: Size := 10;
    2: Size := 14;
  end;  
  // Создание массива новых частиц
  FormGame.ButtonCreateClick(Sender);
  // Активизация игрового поля
  FormGame.PanelGame.Enabled := True;
  FormGame.PanelResult.Visible:= false;
  // Закрываем форму	
  Close;

end;

Листинг 7

Поясним код:

  • перед тем, как формировать новый игровой процесс, необходимо очистить память от динамически созданных компонентов методом Free (выделено жёлтым);
  • назначаем размер и количество частиц согласно положению переключателей — радиокнопок (выделено зелёным). Порядковый номер выбранного переключателя можно узнать через целочисленное свойство ItemIndex (нумерация начинается с нуля);
  • создаём массив новых частиц, исходя из выбранных параметров игрового процесса, вызвав процедуру ButtonCreateClick (кнопка «Создать»);
  • активируем игровое поле и убираем панель, отображающую результат игры;
  • закрываем форму.

6. Так как создание игрового мира происходит через кнопку «Начать игру» второй формы, то кнопка «Создание», находящаяся на главной форме, не нужна. Поставьте для неё значение свойства Visible = True . Единственную функцию, которую она будет выполнять — это быстрый доступ к коду создания массива частиц на этапе разработки приложения.

7. Теперь у нас готово полнофункциональное приложение! Запустите его. Нажмите на кнопку «Новая». В открывшемся окне выберите два понравившихся вам цвета и один из вариантов размера и количества частиц. Нажмите на кнопку «Начать игру» и играйте!

Повторное нажатие на кнопку «Новая», а потом «Начать игру» не приведёт к проблеме замусоривания памяти, т. к. перед созданием новой игры старые частицы удаляются.

 

 

3. Движущиеся частицы

1. Но как бы ни была хороша игрушка, её всегда можно сделать ещё лучше! Этим мы сейчас и займёмся. Добавим к нашим частицам элемент движения. Так, чтобы они случайным образом перемещались по игровому полю, не выходя за его границы. Для этого обработаем событие таймера OnTimer следующим образом:

procedure TFormGame.TimerTimer(Sender: TObject);
begin

  // В цикле случайным образом меняем координаты каждого компонента Shape 
  For f:=1 to n do
    with TShape(FindComponent('Sh'+IntToStr(f))) do begin  // Поиск компонента по его имени
      // Определяем новые координаты каждой частицы 
      Left := Left + random(5)-2;
      Top  := Top  + random(5)-2;
      // Проверяем выходы каждой частицы за границы игрового поля
      If Top  < 1 then Top  := 1;
      If Left < 1 then Left := 1;
      If Top  > panelGame.Height - Size then Top := panelGame.Height - Size;
      If Left > panelGame.Width  - Size then Left:= panelGame.Width  - Size;
  end; 

end;

 Листинг 8

Поясним код:

  • Задаём цикл поиска по имени.
  • Для упрощения работы был использован оператор with.  Упомянув в нём компонент всего один раз, мы можем обращаться к любому его свойству, методу или событию.
  • В теле оператора with, случайным образом меняем расположение компонентов Shape на игровом поле. Причём положение каждой из частиц меняется на величину от -2 до 2 по каждой из координат (выделено жёлтым). Это создаёт эффект броуновского движения частиц.
  • Чтобы частицы в процессе движения не вышли за границы игрового поля, их положение необходимо постоянно контролировать. Для этого введены четыре условия для каждой из границ поля. Частица, решившая выйти за границы, будет отталкиваться от них.

2. Запустите приложение. И… оно сразу же вызвало сообщение об ошибке (рисунок 4)! Говорит, что невозможен доступ к адресу памяти (Access violation at address). Почему?

image025
Рисунок 4

Да потому, что мы обращаемся к массиву объектов для изменения координат частиц, а при первом запуске приложения он ещё пуст. Как же быть? Да просто необходимо переписать строчки обработчика события OnCreate главной формы следующим образом (выделено жёлтым):

procedure TFormGame.FormCreate(Sender: TObject);
begin

  randomize;          // Активация генератора случайных чисел
  n:=0;               // Изначально число частиц в игре 
  Size:=0;            // Начальный размер частиц 
  colorFalse:=Clred;  // Цвет проигрыша
  colorTrue:=ClGreen; // Цвет выигрыша

end;

Листинг 9

 

Для чего мы так сделали? Дело в том, что цикл в таймере задаётся от 1 до n, и если мы n положим равным нулю, то цикл будет от 1 до 0. Тело такого цикла просто игнорируется. А начальный размер и число частиц для игрового процесса теперь не важны, т. к. всё равно они задаются в форме «Параметры новой игры».

Есть ещё один способ решения этой проблемы. При запуске приложения выключить таймер (Timer.Enabled := False). Включаться он должен только в момент начала игры, а после окончания снова выключаться.

3. Всё! Запустите уже полностью готовое приложение и играйте на здоровье.

4. Коротко о главном

  • События динамически созданных компонентов лучше связывать с одним аналогичным компонентом (на этапе RunTime невидимым), помещённым на форму. А через параметр Sender определять, от какого динамически созданного компонента пришло событие.
  • Для назначения динамически созданному компоненту события необходимо записать:
    <имя динамически созданного компонента>.<название события> := <имя существующей процедуры, которая реализует событие>;
  • Компонент ColorDialogimage018  (категория Dialog) представляет собой стандартный диалог по выбору пользователем цвета.

 

Выполнение заданий

Задания I уровня сложности

1. Модифицируйте созданное приложение так, чтобы можно было менять цвет фона игрового поля по аналогии с выбором «проигрышного» и «выигрышного» цветов.


2. Модифицируйте созданное приложение так, чтобы можно было менять количество частиц с помощью компонентов Edit и UpDown.


3. Модифицируйте созданное приложение так, чтобы частицы не отталкивались от границ игрового поля. Поле должно быть замкнуто по горизонтали и вертикали. Т. е., когда частица пропадает за какой-то стороной игровой области, то она появляется с другой его стороны.


4. Модифицируйте созданное приложение так, чтобы каждая частица имела свою скорость движения (от 0 до 6 пикселей за один «тик» таймера).
Подсказка: Скорость движения можно задать случайным образом через свойство Tag в момент создания частиц.


5. Модифицируйте созданное приложение так, чтобы частицы перемещались только по горизонтали слева направо. Причём, когда частица исчезает с правой стороны игрового поля, она появляется с левой его стороны (т. е. происходит зацикливание по горизонтали).


6. Создайте приложение с кнопкой «Пуск», при нажатии на которую форма заполняется десятью компонентами типа Panel с размерами 10х10 и случайными координатами. Компоненты не должны выходить за границы формы. Изначально цвет панели — зелёный. При щелчке кнопкой мыши по панели она окрашивается в красный цвет. При повторном щелчке она вновь становится зелёной.


 

7. Создайте приложение с кнопкой «Пуск», при нажатии на которую форма заполняется пятью компонентами типа Button с размерами 60х20 и случайными координатами. В заголовке каждой кнопки должна стоять цифра, определяющая порядковый номер компонента (т. е. каким по счёту он был создан). При нажатии на кнопку её заголовок изменяется на координаты этой кнопки (например, «104, 303»).


8. Создайте приложение с компонентом RadioGroup, в котором будут перечислены следующие названия: кнопка, метка и однострочный редактор. Если пользователь щёлкнет мышью по свободной форме, то в месте щелчка динамически создаётся тот компонент, который указан в списке. Заголовок появившегося компонента должен соответствовать общепринятым. Например: Button1, Button2, Edit1 и т. д.


9. Создайте приложение с кнопкой «Пуск», при нажатии на которую динамически создаётся пять форм, вложенных в главную (как матрёшки). Центр всех создаваемых форм совпадает с центром главной формы. В заголовке форм отображается их порядковый номер. Примерный внешний вид приложения приведен на рисунке:

image027

Примечание: Для отображения формы необходимо применить уже известный нам метод Show, вместо свойства Parent.

 

Задания II уровня сложности

1. Создайте игру, аналогичную той, что вы делали в упражнении. Только игровым полем будет весь экран, а частицами будут компоненты Form без строки заголовка (свойство BorderStyle = bsNone). Примерный результат приведён на рисунке:

image029

Примечание: Ширину и высоту экрана можно узнать через специальный класс TScreen (Screen.Width и Screen.Height).