Программная обработка перемещения объекта
Расположите на форме компонент и задайте его свойство 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('С днем святого Валентина!');
Если картинка подобрана правильно, то у вас получиться хороший подарок ко дню святого Валентина.