Буксировку компонентов будем рассматривать на примере перемещения компонентов TImage. Для рассмотрения методов буксировки компонент, достаточно поместить на форму два компонента TImage и создать рисунок приемлемого размера, поместив его в директорию, где создан проект (по умолчанию Projects), например ris.bmp.
Создаем новый проект. Определяем глобально:
int viX0,viY0; bool fMove;
Помещаем на форму два элемента TImage и готовим в директории Projects рисунок ris.bmp.
В обработчике события OnCreate(два левых клика на форме) пишем код:
void __fastcall
TForm1::FormCreate(TObject *Sender)
{
//Создаем изображение и загружаем
TImage * Pict = new TImage(Form1);
Pict->AutoSize = true;
Pict->Picture->LoadFromFile("ris.bmp");
//Размеры рисунка
Image1->Width=Pict->Width/2;
Image2->Width=Image1->Width;
Image1->Height=Pict->Height;
Image2->Height=Pict->Height;
//Копирование из Pict->Canvas в Image1->ClientRect
//прямоугольника верх/лево/ширина/высота
Image1->Canvas->CopyRect(Image1->ClientRect, Pict->Canvas,
Rect(0,0,Pict->Width / 2,Pict->Height));
Image2->Canvas->CopyRect(Image2->ClientRect, Pict->Canvas,
Rect(Pict->Width / 2,0,Pict->Width,Pict->Height));
delete Pict;
}
В каждом TImage сейчас по половинке изображения - будем их перемещать. Для этого для Image1 создадим три обработчика событий мышки: OnMouseDown, OnMoeseMove и OnMouseUp (два клика на соответствующем окошечке в Events инспектора объектов). Для Image2 перенаправим эти события на Image1, для чего в соответствующем окошечке в Events инспектора объектов для Image2 выберем события для Image1. И напишем коды обработчиков.
void __fastcall
TForm1::Image1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if(Button != mbLeft) return;
//Запомнить где
viX0 = X;
viY0 = Y;
//Будем тащить
fMove = true;
//Переместить на передний план эту половинку
((TControl *)Sender)->BringToFront();
}
// Д В И Г А Е М
void __fastcall
TForm1::Image1MouseMove(TObject *Sender,
TShiftState Shift,int X, int Y)
{
if(fMove)
{
//Установить новые границы для того на кого нажали
((TImage *)Sender)->
SetBounds(
((TImage *)Sender)->Left + X - viX0,
((TImage *)Sender)->Top + Y - viY0,
((TImage *)Sender)->Width,
((TImage *)Sender)->Height);
}
}
// О С Т А Н А В Л И В А Е М С Я
void __fastcall
TForm1::Image1MouseUp(TObject *Sender,
TMouseButton Button,
TShiftState Shift, int X, int Y)
{
fMove = false;
}
Теперь при протаскивании курсора по форме при нажатой левой кнопочки мышки над любым изображением половинка изображения начинает двигаться.
Однако сразу виден и недостаток - изображение мелькает при перетаскивании. Для того чтобы исключить этот недостаток можно использовать метод буксировки контура.
Можно создать новый проект или модифицировать предыдущий, но лучше с нуля. Итак - создаем новый проект.
Определяем глобально:
int viX0,viY0; bool fMove; TRect tRec; //Здесь будут координаты контура
Помещаем на форму два элемента TImage и готовим в директории Projects любой рисунок в формате .bmp.
В обработчике события OnCreat(два левых клика на форме) пишем код:
//Для создания формы аналог с методом перерисовки
void __fastcall
TForm1::FormCreate(TObject *Sender)
{
//Создаем изображение и загружаем
TImage * Pict = new TImage(Form1);
Pict->AutoSize = true;
Pict->Picture->LoadFromFile("ris.bmp");
//Размеры рисунка
Image1->Width=Pict->Width/2;
Image2->Width=Image1->Width;
Image1->Height=Pict->Height;
Image2->Height=Pict->Height;
//Копирование из Pict->Canvas в Image1->ClientRect
//прямоугольника верх/лево/ширина/высота
Image1->Canvas->CopyRect(Image1->ClientRect, Pict->Canvas,
Rect(0,0,Pict->Width / 2,Pict->Height));
Image2->Canvas->CopyRect(Image2->ClientRect, Pict->Canvas,
Rect(Pict->Width / 2,0,Pict->Width,Pict->Height));
delete Pict;
}
В каждом TImage сейчас по половинке изображения - будем их соединять. Для этого для Image1 создадим три обработчика собы- тий мышки OnMouseDown, OnMoeseMove и OnMouseUp (два клика на соответствующем окошечке в Events инспектора объектов). Для Image2 перенаправим эти события на Image1, для чего в соответствующем окошечке в Events инспектора объектов для Image2 выберем события для Image1. И напишем коды обработчиков.
//Для нажатия аналог с методом перерисовки кроме одной строчки
//tRec = ((TControl *)Sender)->BoundsRect;
void __fastcall
TForm1::Image1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if(Button != mbLeft) return;
//Запомнить где
viX0 = X;
viY0 = Y;
//Будем тащить
fMove = true;
//Запоминаем границы
tRec = ((TControl *)Sender)->BoundsRect;
//Переместить на передний план эту половинку
((TControl *)Sender)->BringToFront();
}
// Д В И Г А Е М, НО НЕ ИЗОБРАЖЕНИЕ, А
// ТОЛЬКО КОНТУР ИЗОБРАЖЕНИЯ
void __fastcall
TForm1::Image1MouseMove(TObject *Sender,
TShiftState Shift,int X, int Y)
{
//Установить новые границы для контура
if(fMove)
{
Canvas->DrawFocusRect(tRec);
tRec.left += X - viX0;
tRec.right += X - viX0;
tRec.top += Y - viY0;
tRec.bottom += Y - viY0;
viX0 = X;
viY0 = Y;
Canvas->DrawFocusRect(tRec);
}
}
// О С Т А Н А В Л И В А Е М С Я
void __fastcall
TForm1::Image1MouseUp(TObject *Sender,
TMouseButton Button,
TShiftState Shift, int X, int Y)
{
if(!fMove) return;
//Стирание последнего изображения контура методом OR
Canvas->DrawFocusRect(tRec);
//Если не передумали (не нажали Alt)
if(!Shift.Contains(ssAlt))
{
//Рисуем
((TControl *)Sender)->
SetBounds(
tRec.Left + X - viX0,
tRec.Top + Y - viY0,
((TControl *)Sender)->Width,
((TControl *)Sender)->Height
);
((TControl *)Sender)->BringToFront();
}
fMove = false;
}
Все хорощо, и изображение не мелькает при перетаскивании, но много кода. Чтобы было меньше - можно использовать метод буксировки с использованием встроенных механизмов Drag&Dock.
Как и в предыдущем параграфе можно создать новый проект или модифицировать предыдущий, но лучше опять начнем с нуля. Итак - создаем новый проект.
Помещаем на форму два элемента TImage и готовим в директории Projects любой рисунок в формате .bmp.
Для формы устанавливаем свойство DockSite=true; - в рузудьтате форма стала контейнером, способным принимать переносимые в этот контейнер компоненты. Свойство Use Dock Manager=false иначе приемом компонент будет управлять диспетчер, а он перетаскиваемому компоненту будет выделять пол окна.
Для Image1 и Image2 устанавливаем свойства DragKind=dkDoc; и DragMode=dmAutomatik;
В обработчике события OnCreat (два левых клика на форме) пишем код в котором функция ManualFloat переводит компонент в режим плавающего окна, а ManualDock размещает компонент в указанном приемнике.
void __fastcall
TForm1::FormCreate(TObject *Sender)
{
//Создаем изображение и загружаем
TImage * Pict = new TImage(Form1);
Pict->AutoSize = true;
Pict->Picture->LoadFromFile("ris.bmp");
//Размеры рисунка
Image1->Width=Pict->Width/2;
Image2->Width=Image1->Width;
Image1->Height=Pict->Height;
Image2->Height=Pict->Height;
//Копирование из Pict->Canvas в Image1->ClientRect
//прямоугольника верх/лево/ширина/высота
Image1->Canvas->CopyRect(Image1->ClientRect, Pict->Canvas,
Rect(0,0,Pict->Width / 2,Pict->Height));
Image2->Canvas->CopyRect(Image2->ClientRect, Pict->Canvas,
Rect(Pict->Width / 2,0,Pict->Width,Pict->Height));
delete Pict;
Image1->ManualFloat(Rect(
Form1->Left+Image1->Left,
Form1->Top+Image1->Top,
Form1->Left+Image1->Left+Image1->Width,
Form1->Top+Image1->Top+Image1->Height
)
);
Image1->ManualDock(Form1,NULL,alLeft);
Image2->ManualFloat(Rect(
Form1->Left+Image2->Left,
Form1->Top+Image2->Top,
Form1->Left+Image2->Left+Image2->Width,
Form1->Top+Image2->Top+Image2->Height
)
);
Image2->ManualDock(Form1,NULL,alLeft);
}
Компоненты хорошо двигаются и не мельтешат при перетаскивании.
Рассмотрим код:
void __fastcall
TForm1::Button1MouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{
const int SC_DRAGMOVE=61458;//0xF012;
ReleaseCapture();
((TControl *)Sender)->Perform(WM_SYSCOMMAND,SC_DRAGMOVE,0);
}
Здесь освобождается курсор мыши и методом Perform посылается источнику события
сообщение о буксировке. Таким образом можно таскать многие элементы - в том числе
и саму форму за любой элемент - достаточно создать для них обработчик события
OnMouseMove с данным кодом.
На главную подраздела о буксировке