Wątek przeniesiony 2016-06-16 18:58 z Newbie przez furious programming.

Ruch kursora (MouseEvent) z wciśniętym przyciskiem myszy.

0

Witam.

Muszę wykryć moment, w którym użytkownik wjeżdża kursorem w obszar komponentu. Niby proste, bo kontrolka obsługuje zdarzenia OnMouseEnter i OnMouseLeave. Ja jednak chcę oskryptować sytuację, gdy użytkownik wjeżdżając na kontrolkę, przytrzymuje lewy przycisk myszy. Niestety, ale Delphi 7 w ogóle nie chce wykonywać MouseEventów (typu OnMouseEnter i OnMouseLeave), jeżeli lewy przycisk myszy jest wciśnięty (z prawym działa).

Da się coś z tym zrobić?

0

Co to za komponent i z jakiej klasy dziedziczy?

Z tego co widzę, akurat oczekiwane zachowanie jest bardzo podobne lub identyczne jak Drag&Drop.

0

Akurat rodzaj komponentu nie ma dla mnie znaczenia. Chcę uzyskać coś takiego, że po najechaniu myszą na Panel, zmienia on kolor. Panel nie obsługuje OnMouseEnter i OnMouseLeave, więc nieco chałupniczo wrzuciłem na niego Label z ustawioną przezroczystością i brakiem tekstu. Dzięki temu pozostał niewidoczny i pozwalał mi obsłużyć MouseEventy. Niestety apka ich nie wychwytuje, jeżeli lewy przycisk myszy jest wciśnięty.

A Drag&Drop nie działa (właśnie testowałem na Panelu).

2

Akurat rodzaj komponentu nie ma dla mnie znaczenia.

No dobrze, jednak komponenty graficzne różnią się implementacją od tych okienkowych, więc to ma znaczenie;

Panel nie obsługuje OnMouseEnter i OnMouseLeave, więc nieco chałupniczo wrzuciłem na niego Label z ustawioną przezroczystością i brakiem tekstu.

A to nie mogłeś sobie dodać obsługi komunikatów CM_MOUSEENTER i CM_MOUSELEAVE? Przecież to banalne...


Swoją drogą, zależy też w którym miejscu wciśnięto LPM, czy nad powierzchnią formularza, czy nad jakimś komponentem;

Swoje komponenty pisałem od podstaw i mam w nich dodaną obsługę tych komunikatów (bez zdarzeń, tylko dla internalsów); Działa to bez problemu - można wcisnąć LPM gdziekolwiek poza docelowym komponentem (na formularzu lub innym komponencie), a następnie najechać na ten docelowy i komunikaty zostają prawidłowo obsłużone (wykorzystuję je do malowania innej grafiki); Trzymając wciśnięty LPM każdy komponent prawidłowo obsługuje oba komunikaty i na nie prawidłowo reaguje; Natomiast kliknięcie realizowane jest po zwolnieniu LPM; Działa to praktycznie tak samo jak Drag&Drop, ale nie umożliwia przeciągania elementów;

Całość zawdzięczam usunięciu enuma csCaptureMouse z ControlStyle - bez tego klasa okna zupełnie inaczej obsługuje te komunikaty; M.in. nie wysyła komunikatu CM_MOUSEENTER do komponentu, jeśli w momencie najechania kursorem, wciśnięty jest LPM;

Spróbuj u siebie wykluczyć ten enum, bo ja piszę pod Lazarusem i LCL może nieco inaczej się zachowywać; Napisz swój komponent dziedziczący po TPanel, w konstruktorze usuń tego enuma, a także dodaj sobie obsługę tych komunikatów i ew. także zdarzenia, jeśli potrzebujesz móc je zdefiniować na zewnątrz.

0

Nie chciało mi się pisać komponentu, więc po prostu stworzyłem sobie klasę na bazie TPanel i dodałem obsługę komunikatu CM_MOUSEENTER (i tak tworzę te Panele w locie, więc nie przeszkadza mi brak kontrolki w formie "fizycznej", jako odrębnego komponentu). Faktycznie uprościło mi to życie ;). Niestety wyłączenie csCaptureMouse dla mojego Panelu nie pomogło (dalej nie chciało łapać komunikatu przy wciśniętym przycisku myszy). Na szczęście idąc za radą kAzek'a, spróbowałem wykluczyć użycie tego stylu nie dla mojego Panelu, ale dla jego rodzica i to... pomogło! Sam bym na to nie wpadł, dzięki wam obu :).

EDIT:

Po dalszych "badaniach" okazało się, że w ogóle nie o rodzica tutaj chodzi. Znaczenie ma najwyraźniej tylko to, na jakiej kontrolce wywołamy WM_LBUTTONDOWN (a potem przytrzymamy lewy przycisk i spróbujemy uruchomić zdarzenie CM_MOUSEENTER). Jeżeli "kliknięta" kontrolka używa stylu csCaptureMouse, wychwycenie komunikatu przez CM_MOUSEENTER nie zadziała.

Może się to komuś przyda.

0

Znaczenie ma najwyraźniej tylko to, na jakiej kontrolce wywołamy WM_LBUTTONDOWN (a potem przytrzymamy lewy przycisk i spróbujemy uruchomić zdarzenie CM_MOUSEENTER). Jeżeli "kliknięta" kontrolka używa stylu csCaptureMouse, wychwycenie komunikatu przez CM_MOUSEENTER nie zadziała.

Tak, dokładnie o to chodzi;

Istnienie csCaptureMouse w zbiorze ControlStyle zapewnia skupienie obsługi na klikniętym komponencie - wciskając i trzymając LPM, choćbyś nie wiem gdzie przesunął kursor, to i tak kontrolka nie dostanie CM_MOUSELEAVE, dopóki nie puści się trzymanego przycisku; Oprócz tego dostanie także komunikat WM_LBUTTONUP (pod Lazarusem LM_LBUTTONUP);

W każdym razie wspomniany enum nie może istnieć w komponencie, nad którym wciskasz LPM.

0

Odświeżam ten temat, bo w sumie to kontynuacja mojego poprzedniego problemu, więc chyba nie ma sensu zaśmiecać forum czymś nowym.

Okazało się, że jednak muszę wykryć także i moment, w którym użytkownik puszcza LMB.

Mam coś takiego, że po wciśnięciu lewego przycisku myszy, uruchamia się coś w rodzaju globalnego trybu edycji, pozwalającego na modyfikację pewnych elementów w obrębie mojej aplikacji (po najechaniu na nie myszą). Tryb ten jednak powinien się zawsze dezaktywować po tym, jak użytkownik zwolni przycisk myszy. Chciałem to obsłużyć w taki sposób, że wszystkie kontrolki w obrębie mojej aplikacji, będą po prostu nasłuchiwały w oczekiwaniu na WM_LBUTTONUP. Jest to jednak zbyt uciążliwe i niepraktyczne. Użytkownik może z resztą zwolnić przycisk poza obrębem mojej aplikacji i wtedy też kicha, bo tego nie wykryję i wszystko się sypnie...

Da się to jakoś rozwiązać? Trzeba nakładać global hook na mysz, czy można to obejść mniej inwazyjnie?

1

Nie mam teraz głowy do tego, ale raczej trzeba będzie założyć hooka (co nie jest trudne, wręcz przeciwnie), bo komunikaty dostarczane są bezpośrednio do komponentów (tych posiadających uchwyt), więc formularz sam ich nie przechwyci; Hook to akurat kilka linijek kodu, a przynajmniej będzie działał dla całej zawartości formularza;

PS: Ewentualnie może ktoś inny będzie znał rozwiązanie bez używania WinAPI.

1 użytkowników online, w tym zalogowanych: 0, gości: 1