Программная обработка перемещения объекта

Расположите на форме компонент и задайте его свойство AutoSize=true. Дополнительно вам понадобятся несколько новых переменных, которые лучше объявить в разделе private.

Move:Boolean; //Режим перетаскивания

X0,y0:integer; //Начальные координаты мыши

Теперь настраиваем начальное нажатие мыши

Procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

Begin

If Button<>mbLeft then exit; // Если нажата не левая кнопка мыши, то и делать ничего не надо

X0:=X;

Y0:=Y;

Image1.Canvas.DrawFocusRect(Rect(X-5,Y-5,X+5,Y+5)); {рисование рамки}

Move:=true; {включение флажка режима перемещения рамки}

End;

Обрабатываем процесс перетаскивания

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);

begin

if not Move then exit; //Ничего не делать, если перетаскивание не включено

Image1.Canvas.DrawFocusRect(Rect(X0-5,Y0-5,X0+5,Y0+5)); {стирание рамки}

Image1.Canvas.DrawFocusRect(Rect(X-5,Y-5,X+5,Y+5)); {рисование рамки}

X0:=X; {запоминание координат курсора}

Y0:=Y;

end;

Последний этап – выключить процесс перетаскивания при отпускании клавиши мыши.

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,Y: Integer);

begin

if not drag then exit;

Image1.Canvas.DrawFocusRect(Rect(X0-5,Y0-5,X0+5,Y0+5)); {стирание рамки}

Move:=false; {выключение флажка режима перемещения рамки}

end;

При нажатии кнопки мыши рисуется первая рамка, запоминаются координаты курсора, и включается режим перемещения рамки (переменная drag = true). При перемещении мыши в режиме перемещения рамки стирается прежняя рамка, рисуется рамка в новой позиции, и запоминаются новые координаты курсора. При отпускании кнопки мыши стирается рамка и выключается режим перемещения рамки.

Лабораторная работа по перетаскиванию объектов №15.

1. Создайте новый проект «Пазлы» и сохраните форму проекта с именем PazlForm.pas, и сам проект Pazly в отведенную для них папку.

2. Наш проект состоит из следующих этапов:

a. Размещение рисунка на форме.

b. Разбивка рисунка на отдельные части, которые возможно перемещать по форме.

3. Для того чтобы разместить на форме рисунок, создадим виртуальный компонент BitMap, используем его свойства, а при разрушении формы разрушим и сам компонент. Такой подход необходим для того, чтобы иметь возможность восстанавливать часть рисунка, перекрытую другими Фомами.

a. Скопируйте в папку с проектом рисунок формата bmp. В дальнейшем в программе вы будете использовать его имя. В нашем примере – это g18.bmp

b. Объявите в разделе private

BitMap:TBitMap;

FileName: String;

c. Теперь создадим обработчик событий для события OnCreate - создание формы

procedure TForm1.FormCreate(Sender: TObject);

begin

FileName:='g18.bmp'; //Задаем имя файла рисунка

BitMap:=TBitMap.Create; //Создаем компонент

try //Если файл существует, то

BitMap.LoadFromFile(FileName); //Перерисовываем его в компонент BitMap

Canvas.Draw(0,0,BitMap); // Размещаем рисунок от левого верхнего угла

Width:=BitMap.Width*2; //Корректируем ширину формы

Height:=BitMap. Height* 3 div 2; //И высоту

finally //Если такого файла нет, то ничего не делаем.

end; {try}

end;

d. Если компонент был создан, то он должен быть разрушен, иначе приложение вызовет зависание вашей машины. Поэтому в процедуру для события OnDestroy( разрушение формы) пишем следующую строчку.

procedure TForm1.FormDestroy(Sender: TObject);

var i,j:integer;

begin

Bitmap. Free ; //Разрушить компонент BitMap

end;

e. Сохраните и запустите проект. Теперь, не закрывая проект, перейдите в окно Delphi, а затем обратно. Рисунок с вашей формы исчезнет. Что бы этого не происходило нужно настроить событие формы OnPaint.

procedure TForm1.FormPaint(Sender: TObject);

begin

if BitMap<>nil then // Если рисунок существует, то восстановить стертый кусок

canvas.CopyRect(canvas.ClipRect ,BitMap.Canvas ,canvas.ClipRect );

end;

f. Вот теперь сохраните и запустите проект еще раз. Рисунок с формы исчезать не будет.

4. Теперь научимся разбивать рисунок на несколько кусочков. Сначала поместим рисунок в еще один виртуальный компонент типа TImage, из которого потом скопируем кусочки в массив компонентов типа TImage. Как и в проекте «Сапер», мы с самого начала зададим переменное количество пазлов.

a. Разместите на форме компонент таймер.

b. Опишите в разделе private следующие переменные

Pict:TImage; //Первоначальное размещение рисунка

Picti,n:Byte; // Разрезать – не разрезать

Paz:array [1..10,1..10] of TImage; // Пазлы

c. В процедуру создания формы FormCreate добавьте строчку Picti:=0;

d. Для таймера предусмотрите следующую процедуру

procedure TForm1.Timer1Timer(Sender: TObject);

var i,j,w,h:integer; //Номер строки, столбца, ширина и высота пазла

vs:real;

begin

if Picti>0 then exit; //Если разрезка уже сделана, то выходим из процедуры

Picti:=1; // Запоминаем, что разрезка уже делалась

Pict:=TImage.Create(Self); //Создаем компонент под целый рисунок

Pict.Picture.LoadFromFile(FileName); //Заполняем компонент рисунком

n:=StrToInt( InputBox('Пазлы', 'Уровень разбивки', '3')); //Запрашиваем уровень разбивки

w:= Pict.Width div n; //Высчитываем ширину пазла

h:=Pict.Height div n; //Высчитываем высоты пазла

BitMap:=nil; //Убираем рисунок с формы

canvas.Refresh ; //Перерисовываем форму

for i:=1 to n do

for j:=1 to n do begin

Paz[i,j]:=TImage.Create(Self); //Создаем пазлы

Paz[i,j].Parent :=self; //Приписываем их к форме

Paz[i,j].Height:=h; //Задаем высоту пазла

Paz[i,j].Width := w ; //Ширину пазла

Paz[i,j].Canvas.CopyRect(Paz[i,j].ClientRect,Pict.Canvas, Rect(w *(i-1),(j-1)*h,w * i, j*h)) ; //Размещаем на пазле кусок рисунка из компонента Pict, указав координаты верхнего левого и нижнего правого углов кусочка.

Paz[i,j].Visible :=true; //Делаем пазл видимым

Paz[i,j].Left := w *(i-1); //Размещаем пазлы по порядку

Paz[i,j].Top:=(j-1)*h ;

Paz[i,j].DragKind :=dkDock; //Определяем компонент, как для встраивания. Тоже свойство = dkDrag компонент для обычного перетаскивания.

Paz[i,j].DragMode :=dmAutomatic; //Разрешить перетаскивание без программного кода

Paz[i,j].ManualFloat(Rect(Left+Paz[i,j].Left , Top+Paz[i,j].Top,Left+Paz[i,j].Left+w, Top+Paz[i,j].Top+h)); // Переводит кусок в плавающий режим

Paz[i,j].ManualDock(Form1,nil,alleft); // Разрешить извлечь кусок с формы

end; {for}

Randomize; {Размещаем пазлы случайным образом}

for i:=1 to n do for j:=1 to n do begin

Paz[i,j].Left := random(Width-w);

Paz[i,j].Top:=random(Height - h) ;

end;

Pict.Free; //Разрушаем контейнер с рисунком

end;

e. Сохраните и запустите проект. Теперь можно и поиграть.

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

6. Настройте в программе выбор рисунка с помощью компонента OpenDialog, если исходный рисунок не был найден.

Лабораторная работа. №16

1. Возьмем за основу проект «Пазлы» прошлого урока. К сожалению, автоматическое перетаскивание объектов обладает своими недостатками. Мы не можем проверить правильность размещения компонентов, у которых в добавок при перетаскивании образуется рамка.

2. Перепишем обработчик для таймера.

procedure TForm1.Timer1Timer(Sender: TObject);

var i,j:integer;

vs:real;

begin

if Picti>0 then exit; //Если разбивка произошла, то выходим

Picti:=1;

Pict:=TImage.Create(Self); //Создаем контейнер для рисунка

Pict.AutoSize :=true;

Pict.Picture.LoadFromFile(FileName);

n:=StrToInt( InputBox('Пазлы', 'Уровень разбивки', '3'));

w:= Pict.Width div n; //ширина пазла

h:=Pict.Height div n; //Высота пазла

BitMap:=nil;

canvas.Refresh ; //Очищаем канву

for i:=1 to n do begin

for j:=1 to n do begin

Paz[i,j]:=TImage.Create(Self); //Создаем пазл

with Paz[i,j] do begin

Parent :=self; //Приписываем к форме

Height:=h; //Задаем высоту

Width := w ; //Задаем ширину

Canvas.CopyRect(Paz[i,j].ClientRect,Pict.Canvas, Rect(w *(j-1),(i-1)*h,w * j, i*h)) ;//Заполняем рисунком

Visible :=true; //Делаем видимым

Left := w *(i-1); //Расставляем правильно

Top:=(j-1)*h ;

AutoSize :=true; //Даем возможность дальнейшего перемещения компонента

{OnMouseDown:=Image1MouseDown;

OnMouseMove:=Image1MouseMove;

OnMouseUp:=Image1MouseUp;} //позже мы напишем эти процедуры

end;

end;

end;

Randomize; //Расставляем в случайном порядке

for i:=1 to n do begin

for j:=1 to n do begin

Paz[i,j].Left := random(Width-w*3 div 2);

Paz[i,j].Top:=random(Height - h*3 div 2) ;

end;

end;

Pict.Free;

end;

3. Разместите на форме компонент Image1 и напишите для него следующие процедуры:

4. Для события OnMouseDown – начало перетаскивания

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

if button<>mbLeft then exit;

x0:=x;

y0:=y;

move:=true;

rec:=(sender as TControl).BoundsRect ;

end;

переменные x0 и y0 опишите в разделе private, как целые числа, move:Boolean, rec:TRect.

5. Для процесса перетаскивания OnMouseMove

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,

Y: Integer);

begin

if not move then exit;

Canvas.DrawFocusRect(rec);

with rec do begin

left:= Left+x-x0;

Right:=Right+x-x0;

Top:=top+y-y0;

bottom:=bottom+y-y0;

x0:=x;

y0:=y;

end;

Canvas.DrawFocusRect(rec);

end;

6. Для окончания перетаскивания OnMouseUp

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

var l,t:integer;

begin

Canvas.DrawFocusRect(rec);

with (Sender as TControl) do begin

l:=(rec.Left +x-x0) div w * w;

t:=(rec.Top +y-y0)div h *h;

SetBounds(l,t,Width,Height);

BringToFront;

end;

move:=false;

end;

7. Сохраните и запустите проект. Ничего не происходит. Мы забыли определить выполнение этих функций для каждого пазла. Уберите фигурные скобки в обработчике события для таймера. Теперь компонент Image1 нам больше не нужен, и его можно удалить. Еще раз сохраните и запустите проект.

8. Перед вами готовая игрушка с пазлами. Осталось научить ее определять, когда же игрок заканчивает свою игру. Для этого вам понадобиться новая функция

function TForm1.analiz:boolean;

var i,j:integer;

begin

Result:=false;

for i:=1 to n do

for j:=1 to n do begin

if abs((Paz[i,j].Left-Paz[1,1].Left) - (j-1)*w)>1 then exit;

if abs((Paz[i,j].Top-Paz[1,1].Top) - (i-1)*h)>1 then exit;

end;

result:=true;

end;

Не забудьте описать ее. Теперь в предпоследнюю строчку процедуры TForm1.Image1MouseUp вставьте строчку

if analiz then ShowMessage('С днем святого Валентина!');

Если картинка подобрана правильно, то у вас получиться хороший подарок ко дню святого Валентина.