Posts tagged ‘messages’

Ciągnięcie okna za wnętrze

2009-10-06 21:14

System Windows pozwala tworzyć okna o różnych niestandardowych właściwościach – między innymi takich, które nie zawierają żadnego standardowego elementu, jak pasek tytułu czy przycisk zamknięcia. Kiedy zechcemy umożliwić przesuwanie takiego okna, to natrafimy na klasyczny problem Windows API, który posiada kilka rozwiązań. I jak to często bywa, mało które jest dobre ;)

Najkrótszym jest obsłużenie komunikatu WM_NCHITTEST. Przy jego pomocy system pyta okno, w jaką jego część “trafia” (stąd nazwa hit test) podany punkt. Trik polega na oszustwie poprzez udawanie, że prawie całe nasze okno (a przynajmniej jego obszar klienta) jest paskiem tytułu:

  1. case WM_NCHITTEST:
  2.     LRESULT hit = DefWindowProc(hWnd, uMsg, wParam, lParam);
  3.     return hit == HTCLIENT ? HTCAPTION : hit;

Jest to jednak na tyle skuteczne, że wówczas nasze okno naprawdę zacznie składać z samego paska tytułu. Najpoważniejszym (acz wcale nie jedynym) skutkiem ubocznym tego faktu jest niemożność jakiejkolwiek interakcji z kontrolkami zawartymi w oknie. Jeśli więc mamy takowe, to mamy też kłopot :)

Można oczywiście załatwić wszystko ręcznie: wykryć przeciąganie (WM_LBUTTONDOWN), “złapać” myszkę (SetCapture), odpowiednio przesuwać okno (np. SetWindowPos) o różnicę początkowej oraz aktualnej pozycji kursora (w WM_MOUSEMOVE), a na koniec zwolnić gryzonia (ReleaseCapture) w odpowiedzi na koniec przeciągania (WM_LBUTTONUP). Uff… Sporo roboty, nieprawdaż? Tak to jest, kiedy oszustwo nie popłaca :)
A może jednak?… Pomysł z podszyciem się pod pasek tytułu wydawał się dobry, lecz sęk w tym, że nie potrzebujemy (wręcz nie chcemy) całej jego funkcjonalności. Dlatego zamiast dużego przekrętu posłużmy się małym: symulujmy tylko i wyłącznie wciśnięcia lewego przycisku myszy:

  1. case WM_LBUTTONDOWN:
  2.     SendMessage (hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
  3.     break;

Wciśnięcia kierowane w pasek tytułu, rzecz jasna. W ten sposób “wywołamy” niejako tę część jego możliwości, która nas interesuje – czyli przesuwanie okna. Jednocześnie, ponieważ robimy to dopiero w WM_LBUTTONDOWN, nie przeszkadzamy innym kontrolkom w odpowiadaniu na zdarzenia myszy.

To rozwiązanie ma jeszcze jedną zaletę: daje się je zastosować także w środowiskach, które nie dają łatwego dostępu do procedury zdarzeniowej okna – jak np. Windows Forms. W nich wystarczy wywołać SendMessage wewnątrz zdarzenia w rodzaju OnMouseDown (wciśnięcie przycisku myszy nad oknem).

Tags: , ,
Author: Xion, posted under Programming » 4 comments
 


© 2019 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.