Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 15.11.2014, 22:12   #1
exyl
Пользователь
 
Регистрация: 15.11.2014
Сообщений: 75
По умолчанию Плавное перетаскивание TImage большого размера

Здравствуйте.

Задача заключается в том, чтобы плавно перетаскивать достаточно большую (2000*2000 пикселей) картинку в jpg формате при зажатии ЛКМ средствами Делфи 2007.

Смысл: есть вкладки (реализованные через TPanel, а не через пэйдж контрол, что не есть тру, но на это есть свои веские причины и щас не об этом). На одной из TPanel лежит TImage, в него загружена крупная картинка (конкретно, план местности). Нужно организовать работу с этим планом (перетаскивание с зажатой ЛКМ и масштабирование колесиком мыши).

Как я стал решать. Таскать по ОнМаусМув напрямую смысла нет - будет мерцать даже с ДаублБуфферед. Так что кинул на панель СкроллБокс, выставил выравнивание alClient, скроллбары в False (они не должны быть видны), свойство Smooth в тру и уже на него перекинул TImage. Далее записал в обработчик OnMouseMove на картинке:

Код:
procedure TForm1.imgAppMapsMouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
begin
  if ssLeft in Shift then
    ScrollBox_appMaps.ScrollBy(X, Y);
end;
Перетаскивается плавно, это гуд, но, естесстно, проблема в том, какие координаты сообщать СкроллБаю. Потому что в таком виде нельзя взяться за середину картинки - при подобной попытке картинку привяжет к курсору левым верхним углом, а надо привязать картинку к курсору той точкой, за которую пользователь взялся.

С удовольствием воспользуюсь вашими советами и отвечу на все вопросы. Проект не выкладываю, т.к. он достаточно крупный и с кучей графики.
exyl вне форума Ответить с цитированием
Старый 15.11.2014, 23:07   #2
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Когда-то я решил это так: http://www.programmersforum.ru/showthread.php?t=104883
У меня были в КБ чертежи формата А4-А0, а это огромные простыни.
Так что рекомендую выкинуть Image в пользу другого.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 15.11.2014, 23:10   #3
Vapaamies
Просветитель
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,844
По умолчанию

Мне кажется, что нужно сохранять предыдущую позицию и передавать разность между ними.
В разработке: воспроизводственный контур ИТ
Vapaamies вне форума Ответить с цитированием
Старый 15.11.2014, 23:27   #4
exyl
Пользователь
 
Регистрация: 15.11.2014
Сообщений: 75
По умолчанию

Ну я так и подумал, что TImage в моем случае похож на слона в посудной лавке: громоздкий, неуклюжий и ничо с ним быстро и просто не сделаешь.
Хорошо, выкину, хотя теплилась надежда сделать все максимально просто, быстро и без доп. компонентов.

Задача, на самом деле, немного шире. На плане в некоторых местах нужно будет накладывать небольшие картиночки-маркеры (максимум, 128*128 пикселей) и желательно в пнг. Изначально Делфи 2007 с этим форматом работать не умеет, но когда-то давно я уже ставил компонент, благодаря которому появлялась возможность работать с альфа-каналом, так что не вопрос.

А план будет один-единственный и будет забит в прогу изначально, поэтому быстрая загрузка изображений мне не нужна.

Нужны всего несколько вещей:
- плавное перетаскивание по зажатию ЛКМ;
- плавное зуммирование по колесику мыши;
- отрисовка специальных маркеров (желательно отдельным слоем, чтоб при зуммировании они не меняли своего размера, но это не критично).

Vapaamies,
Правильно, но тогда не будет двигаться картинка во время ОнМаусМув. Она будет отрисовываться только, когда отпускается клавиша, а мне нужно картинку привязать к курсору.
exyl вне форума Ответить с цитированием
Старый 16.11.2014, 00:00   #5
Vapaamies
Просветитель
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,844
По умолчанию

Цитата:
Сообщение от exyl Посмотреть сообщение
Правильно, но тогда не будет двигаться картинка во время ОнМаусМув.
Нужно сохранять те X и Y, которые передаются в обработчик. Суть в том, что ScrollBy хочет дельты смещения, а в обработчик поступают точечные координаты. Чтобы получить смещение, нужно провести линию между двумя точками во времени и пространстве, для чего значение предыдущей точки нужно сохранить.
В разработке: воспроизводственный контур ИТ
Vapaamies вне форума Ответить с цитированием
Старый 16.11.2014, 02:08   #6
exyl
Пользователь
 
Регистрация: 15.11.2014
Сообщений: 75
По умолчанию

Решение нашел, все умещается в две с половиной строчки кода, а я, как обычно, не то и не туда прибавлял, тем более, что вычитать нужно было ))
Все прокручивается плавно, не мерцает и вообще замечательно. Пока не знаю, что там с зумом и маркерами будет, но дополнительный компонент постараюсь не ставить до упора.


Код:
procedure TForm1.imgMapMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if ssLeft in Shift then
    begin
      MAP_POINT.X:=X;
      MAP_POINT.Y:=Y;
    end;
end;

procedure TForm1.imgMapMouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
begin
  if ssLeft in Shift then
    ScrollBox_appMaps.ScrollBy(X-MAP_POINT.X, Y-MAP_POINT.Y);
end;
MAP_POINT - это глобальная переменная типа TPoint.
imgMap - это TImage с загруженной картинкой.

Факультативно можно добавить ограничители в СкроллБай, чтоб картинку нельзя было перетащить за пределы формы.

Последний раз редактировалось exyl; 16.11.2014 в 02:46.
exyl вне форума Ответить с цитированием
Старый 16.11.2014, 04:31   #7
Vapaamies
Просветитель
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,844
По умолчанию

Цитата:
Сообщение от exyl Посмотреть сообщение
MAP_POINT - это глобальная переменная типа TPoint.
Раз уж взялся делать по-человечески, иди до конца. Начальную точку нужно хранить в виде полей private-секции формы, а не в глобальных переменных.
В разработке: воспроизводственный контур ИТ
Vapaamies вне форума Ответить с цитированием
Старый 16.11.2014, 04:51   #8
exyl
Пользователь
 
Регистрация: 15.11.2014
Сообщений: 75
По умолчанию

Цитата:
Сообщение от Vapaamies Посмотреть сообщение
Раз уж взялся делать по-человечески, иди до конца. Начальную точку нужно хранить в виде полей private-секции формы, а не в глобальных переменных.
А откуда ты знаешь, где еще используется эта переменная? Телепат?

На самом деле, она у меня там и прописана. Но к тебе у меня вопрос. А как тогда назвать такую переменную? Локальной? А как же тогда переменные внутри функций? "Локально-локальные" или "совсем локальные"? ))

Так вот, все переменные, объявленные за пределами функций или процедур называются глобальными. Только одни (в секции public) могут использоваться из других форм, а другие (в секции private) - нет. Так что возьми самоучитель с основами терминологии и выучи базу, чтоб потом не попадать в глупые ситуации.
exyl вне форума Ответить с цитированием
Старый 16.11.2014, 10:54   #9
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

Цитата:
А как тогда назвать такую переменную?
При чем здесь локальные и глобальные переменные? Данные секций классов не имеют к ним ни какого отношения. По другому инициализируются, другое время существования и другой доступ к ним.
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 16.11.2014, 12:01   #10
exyl
Пользователь
 
Регистрация: 15.11.2014
Сообщений: 75
По умолчанию

Цитата:
Сообщение от Аватар Посмотреть сообщение
При чем здесь локальные и глобальные переменные? Данные секций классов не имеют к ним ни какого отношения. По другому инициализируются, другое время существования и другой доступ к ним.
Ну а как ты переменную назовешь, если ее можно юзать в любой процедуре/функции модуля? Не локальной же?

Но это вопрос терминологии, а у меня есть вопрос по теме.
Дошло дело до зума.

Есть код. Процедуру описал в private, как и константу MAP_ZOOM_NUM, которая нужна для определения количества приближений/отдалений от плана и равна 5. MAP_ZOOM тоже из private, типа byte и туда заносится текущий порядковый номер зума (от 0 до MAP_ZOOM_NUM), соответственно при MAP_ZOOM=5 зум наименьший (самое сильное уменьшение картинки), а если =0, то зума нет (оригинальный размер). ZOOM_MAP_POINT - это TPoint из private, в который пишутся координаты курсора относительно картинки в OnMouseMove Image1.

Код:
procedure TForm1.WMMOUSEWHEEL(var Msg: TMessage);
begin
  inherited;
  if WindowFromPoint(Mouse.CursorPos)<>Panel1.Handle then
    Exit;
  if Msg.WParam<0 then
    if MAP_ZOOM>=MAP_ZOOM_NUM then
      Exit
    else
      begin
        Inc(MAP_ZOOM);
        //Image1.Top:=Panel1.Height div 2-ZOOM_MAP_POINT.Y div 2; //Вот тут нужно...
        //Image1.Left:=Panel1.Width div 2-ZOOM_MAP_POINT.X div 2; //...преобразовать координаты.
        Image1.Width:=Round(Image1.Width/1.25); //т.к. свойство proportional имеджа стоит в true
      end
  else
    if MAP_ZOOM<=0 then
      Exit
    else
      begin
        Dec(MAP_ZOOM);
        //Image1.Top:=Panel1.Height div 2-ZOOM_MAP_POINT.Y div 2;
        //Image1.Left:=Panel1.Width div 2-ZOOM_MAP_POINT.X div 2;
        Image1.Width:=Round(Image1.Width*1.25);
      end;
end;
А вот теперь вопрос. Как правильно преобразовать координаты, чтоб приближая/отдаляя картинку она делала это относительно курсора (как, например, в гугл мэпс или яндекс картах)?
Задача геометрическая, но я никак не могу сообразить. Есть ширина/высота самой картинки и окошка, в котором она отображается. Есть топ/лефт картинки. Закомментированные строки кода - это как раз те места, где нужно вписать формулу для пересчета. Загвоздка одна - я не могу сообразить, как она будет выглядеть.

Последний раз редактировалось exyl; 16.11.2014 в 12:10.
exyl вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Определение размера файлов большого размера stpdqstns Общие вопросы C/C++ 4 13.03.2013 11:50
плавное появление/исчезновение объекта TImage Хамяг Общие вопросы Delphi 2 04.12.2011 01:14
Плавное изменение размера формы TaTT DoGG Общие вопросы .NET 5 31.03.2010 16:53
Перетаскивание файла из ShellListView в TImage Fakov Общие вопросы Delphi 1 31.01.2010 22:56
Сохранение книги большого размера. nemoomen Microsoft Office Excel 12 22.03.2009 05:57