Witam, przedstawiam sposób, w jaki można otrzymać okno dowolnego kształtu oraz jak (w przypadku gdy oknem jest forma) przenosić je.
Opis algorytmu.
Procedura przyjmuje trzy argumenty:
Mask – piksele o tym kolorze traktowane są jako przezroczyste,
Bmp – bitmapa, której kształt ma przybrać okno,
hwnd – uchwyt okna, którego kształt ma zostać zmieniony.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
procedure CreateVariousWindow(Mask : TColor ; var Bmp : TBitmap ; hwnd : HWND) ; var hrgn1 , hrgn2 : HRGN ; // 1 i , j , x : Integer ; begin hrgn2 := CreateRectRgn(0 , 0 , 0 , 0) ; for i := 0 to Bmp.Height - 1 do // 2 begin x := 0 ; for j := 0 to Bmp.Width - 1 do if (Bmp.Canvas.Pixels[j , i] <> Mask) and (x = 0) then // 3 x := j else if (x <> 0) and ((Bmp.Canvas.Pixels[j , i] = Mask) or (j = Bmp.Width - 1)) then // 4 begin hrgn1 := CreateRectRgn(x , i , j , i + 1) ; CombineRgn(hrgn2 , hrgn1 , hrgn2 , RGN_OR) ; // 5 x := 0 ; end ; end ; SetWindowRgn(hwnd , hrgn2 , true) ; // 6 end ; |
1. Definiujemy dwa regiony, pierwszy określa wyodrębnione pola z danej części obrazka, a drugi całe dotychczas określone pole
2. Sprawdzamy każdy piksel wczytanego obrazka-jeżeli natkniemy się na taki, który jest różny od maski (3) i jeżeli już wcześniej takiego nie znaleźliśmy, to zapamiętujemy jego pozycję. Jeżeli warunek nie jest spełniony, to sprawdzamy (4) czy już znaleźliśmy piksel różniący się od maski i czy aktualny piksel jest taki sam jak kolor maski lub doszliśmy do końca linii obrazka. Jeżeli wyrażenie jest prawdziwe, to tworzymy nowy region, lewy górny punkt ma współrzędne (x , i) a dolny prawy (j , i + 1), czyli tworzymy region o wysokości jednego piksela. Następnie (5) łączymy cały dotychczas wyodrębniony obszar z aktualnie utworzonym.
6. Przypisujemy określony obszar oknu, którego uchwyt przekazaliśmy w parametrze hwnd.
Możemy teraz wykorzystywać nasza procedurę do zmiany kształtów dowolnego okna, np. formy (radzę ustawić BorderStyle formy na bsNone) czy przycisku:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
CreateVariousWindow(RGB(0 , 0 , 0) , Bmp , Handle) ; // forma CreateVariousWindow(RGB(0 , 0 , 0) , Bmp , Button1.Handle) ; // przycisk var h : HWND ; begin h := FindWindow(nil , 'Kalkulator') ; CreateVariousWindow(RGB(0 , 0 , 0) , Bmp , h) ; // zmieniamy kształt kalkulatora Windowsowego ;-) |
Efekty działania:
Przycisk:
Kalkulator:
Poruszanie oknem o nietypowym kształcie.
Jeżeli chcemy uzyskać najlepszy efekt zmiany kształtu formy, musimy ustawić BorderStyle na bsNone. Stracimy jednak przez to belkę tytułową, przez co nie będziemy mogli przesuwać naszego okna. Aby umożliwić zmianę położenia okna, musimy zrobić to w następujący sposób: dodaj definicje dwóch zmiennych globalnych:
1 2 3 4 5 6 7 |
var Form1: TForm1; Klik : Boolean ; OldMousePos : TPoint ; |
Klik określa, czy wciśnięto lewy przycisk myszki a OldMousePos poprzednią pozycję myszki.
Teraz obsłuż zdarzenia OnMouseDown, Up oraz Move formy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Button = mbLeft then begin Klik := true ; GetCursorPos(OldMousePos) ; end ; end; procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Klik := false ; end; procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var P : TPoint ; begin if Klik then begin // pobieramy aktualną pozycję myszy, aktualizujemy pozycję okna // dodając do aktualnej pozycji różnicę nowej i starej poz. myszki GetCursorPos(P) ; Form1.Left := Form1.Left + P.X - OldMousePos.X ; Form1.Top := Form1.Top + P.Y - OldMousePos.Y ; OldMousePos.X := P.X ; OldMousePos.Y := P.Y ; end ; end; |