C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Как направить клик мышки с TImage под него?
Kite
  Отправлено: 25.02.2004, 18:17


Ученик-кочегар

Группа: Участник
Сообщений: 8



Есть два TImage объекта, расположены друг над другом, клики от мышки естественно ловит только верхний TImage, на обоих TImage находятся рисунки с Transparent частями, нужно, чтобы при клике на прозрачном цвете верхнего TImage, клик уходил на TImage под ним, родилась, блин, проблема, не могу решить.
Pirs
Отправлено: 25.02.2004, 22:28


Дежурный стрелочник

Группа: Участник
Сообщений: 39



Просто из image1 вызываешь обработчик OnClick для image2.
Если это событие MouseDown, то вызываешь такое же событие для image2, но подставляешь координаты X, Y из image1 и если у них расположение не совпадает то плюсуешь к X, Y разницу в пикселах.
Kite
Отправлено: 26.02.2004, 08:19


Ученик-кочегар

Группа: Участник
Сообщений: 8



У меня тут все немножко сложнее, Image-ы создаются динамически, ну вобщем есть как-бы репозиторий там образцы TImage-ей, пользователь мышкой перетаскивает нужный Image на рабочую область (ScrollBox), все это сделано при помощи DragDrop и DragOver, поэтому когда он шлепает объект в нужном месте, програма динамически создает TImage и вставляет его в ScrollBox там, где произошел Drop, а в динамически созданном TImage, я подключаю свои обработчики onMouseDown, onMouseOver для того, чтобы мышкой можно было эти объекты перемещать по рабочей области ScrollBox, поэтому объекты мои не фиксированы и нужно как-то сообщение onMouseDown, которое словила верхняя TImage отправить обратно в очередь сообщений.
Если уж действовать таким методом как предложено, так, тогда как в этом случае узнать, из обработчика клика верхнего TImage какой находится под ним?
Георгий
Отправлено: 26.02.2004, 12:32


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



есть такая идея — сделать Image, словившее клик невидимым и действительно отправить сообщение обратно в очередь.
поставить сообщение в очредь можно функцией PostMessage

но это будет некрасиво.
поэтому предлагаю всётаки где-нибудь хранить указатели на созданные image и при каждом click`е пробегаться по этим image и искать всё то множество, на которое попал click.
Kite
Отправлено: 26.02.2004, 18:09


Ученик-кочегар

Группа: Участник
Сообщений: 8



Пробегать все — тоже некрасиво, большая задержка времени при большом количестве объектов(конечно смешно на сегоднешних машинах), но я как программист, выросший на старых машинах, на ASM-е к этой идее отношусь с болью в душе smile.gif)
А через PostMessage тоже можно, только нужно каким-нибудь другим методом, без выключения visible, какнибудь надо снять захват сообщений с объекта, который поймал и отправить обратно сообщение в очередь, тогда его словит другой объект. Надо посмотреть хелп... Я всетаки склоняюсь, что борландовцы эту хрень предусмотрели.
Георгий
Отправлено: 26.02.2004, 20:25


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



QUOTE
А через PostMessage тоже можно, только нужно каким-нибудь другим методом, без выключения visible, какнибудь надо снять захват сообщений с объекта, который поймал и отправить обратно сообщение в очередь, тогда его словит другой объект. Надо посмотреть хелп... Я всетаки склоняюсь, что борландовцы эту хрень предусмотрели.

в photon`е под QNX это можно, а в MS Windows такое если и возможно, то не афишируется smile.gif вообще то говоря я и не искал особо...

QUOTE
Пробегать все — тоже некрасиво, большая задержка времени при большом количестве объектов
давай оценим накладные расходы на линейный поиск:
для каждого элемента:
1. выбор элемента ( чтение 4х байт — указателя на него )
2. проверка попадает ли click в его прямоугольник ( чтение 4*4 байт + 4 операции сравнения )
3. если попадает — то является ли область непрозрачной ( несколько обращений по указателям, вызов перегруженного оператора индексирования, возврат из вызова — итого много тактов )
4. если непрозрачная, то вызов click`а на элементе — итого ещё дольше, чем 3

как итог:
1. если много маленьких элементов (до 1000) то алгоритм работает достаточно быстро ( в цикле работают 1 и 2 )
2. если много больших непрозрачных элементов то тоже работает достаточно быстро (как только нашли непрозрачный, то остановились. в цикле работают пункты 1,2; пункты 3,4 только один раз)
3. если много прозрачных элементов то будут тормоза (в цикле будут работать пункты 1,2,3; пункт 4 только один раз)

Вообще то говоря эта задача схожа с задачей трассировки лучей в 3х мерном пространстве, но с одной поправкой — твой "луч" (click) идёт перпендикулярно плоскостям объектов, поэтому можно попробовать ускорить работу по отсеиванию не стоящих на пути луча непрозрачных участков, но, на мой взгляд, это слишком трудоёмко — советую как пробный вариант сделать с линейный поиском (перебором) и посмотреть время работы, скорее всего оно будет удовлетворительное.
Kite
  Отправлено: 26.02.2004, 20:41


Ученик-кочегар

Группа: Участник
Сообщений: 8



Всетаки я решил эту проблему, да очень простым методом

((TImage*)Sender)->Enabled=false;
SendMessage(Handle,WM_LBUTTONDOWN,0,lpar);
((TImage*)Sender)->Enabled=true;

Если в TImage выставить Enable в false, то он перестает принимать сообщения от всего, потом мы напрямую, не через PostMessage, а напрямую посылаем мообщение в обаботчик сообщений TApplication через SendMessage, Handle — хэндл TApplication, именно он занимается расквартировкой кликов по объектам(сам перебирает список smile.gif ). А координаты мышки мы берем глобальные из переменной Mouse и засовываем их lpar во HIWORD — Y, а в LOWORD — X, вот так все оказалось просто. Спасибо всем!
Kite
Отправлено: 26.02.2004, 22:11


Ученик-кочегар

Группа: Участник
Сообщений: 8



Небольшое исправление:

TPoint cl=Form1->ScreenToClient(Mouse->CursorPos);
long lpar=(cl.y << 16)|(WORD)cl.x;
Image2->Enabled=false;
SendMessage(Form1->Handle,WM_LBUTTONDOWN,0,lpar);
Image2->Enabled=true;

Вот так надо, оказывается хэндл в SendMessage нужно передавать, той формы, где все находится, а не TApplication, а x и y нужно передавать в локальных для формы координатах, во как, просто фантастически просто и удобно, я тащусь smile.gif !!!!
Георгий
Отправлено: 27.02.2004, 00:32


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



попробовал сделать то, что ты сказал и ушло всё это в вечную рекурсию.
при использовании PostMessage рекурсии не получается, зато получается вечный цикл.

что делаю не так?

шлёпал на форму 2 взаимоперекрывающихся TImage и 1 TMemo.

CODE
void __fastcall TForm1::Image2MouseDown(TObject *Sender,
     TMouseButton Button, TShiftState Shift, int X, int Y)
{
this->Memo1->Lines->Add("*2");
TPoint cl=Form1->ScreenToClient(Mouse->CursorPos);
long lpar=(cl.y << 16)|(WORD)cl.x;
Image2->Enabled=false;
PostMessage(Form1->Handle,WM_LBUTTONDOWN,0,lpar);
Image2->Enabled=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Image1MouseDown(TObject *Sender,
     TMouseButton Button, TShiftState Shift, int X, int Y)
{
this->Memo1->Lines->Add("*1");
}


Отредактировано Георгий — 27/02/2004, 01:35
Kite
  Отправлено: 27.02.2004, 07:28


Ученик-кочегар

Группа: Участник
Сообщений: 8



Да, я этого не заметил, так как у меня постоянно выводилась напоминалка после нажатия — MessageBoxA, просто в билдере реализована такая система, если пользователь нажал на компоненте кнопку мыши, то этот компонент начинает принимает все сообщения напрямую, даже если мышка не над ним, так что рекурсия объясняется тем, что все сообщения хватал именно этот объект, а если выводиш мессажбокс, то это снимается, также эту штуковину снимает функция ReleaseCapture(), так что вот так надо делать...
CODE

void __fastcall TForm1::Image2MouseDown(TObject *Sender,
     TMouseButton Button, TShiftState Shift, int X, int Y)
{
TPoint cl=Form1->ScreenToClient(Mouse->CursorPos);
long lpar=0x0; //(cl.y << 16)|(WORD)cl.x;
//        Application->MessageBoxA("Верхняя","",MB_OK);
       Image2->Enabled=false;
       ReleaseCapture();
       SendMessage(Form1->Handle,WM_LBUTTONDOWN,0,lpar);
       Image2->Enabled=true;
}

Георгий
Отправлено: 27.02.2004, 09:47


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



Прикольно — работает!
но вот с WM_LBUTTONDBLCLK какоя то фигня получается — происходит чередование: то первый Image срабатывает, то второй, причём строго по очереди.
никогда не задумывался как именно VCL трассирует сообщения, а тут даже интересно стало
Хм — с учётом моих рассуждений об эффективности поиска — что будет если сделать десяток тысяч взаимопересекающихся элементов GUI (например кнопочки) и посмотреть насколько быстро будет это реагировать на клики мышки?
Kite
Отправлено: 01.03.2004, 15:07


Ученик-кочегар

Группа: Участник
Сообщений: 8



Ну по крайней мере я пробовал динамически создать 50000 TButton на форме, клики они принимают моментально, только передвижение формы — становится затруднительной задачей, он просто долго метод Paint выполняет для прорисовки. А насчет дабл клика, надо попробовать, мне это тоже в програме нужно будет учесть.

Вернуться в Вопросы программирования в C++Builder