Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Перемещение картинки мышкой


Автор: ALeXandrK 11.8.2007, 00:44
Решается избитая задача - передвижение картинки мышкой.
Т.е. кликаем на картинку (TImage) и начинаем её тоскать по форме... где курсор, там и картинка.

Но есть проблема: если курсор передвинуть очень быстро, то он выйдет за пределы картинки 
(если картинка маленькая). Идеальный вариант - это рисовать картинку вместо курсора, но сами
знаете, что нелюбую картинку можно поставить курсором.

Как быть, кто знает??? smile 

P.s.: У меня в программе есть TStringGrid, а его ячейки я рисую сам (цвет, текст). 
Я пытаюсь реализовать перетаскивание ячеек следующим образом: 
  • Кликаем на ячейку
  • Создаем TImage
  • Rect ячейки копирую в TImage
  • TImage двигаю куда нужно
  • ну и копирую Rect из TImage в нужную ячейку
Я бы рат не прорисовывать ничего, а просто вид курсора поменять, но пользователь должен точно знать что он тащит.


P.p.s.:
Метод перетаскивания картинки:
В методе OnMouseMove:

Код

SetBounds(Left+X-Width div 2,Top+Y-Height div 2,Width,height);

Автор: Sanchezzz 11.8.2007, 01:40
не знаю устроит тебе такой код  но работает четко и без мерцаний 

Код

implementation var
imgflag:boolean;
x0,y0:integer;
{$R *.dfm}


procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if button <> mbLeft then
    imgflag := false
  else
  begin
    imgflag := true;
    x0 := x;
    y0 := y
  end
end;


procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
 begin
if imgflag=true then
  begin
(Sender as TImage).SetBounds((Sender as TImage).Left + x - x0
{div 2 тогда прикольное сочитание получится}, (Sender as TImage).Top + y - y0
{div 2 тогда прикольное сочетание получится}
, (Sender as TImage).width, (Sender as TImage).height);
end;
 end;

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
imgflag:=false;
end;

Автор: MetalFan 11.8.2007, 09:19
Цитата(Sanchezzz @  11.8.2007,  01:40 Найти цитируемый пост)
implementation var
imgflag:boolean;
x0,y0:integer;

глобальные переменные - зло! тем более тогда, когда можно и без них обойтись

Автор: ALeXandrK 11.8.2007, 11:38
СТОП!
Мерцаний у меня нет! Я от них избавляюсь 
Код

DoubleBuffer:=true;


Вопрос совершенно в другом:
Если резко дернуть курсор, то он убежит с картинки, а он должен оставаться всегда на середине компонента!

Глобальных переменных у меня тоже нет smile 

Само передвижение у меня прекрасно работает!

P.s.:
Sanchezzz: я примерно таким кодом все и двигаю, только глобальных переменных у меня нет smile 

Автор: Sunvas 11.8.2007, 13:11
Цитата(ALeXandrK @  11.8.2007,  11:38 Найти цитируемый пост)
Если резко дернуть курсор, то он убежит с картинки, а он должен оставаться всегда на середине компонента!

Ты что-то не так делаешь значит. Правильнее всего перемещать картинку - это обрабатывать ее OnMouseMove. Если уж ты "взял" картинку и не "отспускаешь" ее, то где бы не находился курсор (даже за пределами картинки) все равно будет выполняться событие OnMouseMove!


Цитата(MetalFan @  11.8.2007,  09:19 Найти цитируемый пост)
глобальные переменные - зло! тем более тогда, когда можно и без них обойтись

Ммм. Интересно, как ты предлагаешь лучше всего обойтись без глобальных переменных? Ведь все-равно, обрабатывая OnMouseMove, мы должны знать нажата ли левая кнопка в момент перетаскивания.

Автор: ALeXandrK 11.8.2007, 13:16
У меня наследник от TImage. А код передвижения я сразу реализовал в наследнике.
Так что роль глобальной переменной играет сам созданный экземпляр класса.

Условия при движении я не проверяю. Компонент создан, значит двигаем.

Автор: Sunvas 11.8.2007, 13:25
Цитата(ALeXandrK @  11.8.2007,  13:16 Найти цитируемый пост)
 Компонент создан, значит двигаем.

В том-то и проблема.. Если бы ты обрабатывал OnMouseMove после OnMouseDown - за тебя Windows решила бы твою проблему... А в твоем случае решить проблемму удобно невозможно, разве что таймер поможет.

Автор: ALeXandrK 11.8.2007, 13:40
Цитата

В том-то и проблема.. Если бы ты обрабатывал OnMouseMove после OnMouseDown - за тебя Windows решила бы твою проблему... А в твоем случае решить проблемму удобно невозможно, разве что таймер поможет.

Ну вот. Уже хорошо.

Значит мне нужно каким-то образом вызвать OnMouseDown;
Но как? Если у меня картинка создается при событии OnMouseUp грида.

Прикрепил пример того, что я делаю.

Автор: Sunvas 11.8.2007, 15:10
Цитата(ALeXandrK @  11.8.2007,  13:40 Найти цитируемый пост)
Значит мне нужно каким-то образом вызвать OnMouseDown;Но как? Если у меня картинка создается при событии OnMouseUp грида.

Попробуй просто послать это сообщение вручную.

Автор: ALeXandrK 11.8.2007, 15:18
Написал вот это:
Код

...
        h := FindWindowEx(Handle, 0, 'TStringGrid', NIL);
        SendMessage(h, WM_MOUSELEAVE, 1, 0);
        h := FindWindowEx(h, 0, 'TMovingCell', NIL);
        SendMessage(h, WM_ACTIVATE, 1, 0);
        SendMessage(h, WM_LBUTTONDOWN, 1, 0);
...


Не помогло.

Автор: Snowy 11.8.2007, 15:39
А так не пойдёт?
Сделал через фрейм - не люблю компоненты...

Добавлено через 6 минут и 30 секунд
Если очень нужно, чтобы курсор был именно посередине, то поправить кусочек в Unit2 так:
Код
procedure TFrame2.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  BringToFront;
  Left := Left + X - Image1.Width div 2;
  Top := Top + Y - Image1.Width div 2;
  ReleaseCapture;
  Perform(WM_SYSCOMMAND, $F012, 0);
end;

Автор: ALeXandrK 11.8.2007, 16:26
Snowy: Интересное решение, но оно мне все-таки не подходит.

Автор: ALeXandrK 11.8.2007, 18:30
УРА!!! Нашел решение. 
Спасибо всем. Каждый хоть немного, но помог!

Нужны были всего лишь две строчки:
Код

ReleaseCapture;
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);


Т.к. курсор я ставлю посередине при создании картинки, то это событие просто
вызывает левый клик мыши и все идет как нужно smile 

Прикрепляю рабочий пример:

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)