Технология Drag-and-Drop Реализации Drag&DropвVcl
Drag&Drop («перетащи и положи») – это один из способов обмена данными между приложениями. Этим способом обмена пользуются многие программные приложения. Например, очень часто так перемещаются файлы и папки.
В библиотеке визуальных компонент - VCL реализована собственная версия Drag&Drop – технологии, которая обеспечивает прием и передачу любых управляющих элементов внутри одной и той же формы. При таком внутреннем использовании VCL не обращается к операционной системе, хотя для организации общения различных приложений нужно было бы использовать соответствующие функции API Windows.
Пользователь, нажав на левую кнопку мыши, может перетащить управляющий элемент (объект – источник) на другой элемент (объект-приемник). В моменты перетаскивания и отпускания генерируются события, которые должна обрабатывать программа (получателем событий является элемент, над которым находится курсор мыши). Свойство компонентов DragModeотвечает за их участие в процессе обмена данными.
DragMode = dmAutomatic - события срабатывают автоматически, программист пишет только коды, соответствующих обработчиков событий.
DragMode = dmManual -все вызовы программист должен организовать сам.
События, возникающие при перетаскивании
Событие OnDragOverвозникает во время перемещения курсора мыши над объектом-приемником, а также при отпускании кнопки на этом объекте.
Параметры события:
Sender- объект-приемник (над ним находится курсор);
Source - объект-источник;
X,Y- координаты мыши в системе клиентской области объекта Sender;
State- состояние (имеет одно из трех значенийdsDragEnter– курсор мыши появился над элементом;dsDragMoveкурсор перемещается над элементом;dsDragLeave– курсор ушел с элемента или над элементом была отпущена кнопка).
Accept– логическая переменная. В этой переменной обработчик должен вернуть свое решение принимать или не принимать объектSource.
Например, компонент класса Label(Name=Label1)должен принимать только компоненты классаShape(геометрические фигуры), тогда его обработчик будет содержать проверку переносимого объекта-источника(Source):
void __fastcall TForm1::Label1DragOver(TObject *Sender, TObject *Source,
int X, int Y, TDragState State, bool &Accept)
{
Accept=Source->ClassNameIs("TShape");
}
Событие OnDragDropвозникает при отпускании левой кнопки мыши над элементом, готовым к приему. Его параметрыSender,Source,XиYимеют тот же смысл, что и у предыдущего события. Содержимое этого обработчика зависит от того, какие функции программист разрешает выполнять пользователю путем перетаскивания. Это может быть изменение местоположения объектов, обмен информацией и т.д.
В следующем примере не происходит физического перемещения объектов; компонент Label1 получает указатель на перемещенный объект (геометрическая фигура) и считывает значения свойств (Height, Width) для вычисления периметра фигуры. Результат вычислений размещается в Label1 -> Caption.
void __fastcall TForm1::Label1DragDrop(TObject *Sender,
TObject *Source, int X, int Y)
{
float p, pi=3.14; int w, h, r, D;
if (String(Source->ClassName())=="TShape")
{
h=((TShape *)Source)->Height;
w= ((TShape *)Source)->Width ;
D = w; if ( D > h ) D = h;
switch ((( TShape *)Source) -> Shape)
{ case stRectangle:
Label2->Caption ="Прямоугольник";
p= 2*(w + h);
break;
case stSquare:
Label2->Caption = "Квадрат";
p= 4*D;
break;
case stCircle:
Label2->Caption = "Круг";
p= pi*D;
break;
case stEllipse:
Label2->Caption = "Эллипс";
p=pi*(3*(w+h)/4-sqrt(w*h)/2);
break;
case stRoundRect:
Label2->Caption = "Закругленный
прямоугольник";
r=(D-((TShape*)Source)->Pen->
Width +1)/4;
p=2*(w+h)-8*r+2*pi*r;
break;
case stRoundSquare:
Label2->Caption="Закругленный
квадрат";
r=(D-((TShape*)Source)->Pen->
Width+1)/4;
p=4*D-8*r+2*pi*r;
break;
}
p=p/(Form1->PixelsPerInch/2.54);
Label1->Caption = FloatToStr (p);
}
}
При завершении процесса перетаскивания вне зависимости от его результата исходный объект получает событие OnEndDrag. Его параметры:
Sender– указатель объекта - источника;
Target– указатель объекта - приемника;
X, Y– координаты курсора.
В следующем примере переносимый компонент Shape1 узнает имя объекта - приемника (если объект не принят передается NULL):
void __fastcall TForm1::Shape1EndDrag(TObject *Sender, TObject *Target,
int X, int Y)
{
if (Target != NULL)
Label2->Caption =(AnsiString) (( TComponent *) Target)->Name;
}