Буксировку компонентов будем рассматривать на примере перемещения компонентов 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 с данным кодом.
На главную подраздела о буксировке