Przezroczysta forma

patrol_x

Niniejszy artykuł ma na celu przedstawienie podstawowych technik kształtowania interfejsu użytkownika za pomocą określania przezroczystości elementów formy. Techniki te opierają się przede wszystkim na wywołaniach WinAPI, choć zamieszczone przykłady mogą również przedstawiać realizację w oparciu o biblioteki VCL.

1 Techniki kształtowania wyglądu okna
     1.1 Ustawienie koloru przezroczystego
     1.2 Wycinanie za pomocą regionów
     1.3 Ustawienie poziomu przezroczystości formy
     1.4 Ustawienie przezroczystości poszczególnych pikseli
     1.5 Ustawienie przezroczystości poszczególnych pikseli i zachowanie komponentów
2 Przygotowanie bitmap
     2.6 Generowanie
     2.7 Przygotowanie za pomocą Adobe Photoshop
     2.8 Przygotowanie za pomocą GIMP
     2.9 Konwersja PNG do BMP (32 bit) za pomocą Microsoft Paint

Techniki kształtowania wyglądu okna

Ustawienie koloru przezroczystego

Jest to najprostsza w realizacji technika. Polega na określeniu, jaki kolor będzie uznawany za przezroczysty. Każde wystąpienie wskazanego koloru tworzy w danym miejscu wycięcie w oknie. Miejsce to jest taktowane jako obszar poza aplikacją - kliknięcie w miejsce z kolorem przezroczystym jest równoznaczne z kliknięciem w obszar pod danym oknem.

Najprostszy przykład realizacji za pomocą VCL jest przedstawiony poniżej. Wystarczy utworzyć nową aplikację, postawić dowolne komponenty i w akcji OnShow wpisać poniższy kod:

begin
//Ustawianie wyglądu formy
BorderStyle := bsNone;
Color := clFuchsia;
with TShape.Create(self) do
  begin
  Parent := self;
  Shape := stRoundRect;
  SetBounds(10, 10, 100, 100);
  end;

//Włączanie przezroczystości
TransparentColorValue := Color;
TransparentColor := TRUE;
end;

Transparent1_BlendColor.jpg
Rys. 1. Okno z kolorem przezroczystym

  • Zalety:
  • Łatwość ukształtowania formy za pomocą kształtów,
  • Łatwość ukształtowania okna za pomocą bitmap,
  • Obsługa komponentów ustawionych na formie.
  • Wady:
  • Brak możliwości stopniowania przezroczystości - piksel jest całkiem widoczny albo wcale,
  • Efekt ustawiania przezroczystości w miejscach niezaplanowanych, na przykład we fragmentach ikon, rysunków lub obszarze, który użytkownik może kolorować samodzielnie, gdyż może użyć koloru, ustawionego jako przezroczysty.

Wycinanie za pomocą regionów

Technika ta polega na przypisaniu oknu regionu (figury lub efektu działania na zbiorach punktów figur) jako prezentowanego obszaru okna. Piksele znajdujące się w ramach regionu są prezentowane, piksele poza regionem są traktowane jako obszar poza aplikacją.

Najprostszy przykład realizacji za pomocą WinAPI jest przedstawiony poniżej. Wystarczy utworzyć nową aplikację, postawić dowolne komponenty i w akcji OnShow wpisać poniższy kod:

var Region1, Region2:HRGN;
begin
//Przygotowywanie regionów do wycięcia
Region1 := CreateEllipticRgn(10, 10, 100, 100);
Region2 := CreateRectRgn(0, 30, 200, 70);
CombineRgn(Region1, Region1, Region2, RGN_XOR);

//Wycinanie formy
SetWindowRgn(Handle, Region1, TRUE);

//Usuwanie regionów
DeleteObject(Region1);
DeleteObject(Region2);
end;

Transparent2_Region.jpg
Rys. 2. Okno wycięte regionem

Przykładzik wielokrotnego wycinania formy o dość interesującym kształcie.

var rgn, rgn2 :HRGN;
temp_rgn:HRGN;

begin

// Stworzenie dużego kwadratu
    rgn :=CreateRectRgn( 0,0, 200,200);
// Wycięcie wnętrza za pomocą małego kwadratu
    temp_rgn :=CreateRectRgn(50,50, 150,150 );
    CombineRgn (rgn, rgn, temp_rgn, RGN_DIFF);
    DeleteObject (temp_rgn);
// Na koniec dodanie elipsy
    temp_rgn :=CreateEllipticRgn( 40,80, 160,120);
    CombineRgn (rgn, rgn, temp_rgn, RGN_OR);
    SetWindowRgn(Handle, rgn, TRUE);
    DeleteObject (temp_rgn);

end;
  • Zalety:
  • Łatwość ukształtowania formy za pomocą kształtów,
  • Możliwość przycięcia części komponentu,
  • Obsługiwane przez systemy Microsoft Windows 9x/NT/ME.
  • Wady:
  • Brak możliwości ukształtowania okna za pomocą bitmap,
  • Brak możliwości stopniowania przezroczystości - piksel jest całkiem widoczny albo wcale.

Ustawienie poziomu przezroczystości formy

Technika ta polega na ustawieniu wartości przezroczystości całego okna i jego komponentów - wartość ta jest liczbą całkowitą z zakresu 0..255. Okno z ustawioną wartością 255 jest traktowane jako całkowicie nieprzezroczyste. Okno z przezroczystością 1..254 jest przezroczyste, ale kliknięcie na dowolny piksel jest traktowane jako kliknięcie w ramach okna aplikacji. Okno z przezroczystością 0 jest traktowane jako okno niewidoczne, a kliknięcie na dowolny piksel jest równoznaczne z kliknięciem w obszar pod danym oknem.

Najprostszy przykład realizacji za pomocą VCL jest przedstawiony poniżej. Wystarczy utworzyć nową aplikację, postawić dowolne komponenty i w akcji OnShow wpisać poniższy kod:

begin
AlphaBlendValue := 100;
AlphaBlend := TRUE;
end;

Transparent3_AlphaValue.jpg
Rys. 3. Okno z ustawionym poziomem przezroczystości

Najprostszy przykład realizacji za pomocą WinAPI jest przedstawiony poniżej. Wystarczy utworzyć nową aplikację, postawić dowolne komponenty i w akcji OnShow wpisać poniższy kod:

begin
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
SetLayeredWindowAttributes(Handle, 0, 100, LWA_ALPHA);
end;

Podczas wyłączania przezroczystości warto odmalować okno, gdyż wiąże się to ze zmianą trybu obsługi okna przez system operacyjny:

begin
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) and not WS_EX_LAYERED);
RedrawWindow(Handle, 0, 0, RDW_ERASE or RDW_INVALIDATE or RDW_FRAME or RDW_ALLCHILDREN);
end;
  • Zalety:
  • Łatwość określenia wspólnego poziomu przezroczystości okna i komponentów,
  • Możliwość ustawienia częściowej przezroczystości.
  • Wady:
  • Brak możliwości ukształtowania okna za pomocą bitmap czy kształtów,
  • Brak możliwości ustawienia przezroczystości dla okna będącego potomkiem innego okna,
  • Komponenty przyjmują poziom przezroczystości całego okna,
  • Obsługiwane przez systemy Microsoft Windows 2000/XP/Vista.

Ustawienie przezroczystości poszczególnych pikseli

Technika ta polega na dostarczeniu bitmapy (wygenerowanej lub wczytanej), która będzie stanowiła obraz okna. Ponieważ bitmapa ta zastępuje obraz wyglądu okna, nie są widoczne żadne komponenty na nim umiejscowione. Jednak możliwe jest zastosowanie bitmapy o 32 bitowej głębi kolorów (RGBA), a zatem informacji o stopniu przezroczystości poszczególnych pikseli. Dodatkowo warto zwrócić uwagę na fakt, że system, posiadając gotowy obraz okna, nie ma potrzeby wywoływać zdarzenia odmalowania (co zwykle wykonuje przez wysłanie komunikatu). W przypadku okien o przezroczystości poszczególnych pikseli, decydowanie o zmianie wyglądu okna leży wyłącznie w gestii samej aplikacji. Podczas modyfikowania pozycji takiego okna nie jest również wywoływane odmalowywanie okien znajdujących się pod spodem. Wynika to z faktu, że system domalowuje odpowiednio przezroczysty obraz okien dopiero na samym końcu procesu generowania wyglądu ekranu, którego dokonuje tak, jakby przezroczyste okna nie były widoczne - dzięki temu rysowane są okna znajdujące się pod przezroczystymi. Z tego faktu wynika pewne ograniczenie - zrzut ekranu, wykonany przez kopiowanie obrazu z kontekstu ekranu, nie zawiera okien przezroczystych.

Należy pamiętać, że piksel o przezroczystości A powinien mieć składowe R, G, B w zakresie 0..A.

Najprostszy przykład realizacji za pomocą WinAPI jest przedstawiony poniżej. Wystarczy utworzyć nową aplikację, postawić dowolne komponenty i w akcji OnShow wpisać poniższy kod:

var blend:BLENDFUNCTION;
    P:TPoint;
    S:TSize;
    Bitmap:TBitmap;
    X,Y:integer;
    Pixel:PRGBQuad;
    Alpha:byte;

begin
//Przygotowywanie wyglądu formy
BorderStyle := bsNone;
Width := 512;
Height := 512;
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);

//Przygotowywanie bitmapy
Bitmap := TBitmap.Create();
try
  Bitmap.Width := Width;
  Bitmap.Height := Height;
  Bitmap.PixelFormat := pf32bit;
  for Y := 0 to Bitmap.Height-1 do
    begin
    Pixel := Bitmap.ScanLine[y];
    for X := 0 to Bitmap.Width-1 do
      begin
      Alpha := Byte(X xor Y);
      Pixel.rgbRed := MulDiv(0, Alpha, 255);
      Pixel.rgbGreen := MulDiv(0, Alpha, 255);
      Pixel.rgbBlue := MulDiv(0, Alpha, 255);
      Pixel.rgbReserved := Alpha;
      inc(Pixel);
      end;
    end;

//Nakładanie bitmapy
  P := Point(0, 0);
  S.cx := Bitmap.Width;
  S.cy := Bitmap.Height;
  blend.BlendOp := AC_SRC_OVER;
  blend.BlendFlags := 0;
  blend.AlphaFormat := AC_SRC_ALPHA;
  blend.SourceConstantAlpha := 255;
  UpdateLayeredWindow(Handle, GetDC(0), nil, @S, Bitmap.Canvas.Handle, @P, 0, @blend, ULW_ALPHA);
finally
  Bitmap.Free;
  end;
end;

Transparent4_PerPixel.jpg
Rys. 4. Okno z przezroczystością poszczególnych pikseli

  • Zalety:
  • Łatwość dowolnego kształtowania okna za pomocą kształtów (rysowanych na bitmapie), bitmap i stopniowanej przezroczystości pojedynczych pikseli,
  • Możliwość ustawienia częściowej przezroczystości.
  • Wady:
  • Brak możliwości ustawienia przezroczystości dla okna będącego potomkiem innego okna,
  • Komponenty stają się niewidoczne,
  • Obsługiwane przez systemy Microsoft Windows 2000/XP/Vista.

Ustawienie przezroczystości poszczególnych pikseli i zachowanie komponentów

Technika ta jest efektem połączenia wycinania za pomocą regionów oraz ustawiania przezroczystości poszczególnych pikseli. Polega na utworzeniu dwóch okien:

  1. Formy z komponentami, wyciętej za pomocą regionów, aby usunąć wszelki obszar poza komponentami (można zastosować ustawienie poziomu przezroczystości formy),
  2. Formy z przezroczystością poszczególnych pikseli, rysowanej tak, aby w miejscach komponentów pierwszej formy być całkowicie przezroczystą.

Mamy więc sytuację, w której komponenty leżą na innej formie, niż przezroczyste otoczenie narysowane na bitmapie.

Pełen przykład realizacji za pomocą WinAPI jest przedstawiony poniżej. Wystarczy utworzyć nową aplikację, postawić dowolne komponenty i dopisać poniższy kod:

var Wnd: TWndClass;
    Hnd: THandle;
    ComponentForm: TForm;

//Funkcja obsługująca zdarzenia półprzezroczystego okna
function WndNewProc(Wnd: HWND; uMsg: UINT; wPar: WPARAM; lPar: LPARAM): LRESULT; stdcall;
var Rect: TRect;
begin
Result := 0;
case uMsg of
  WM_DESTROY: PostQuitMessage(0);
  WM_LBUTTONDOWN: SendMessage(Wnd, WM_SYSCOMMAND, SC_MOVE+2, 0);
  else
    begin
    if ((uMsg = WM_MOVING) or (uMsg = WM_MOVE)) and GetWindowRect(Wnd, Rect) then
      SetWindowPos(ComponentForm.Handle, 0, Rect.Left, Rect.Top, 0, 0, SWP_NOSIZE);
    Result := DefWindowProc(Wnd, uMsg, wPar, lPar);
    end;
  end;
end;

//Funkcja odmalowująca półprzezroczyste okno z uwzględnieniem regionu
procedure PaintLayeredWindow(Hnd: THandle; Region: HRGN);
var blend: BLENDFUNCTION;
    P: TPoint;
    S: TSize;
    X, Y: integer;
    bmpRGB: TBitmap;
    Alpha: byte;
    Linia24: PRGBTriple;
    Linia32: PRGBQuad;

begin
//Tworzenie warstwy RGB
bmpRGB := TBitmap.Create();
try
  bmpRGB.Width := 512;
  bmpRGB.Height := 512;
  bmpRGB.PixelFormat := pf24bit;
  with bmpRGB.Canvas do
    begin
    Brush.Style := bsSolid;
    Brush.Color := clBlack;
    Rectangle(0, 0, bmpRGB.Width-1, bmpRGB.Height-1);
    Brush.Style := bsClear;
    Font.Style := [fsBold];
    Font.Color := clRed;
    Font.Size := 32;
    TextOut(10, 10, 'TEST');
    end;

//Sklejenie RGB oraz wygenerowanego A
  with TBitmap.Create() do
    begin
    try
      Width := bmpRGB.Width;
      Height := bmpRGB.Height;
      PixelFormat := pf32bit;
      for Y := 0 to Height-1 do
        begin
        Linia24 := bmpRGB.ScanLine[Y];
        Linia32 := ScanLine[Y];
        for X := 0 to Width-1 do
          begin
          if PtInRegion(Region, X, Y) then
            Alpha := 0
          else
            Alpha := byte(X xor Y);
          Linia32.rgbRed := MulDiv(Linia24.rgbtRed, Alpha, 255);
          Linia32.rgbGreen := MulDiv(Linia24.rgbtGreen, Alpha, 255);
          Linia32.rgbBlue := MulDiv(Linia24.rgbtBlue, Alpha, 255);
          Linia32.rgbReserved := Alpha;
          inc(Linia32);
          inc(Linia24);
          end;
        end;

//Nakładanie bitmapy
      P := Point(0, 0);
      S.cx := bmpRGB.Width;
      S.cy := bmpRGB.Height;
      blend.BlendOp := AC_SRC_OVER;
      blend.BlendFlags := 0;
      blend.AlphaFormat := AC_SRC_ALPHA;
      blend.SourceConstantAlpha := 255;
      UpdateLayeredWindow(Hnd, GetDC(0), nil, @S, Canvas.Handle, @P, 0, @blend, ULW_ALPHA);
    finally
      Free;
      end;
    end;
finally
  bmpRGB.Free;
  end;
end;

//Tworzenie regionów, wycinanie okna komponentów i tworzenie okna półprzezroczystego
procedure CreateLayered(Form: TForm);
var Region: HRGN;
    ComponentRegion: HRGN;
    i:Integer;
const LayeredWndClass = 'LayeredWndClass';
begin
ComponentForm := Form;
ComponentForm.BorderStyle := bsNone;
Region := CreateRectRgn(0, 0, 0, 0);
for i := 0 to ComponentForm.ControlCount-1 do
  if ComponentForm.Controls[i].Visible then
    begin
    ComponentRegion := CreateRectRgn(ComponentForm.Controls[i].Left, ComponentForm.Controls[i].Top, ComponentForm.Controls[i].Width+ComponentForm.Controls[i].Left, ComponentForm.Controls[i].Height+ComponentForm.Controls[i].Top);
    CombineRgn(Region, Region, ComponentRegion, RGN_OR);
    DeleteObject(ComponentRegion);
    end;
with Wnd do
  begin
  lpfnWndProc := @WndNewProc;
  hInstance := hInstance;
  lpszClassName := LayeredWndClass;
  hbrBackground := COLOR_WINDOW;
  end;
Windows.RegisterClass(Wnd);
Hnd := CreateWindowEx(WS_EX_LAYERED, LayeredWndClass, PChar(ComponentForm.Caption), WS_VISIBLE, ComponentForm.Left, ComponentForm.Top, ComponentForm.Width, ComponentForm.Height, ComponentForm.Handle, 0, hInstance, NIL);
PaintLayeredWindow(Hnd, Region);
SetWindowRgn(ComponentForm.Handle, Region, TRUE);
DeleteObject(Region);
end;

Teraz, aby z Form1 utworzyć okno półprzezroczyste z komponentami, wystarczy wywołać polecenie:

CreateLayered(Form1);

Transparent5_Mixed.jpg
Rys. 5. Okno z przezroczystością poszczególnych pikseli i komponentami

  • Zalety:
  • Łatwość dowolnego kształtowania okna za pomocą kształtów (rysowanych na bitmapie), bitmap i stopniowanej przezroczystości pojedynczych pikseli,
  • Możliwość ustawienia częściowej przezroczystości dla samych komponentów.
  • Wady:
  • Brak możliwości ustawienia przezroczystości dla okna będącego potomkiem innego okna,
  • Obsługiwane przez systemy Microsoft Windows 2000/XP/Vista,
  • Relatywnie skomplikowana implementacja.

Przykładowa aplikacja wraz z kodem, wykorzystująca ten mechanizm:
*TransparentForm.zip

Przygotowanie bitmap

Generowanie

Bitmapy, określające kolor i przezroczystość poszczególnych pikseli, można wygenerować, jak to miało miejsce w powyższych przykładach.

for Y := 0 to Height-1 do
  begin
  Linia24 := bmpRGB.ScanLine[Y];
  Linia32 := ScanLine[Y];
  for X := 0 to Width-1 do
    begin
    if PtInRegion(Region, X, Y) then
      Alpha := 0
    else
      Alpha := byte(X xor Y);
    Linia32.rgbRed := MulDiv(Linia24.rgbtRed, Alpha, 255);
    Linia32.rgbGreen := MulDiv(Linia24.rgbtGreen, Alpha, 255);
    Linia32.rgbBlue := MulDiv(Linia24.rgbtBlue, Alpha, 255);
    Linia32.rgbReserved := Alpha;
    inc(Linia32);
    inc(Linia24);
    end;
  end;

Składowa przezroczystości jest wyliczana na podstawie pozycji (X, Y) danego piksela, natomiast kolor jest pobierany z istniejącej już bitmapy 24 bitowej. Rozwiązanie takie pozwala na rysowanie dowolnych kształtów na bitmapie, oddzielonej od kanału przezroczystości. Jest to ważne, ponieważ rysowanie po bitmapie 32 bitowej może powodować, że w miejscach, gdzie dokonano rysowania, na kanale przezroczystości pojawi się czarne (wartość 0) tło, a więc fragment będzie całkowicie przezroczysty, bez względu na to, co na nim namalowano.

Przygotowanie za pomocą Adobe Photoshop

Bitmapę można przygotować w programie graficznym pamiętając, aby zawierała kanał przezroczystości, a zatem była 32 bitowa.

  1. Plik → Nowy → RGB → OK
  2. Warstwa → Nowa.. → OK
  3. Usuwamy warstwę Tło (domyślnie stworzona i nieprzezroczysta)
  4. Rysujemy coś z użyciem normalnym przezroczystości na jedynej teraz warstwie
  5. Kanały → Dodaj nowy kanał → Alpha 1: obszary zamaskowane (kanał jest cały czarny)
  6. Zaznaczenie → Kanał: Przezroczystość warstwy 1
  7. Na samym kanale Alpha 1: Edycja → Wypełnij → Kolor biały
  8. Na warstwie 1 zaznaczamy całą przezroczystość i zamalowujemy na biało - przezroczystość jest teraz tylko na kanale Alpha
  9. Plik → Zapisz jako.. → BMP: Windows, 32 bit (A8R8G8B8)

Przygotowanie za pomocą GIMP

  1. Plik → Nowy.. → OK
  2. Rysujemy coś z użyciem normalnym przezroczystości na jedynej teraz warstwie
  3. Warstwa → Przezroczystość → Dodaj kanał alfa
  4. Warstwa → Przezroczystość → Zmiana koloru w alfę
  5. Wybieramy kolor przezroczystego tła → OK
  6. Zapisz jako -> PNG: odznaczyć wszystko z wyjątkiem Zapisz wartości kolorów dla przezroczystych punktów

Ponieważ GIMP nie obsługuje prawidłowo bitmap 32 bitowych, należy przygotować rysunek PNG i przejść do opisu konwersji PNG na BMP za pomocą Microsoft Paint.

Konwersja PNG do BMP (32 bit) za pomocą Microsoft Paint

Paint nie pozwala na utworzenie od zera bitmapy 32 bitowej. Jednak pozwala na otwarcie obrazu PNG, który posiada odpowiednio - jak pokazano powyżej - przygotowane dane o przezroczystości, a następnie zapisanie za pomocą opcji Zapisz jako: Mapa bitowa 24-bitowa (.bmp;.dib) do pliku bitmapy, w rzeczywistości 32 bitowej (co można sprawdzić we właściwościach pliku, prezentowanych przez system).

Tak przygotowany obrazek można wczytać do komponentu TImage lub obiektu klasy TBitmap, a następnie wykorzystać jako źródło pikseli podczas malowania przezroczystego okna.

Jednak, aby wyglądało poprawnie, trzeba będzie być może dokonać korekcji zakresu składowych R, G, B:

for Y := 0 to Height-1 do
  begin
  Linia32 := ScanLine[Y];
  for X := 0 to Width-1 do
    begin
    Linia32.rgbRed := MulDiv(Linia32.rgbRed, Linia32.rgbReserved, 255);
    Linia32.rgbGreen := MulDiv(Linia32.rgbGreen, Linia32.rgbReserved, 255);
    Linia32.rgbBlue := MulDiv(Linia32.rgbBlue, Linia32.rgbReserved, 255);
    inc(Linia32);
    end;
  end;

Zobacz też:

29 komentarzy

Super, czekam tylko jak ktoś napisze artykuł o uzyskiwaniu takiego efektu w Linuksie (Lazarus, ew. Kylix)

Szczawik dzięki za opieprzenie mnie :> i wyjaśnienie
teraz już rozumiem, nie zauważyłem tej informacji o zakresie kanałów względem alpha(chociaż pewnie zauważyłem, ale nie zwróciłem uwagi i zapomniałem), czyli dla przykładu, jeżeli podam alpha na 0x80, to najbardziej biały kolor jaki mogę uzyskać to piksel o wartości: 0x80808080, w programach graficznych alpha to po prostu poziom przezroczystości wiec nawet mi przez myśl nie przeszło że kanały kolorów są zależne od alpha

w MSDN takiej linijki też nie znalazłem, w której jest informacja, że reszta kanałów to 0..A, a może znalazłem i też nie zwróciłem uwagi tak jak tu :/ chociaż teraz to rozumiem, nawet wynika to ze wzorów podanych przy opisie struktury ALPHABLENDING

ale w dalszym ciągu nie rozumiem dlaczego DrawString powoduje taką dziwną anomalię...
DrawString rysuje Brushem, robie SolidBrusha o wartości koloru 0xffffffff, na przezroczystym oknie chcę mieć biały tekst, w ogóle nie przezroczysty, czyli 0xffffffff(zatem kanały mieszczą się w alphie), no i rysuje, daje tą bitmapę po której rysuję do UpdateLayredWindow, i wizualnie wszystko jest ok, bardzo ładnie to wygląda, tekst narysowany tak jak tego chcę, ale od strony okna Windows coś jest nie tak, bo gdy kliknę na ten piksle który narysował DrawString(), to tak jakbym kliknął na okno pod spodem, czyli pomimo tego, że graficznie piksel widać, to jakimś sposobem, system widzi tam Ralpha na 0, bo wysyła komunikat do okna pod spodem...
W MSDN przy opisie metody DrawString() nie ma za wiele, po prostu rysuje na oknie tekst i oczywiście robi to bardzo dobrze, tyle, że po wysłaniu tej bitmapy jako bitmapa okna, jakoś te piksele które narysowała są niewidoczne od strony technicznej okna, nie potrafię tego wytłumaczyć...
Na dodatek gdy rysuję obraz na tym oknie(jeszcze bitmapie nie wysłanej do (UpdateLayerdWidnow) metodą DrawImage jest dobrze, tylko DrawString to powoduje...

btw. Komentując technikę UpdateLayredWidnow, nie wspominałem nic na temat twojego artykułu, a to najlepszy moim zdaniem art na 4p, no może najlepszy łącznie z artykułami o odtwarzaniu dźwięku na niskim poziomie w dziale C, czyli w dwójce najlepszych artów :>

Jak czyta się bez zrozumienia, to ma się problemy. Zanim zaczniesz wyrażać kategoryczne opinie, najpierw poznaj technologię, która za tym stoi.

RGB(80,80,80) przy A=128 to nie ciemny szary, tylko jasny szary. Kolor RGB(180,180,180) w ogóle jest niepoprawny, bo wychodzi poza zakres, więc modyfikuje przezroczystość - stąd jego dziwny wygląd.

W tekście masz wyraźnie napisane:

Należy pamiętać, że piksel o przezroczystości A powinien mieć składowe R, G, B w zakresie 0..A.

Wynika to z tego, że system przezroczystość musi liczyć szybko - w czasie rzeczywistym, więc wszystkie dane musi otrzymać w formie zoptymalizowanej.

W twoim komentarzu jest jeszcze kilka takich argumentów, które nie wynikają z błędnego działania, ale z Twojej jego nieznajomości (choćby opisane działanie DrawString).

Zanim coś tak skomentujesz, poczytaj więcej.

UpdateLayeredWindow(nie SetLayredAttributes) w Windows to masa problemów, samo obliczanie(mieszanie) AlphaBlendingu jest gówniane, wychodzi kaszana, dla przykładu generuje bitmapę w której wszystkie piksele mają alpha=128(czyli teoretycznie półprzezroczystości), i robię pierwszą linijkę jakimś powiedzmy RGB(80,80,80) - ciemny szarny, i każdą linijkę w dół podnoszę kanały o parę wyżej, że na dole jest jasny szaryRGB(180,180,180), i chociaż alpha na całości wynosi 128, to na dole bitmapy jest słaba przezroczystość, silna biała szarość, gdzie słabo widać co jest za oknem, a na górze tam gdzie ciemniejszy ten szary, alpha blending jest bardzo mocny, w dużym stopniu widać co jest za oknem, a słabo widać wartości kanałów okna, a alpha na całej bitmapie wynosi stałą wielkość(128)...

Przy takiej samej w GIMPie odpowiednik tego co na pulpicie wygląda całkiem inaczej, mieszanie kolorów jest w miarę naturalne, jeżeli alpha blending na całej bitmapie wynosi 128, to widać, że jest na całej bitmapie równe jest mieszanie się kolorów z kolorami pod bitmapą(na całej bitmapie jest równy współczynnik widoczności), nie to co na windowsowym pulpicie, całkiem inne obliczanie, dużo lepsze jest w programach graficznych...

Oczywiście mowa o UpdateLayeredWindow i podkładaniu swojej bitmapy, bo z ustawianiem jednolitego koloru(transparent) przez SetLeyredAttributes) jest inaczej już całkiem przyzwoicie, widać że przenikanie jest takie samo na całym oknie, nie to co przy UpdateLayredWindow...

Poza tym, jak rysuję w GDI+ przez DrawString po bitmapie którą potem dam do UpdateLayredWindow, to wizualnie tekst jest narysowany(piksele narysowane), ale jak kliknę na piksel tekstu(narysowany przez DrawString) to wysyła komunikat do okna pod moim oknem, tak jakby alpha była=0, a piksel zwyczajnie widać, no kompletny bezsens...

Zależy co przez to rozumiesz. Jeśli chcesz zrobić przezroczyste okno i komponenty, ostatnia część opisuje, jak to zrobić. Dowolne określanie jednak samej przezroczystości fragmentów komponentów może nie być możliwe bez samodzielnego rysowania.

da sie te rzeczy przystosować dla zwyklych komponentow?

Tym sposobem możesz oczywiście formie, na której są komponenty, ustawić poziom przezroczystości. Jeśli jeszcze zadbasz, by nie wycinać bitmapy w miejscu komponentów, będą one przezroczyste do bitmapy. Musisz wtedy tylko zadbać o kolejność okien (by bitmapa nie nachodziła na komponenty) i o to, by nawet podczas kliknięcia jednego z nich, nawet na chwilę nie zmieniły kolejności.

Po prostu trzeba pamiętać, że komponenty i bitmapa leżą na osobnych oknach.

Artykuł świetny :)

PS. Są jakieś sposoby na półprzeźroczyste komponenty? :> Np. jak na jakąś narysowaną bitmapę (lub TImage z wczytanym obrazkiem) położe TEdita to, żeby był przeźroczysty podobnie jak w przypadku AlphaBlendingu.

Szczawik jak obiecał, tak zrobił artykuł z tamtego topicu na forum :)

jak to zrobic dla 2 obrazkow jpg zeby przeswitywaly przez siebie????

Bardzo przydatne. Chociaż w nowszych wersjach już jest możliwość w inspektorze ustawieni aprzezroczystosci.

@MikiKam:

nie lepiej:

procedure Alpha(Handle: cardinal; AValue:integer);
begin
  if AValue > 255 then AValue:=255;
  if AValue < 0 then AValue:=0;

  SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
  SetLayeredWindowAttributes(Handle, 0, 254-AValue+1, LWA_ALPHA);
end;

?? :]

Wyjaśnienie: 254-AValue+1 - musi być większe od 0 ponieważ ustawienie Alpha na 0 skutkuje tym samy co ustawienie Visible na false i w rezultacie niemożność interakcji z formularzem

Jeżeli chodzi o AlphaBlend w Inspektorze, to należy dodać, iż właściwość ta występuje jedynie w nowszych wersjach Delphi. Ten tekst przeznaczony jest dla posiadaczy starszych Delphi, prezentując niskopoziomowy sposób osiągnięcia efektu przezroczystości. Gratulacje dla autora.

A nie lepszy efekt taki??

Wstaw Track Bara na forme i nazwij go "psezroczystosc"

wstaw taki kod:

procedure TForm1.TrackBar1Change(Sender: TObject);var a: Integer;
begin
a := 250-trackbar1.Position;
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
SetLayeredWindowAttributes(Handle, 0, a, LWA_ALPHA);
end;

:D Tak chyba lepszy efekt. Mozna wstawic do opcji :P
AHA!! ZApomnialem powiedziec ze wstaw do Track Bara maxymalna wartosc 225!!!

Lubię takie konkrety :)

ŁK:
Przezroczysty i przeźroczysty - oba są dobrze.

przeZroczysty, a nie przeŹroczysty - tak na przyszłość

Ja mam tylko 2 ALE... po pierwsze serwis nie nazywa się 4programer.net :p a po drugie taki kod wywala na systemie młodszym niż win 2000 nie ciekawy błąd, więc mogłeś napisać jeszcze jak wykonać ten kod tylko na odpowiednich windowsach :P Ale jak na pierwszy raz to jest OK :D

Tak jest, czekamy na następny artykuł - tylko napisz taki, żebym mógł 6 wystawić :>

witam, wiem że nie opisałem za dużo rzeczy. Ale liczą się chęci jak ktoś wspomniał.To jest mój pierwszy art, na następny raz zapamiętam wasze uwagi i wszystko zapisze. :D

@Ktos: dokladnie - wlasnie robie program ktory ustawia polprzezroczystosc menu :]

Przydałby się jakiś (nawet pobierzny) opis funkcji SetLayeredWindowAttributes i RedrawWindow i użytych paramtrów. A za dobre chęci masz 5.

Przecież zostawiłem sobie furtkę - napisałem, że kod przyda się GŁÓWNIE im, ale niekoniecznie tylko im :)

brodny: Niekoniecznie. Teoretycznie można by to było użyć aby dowolnemu oknu, którego znamy uchwyt nakazać AlphaBlending - to by moglo być ciekawe :)

Zresztą od Delphi 6 lub 7 mamy właściwości formy odpowiedzialne za Alpha Blending w tych systemach - kod przyda się głównie posiadaczom starszych wersji środowiska.

Na ME i NT nie chodzi. Tylko NT 5.0 i wyżej (2000, XP, 2003, Vista).

To 127 w linijce SetLayeredWindowAttributes(Handle, 0, 127 , LWA_ALPHA); to "wartość" (poziom) przeźroczystości. Można by to było napisać..

  1. no dlugi art to to nie jest... :P
  2. bylo :)
  3. "możliwe że na ME też nie chodzi" - ME nie jest z tej rodziny :]
  4. Longhorn i Vista to rozne systemy? :o nie wiedzialem... :]

a nie lepiej AlphaBlend w Object Inspectorze??