[Delphi] PNG jako tlo aplikacji

0

Temat juz byl chyba poruszany ale efekty dalej mnie nie satysfakcjonuja, dlatego pytam. Doszedl ktos do tego jak zrobic forme o wygladzie jakiegos pliku PNG z obsluga kanalu alpha (transparency,alpha channel < tak zeby wyszukiwarka znalazla ;p). Widzialem sporo aplikacji z obsluga tego, jest to dosc szybki sposob na stworzenie czegos w rodzaju Aero-Like ;)

Moze jakies komponenty, nawet platne, byle w miare lekkie dla aplikacji.
I nie pisac mi prosze o PNGImage bo dobrze wiem ze trzeba go uzywac.
Udalo mi sie cos stworzyc z Graphic32 i PNGimage jednak wciaz daleko do idealu...
Pozdrawiam

0

Właściwie PNG w ogólne nie jest potrzebne - wystarczy bitmapa 32bitowa.

http://4programmers.net/Forum/277695

0

na bitmapie 32bitowej zrobie efekt przezroczystosci ?
edit. Ok poradzilem sobie ale jak teraz zrobic by widac bylo komponenty np buton, memo, cokolwiek. Nic nie widac :)

0

Poczytaj sobie powyższy link, tam było to już omawiane.

0

tak, tam jest o 2 formach lub rysowaniu labeli a co jesli chce miec butttona i inne nie statyczne elementy?

0
Szczawik napisał(a)
Andre napisał(a)

Czy da się jeszcze poprawić ten kod, żeby je było widać?

Bezpośrednio tą metodą nie, gdyż bitmapa definiuje wygląd każdego pikselka - RGB oraz przeźroczystość, ale można pośrednio: najpierw na bitmapie narysować treść: zrobić choćby zrzut z formy, z kolorem tła jako przezroczystym, a potem to ustalić za obraz okna.

Jak chcesz mieć inne kontrolki, to albo je rysujesz, albo rezygnujesz ze stopniowanej przeźroczystości i.. :
a) dajesz dla formy stałą wartość przezroczystości (AlphaBlendValue)
b) kształt formy wycinasz za pomocą regionów.

Przy takim podejściu forma będzie miała tylko 2 wartości przezroczystości - stałą oraz zerową.. oraz twoje kontrolki. Ale nie osiągniesz tak przezroczystości stopniowanej (czyli na przykład: część widoczna 100%, część 50%, a część wycięta i nie widoczna wcale).

0

rysowac? a jak je potem obsluzyc? moze jakis przyklad, szkoda ze nie ma jakiejs prostszej opcji na uzyskanie tej przezroczystosci

0
DriveX napisał(a)

rysowac? a jak je potem obsluzyc?

hehe
ja tego szukam juz bardzo dlugo
oczywiscie Szczawik bardzo ulatwil nam sprawe podajac poprzednie rozwiazanie
lecz to jeszcze nie to czego poszukuje
a ja niestety jestem zaslabym amatorem/programista aby cos takiego napisac
pozdrawiam

//wiem ze moj post nieczego nie wnosi ale mialem nieodparta chec odpisanaia na ten post

0

To co przychodzi mi na myśl to zrobienie 2 okien - 1 na wierzchu z przezroczystościami i wyciętymi całkowicie kształtami na kontrolki okna pod spodem, które ma stałą widoczność.

To taki pomysł na szybko, aby uniknąć rysowania.

0

2 formy to znowu wiecej kB w exeku, szkoda ze nikt nie stworzyl odpowiedniej biblioteki ani komponentu do tego by bez problemu mozna bylo postawic png/bmp z kanalem alpha i mozliwoscia stawiania innych kontrolek

0

Więcej KB w Exe? A po co? Skoro okno, które będzie przezroczyste bez komponentów może być dynamicznie tworzone i usuwane (kilka linii w WinAPI), a nie trzymane jako zasób w aplikacji.

Nie stworzono takiej funkcjonalności z bardzo oczywistego powodu: otóż zastosowanie komponentów wymaga, aby system odmalowywał ich wygląd, gdy zmieni się ich stan. Natomiast przeczy to całkowicie idei technologii LayeredWindow, która pozwala na stopniowanie przezroczystości - jest to okno w postaci obrazu, na którego wygląd system nie ma wpływu - może je jedynie przeliczać jako statyczną bitmapę, a od aplikacji zależy kiedy zostanie zmieniony jej wygląd.

Takie podejście przesuwa odpowiedzialność za wygląd w 100% na aplikację - więc doskonale nadaje się dla wszystkich aplikacji wspierających skórki (choćby Winamp lub WMP) i bajerancki wygląd. Za to utrudnia programowanie ładnych graficznie aplikacji ze standardowymi kontrolkami - ale te są znacznie rzadsze.

0

Czyli mowisz zeby zrobic 2 formy;

Form_1:
Transparenta, na niej buttony + inne kontrolki

Form_2:
LayeredWindows
Skorka z BMP32
Procka ktora "przesuwa" forme1 pod Forma2 razem z zawartoscia.

Tak to rozumiem :)

0

Tak, tylko, że Form2 może być stworzona przez Winapi, a nie być formą w VCL Delphi. Natomiast Form1 nie musi być transparentna (choć może i mieć ustawione AlphaBlendValue). To BMP32 zapewni górnej Form2 przezroczystość w określonych miejscach.

0

Kurcze probuje i probuje i jako ze forme potrafie w winapi zrobic to wyswietlic layeredwindows, obrazka juz nie, moglbys mi pomoc jakims kodem ? na maila albo tu obojetne. Dzieki pozdro

0

Stwórz aplikację z Form1 i kilkoma komponentami (ja testowałem z przyciskiem - Application.Terminate w jego akcji - oraz z ListView) dodatkowo dorzuć Image1 (Visible=False), do którego wczytaj 32 bitową bitmapę.

Całość działań jest obsługiwana takim kodem:

unit Unit1;

interface

uses Windows, Forms, MEssages, Graphics, Controls, ExtCtrls, StdCtrls, Classes, ComCtrls;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    Button1: TButton;
    Image1: TImage;
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { ***** Do obsługi okna przezroczystego ***** }
    Wnd: TWndClass;
    Hnd: THandle;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TLinia32 = array[WORD] of TRGBQuad;
  PLinia32 = ^TLinia32;
  TLinia24 = array[WORD] of TRGBTriple;
  PLinia24 = ^TLinia24;
  TLinia8 = array[WORD] of byte;
  PLinia8 = ^TLinia8;

{ ***** Narysowanie obrazu okna przezroczystego z Image1, uwzględniając w bitmapie rejon z zaznaczonymi komponentami ***** }

procedure PaintLayeredWindow(Image1:TImage; Hnd:THandle; Region:HRGN);
var blend:BLENDFUNCTION;
    P:TPoint;
    S:TSize;
    i,j:integer;
    bmpRGB, bmpA:TBitmap;
    Linia8:PLinia8;
    Linia24:PLinia24;
    Linia32:PLinia32;
begin
//Tworzenie warstw RGB oraz A
bmpRGB:=TBitmap.Create();
bmpRGB.Width:=Image1.Width;
bmpRGB.Height:=Image1.Height;
bmpRGB.PixelFormat:=pf24bit;
bmpA:=TBitmap.Create();
bmpA.Width:=Image1.Width;
bmpA.Height:=Image1.Height;
bmpA.PixelFormat:=pf8bit;
//Rozdzielenie Image1.Picture.Bitmap RGBA na RGB oraz A
for j:=0 to Image1.Height-1 do
  begin
  Linia8:=bmpA.ScanLine[j];
  Linia24:=bmpRGB.ScanLine[j];
  Linia32:=Image1.Picture.Bitmap.ScanLine[j];
  for i:=0 to Image1.Width-1 do
    begin
    if PtInRegion(Region, i, j) then
      Linia8[i]:=0
    else
      Linia8[i]:=Linia32[i].rgbReserved;
    Linia24[i].rgbtBlue:=Linia32[i].rgbBlue;
    Linia24[i].rgbtGreen:=Linia32[i].rgbGreen;
    Linia24[i].rgbtRed:=Linia32[i].rgbRed;
    end;
  end;
//Rysowanie po warstwie RGB lub A
bmpRGB.Canvas.Font.Style:=[fsBold];
bmpRGB.Canvas.Brush.Style:=bsClear;
bmpRGB.Canvas.TextOut(10,10,'TEST');
//Sklejenie RGB oraz A
with TBitmap.Create() do
  begin
  Width:=Image1.Width;
  Height:=Image1.Height;
  PixelFormat:=pf32bit;
  for j:=0 to Height-1 do
    begin
    Linia8:=bmpA.ScanLine[j];
    Linia24:=bmpRGB.ScanLine[j];
    Linia32:=ScanLine[j];
    for i:=0 to Width-1 do
      begin
      Linia32[i].rgbRed := MulDiv(Linia24[i].rgbtRed, Linia8[i], 255);
      Linia32[i].rgbGreen := MulDiv(Linia24[i].rgbtGreen, Linia8[i], 255);
      Linia32[i].rgbBlue := MulDiv(Linia24[i].rgbtBlue, Linia8[i], 255);
      Linia32[i].rgbReserved := Linia8[i];
      end;
    end;
  P := Point(0, 0);
  S.cx := Image1.Width;
  S.cy := Image1.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);
  Free;
  end;
bmpA.Free;
bmpRGB.Free;
end;

{ ***** Obsługa komunikatów okna przezroczystego, z przeciąganiem po kliknięciu włącznie ***** }

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(Form1.Handle, 0, Rect.Left, Rect.Top, 0, 0, SWP_NOSIZE);
    Result := DefWindowProc(Wnd, uMsg, wPar, lPar);
    end;
  end;
end;

{ ***** Utworzenie okna przezroczystego i wycięcie wg. komponentów okna nieprzezroczystego ***** }

procedure TForm1.FormShow(Sender: TObject);
var Region:HRGN;
    ComponentRegion:HRGN;
    i:Integer;
begin
Region:=CreateRectRgn(0, 0, 0, 0);
for i:=0 to ControlCount-1 do
  if Controls[i].Visible then
    begin
    ComponentRegion:=CreateRectRgn(Controls[i].Left, Controls[i].Top, Controls[i].Width+Controls[i].Left, Controls[i].Height+Controls[i].Top);
    CombineRgn(Region, Region, ComponentRegion, RGN_OR);
    DeleteObject(ComponentRegion);
    end;
with Wnd do
  begin
  lpfnWndProc := @WndNewProc;
  hInstance := hInstance;
  lpszClassName := 'My1stApp';
  hbrBackground := COLOR_WINDOW;
  end;
Windows.RegisterClass(Wnd);
Hnd:=CreateWindowEx(WS_EX_LAYERED, 'My1stApp', PChar(Form1.Caption), WS_VISIBLE, Form1.Left, Form1.Top, Form1.Width, Form1.Height, Form1.Handle, 0, hInstance, NIL);
PaintLayeredWindow(Image1, Hnd, Region);
SetWindowRgn(Handle, Region, TRUE);
DeleteObject(Region);
end;

{ ***** Zamknięcie aplikacji ***** }

procedure TForm1.Button1Click(Sender: TObject);
begin
Application.Terminate;
end;

end.

Jeśli kontrolki mogą dynamicznie zmieniać miejsce lub rozmiar, albo częściowo pokazują tło pod spodem (tak jak TLabel), należy trochę więcej nakombinować (Label można wypisać na obrazku).

Z tego tematu postaram się napisać wskazówkę do FAQ albo nawet całego arta, tylko najpierw chętnie poznam wasze zdanie i opinie na ten temat.

0

No fajnie fajnie, coraz lepiej. Ale brak obslugi stylow XP. Po dodaniu manifesta butony i wszystko przestaje byc widoczne i nie da sie kliknac. Niektore komponenty maja jakies tlo niepotrzebne :) zaraz zobacze co na to Transparency.

A na tego arta to bylbym chetny bo ten temat jest juz szeroko omawiany a ciagle nie ma dobrego wytlumaczenia i prostego sposobu ktory po prostu dziala :)

btw. thx

edited. ta funkcja do wycinania tych kontrolek nie dziala tak jakos jak powinna, pojawia sie dziura w formie i kontrolki sa przesuniete w dol o parenascie pixeli oraz od lewej +5 px.

edited2. lekka poprawka do kodu

  if Controls[i].Visible then
    begin
    ComponentRegion:=CreateRectRgn(Form1.Controls[i].Left, Form1.Controls[i].Top, Controls[i].Width+Controls[i].Left, Controls[i].Height+Controls[i].Top);
    CombineRgn(Region, Region, ComponentRegion, RGN_or);
    DeleteObject(ComponentRegion);
    Controls[i].Top:=Controls[i].top - 24;
    Controls[i].left:=Controls[i].left - 4;
    end;
0

Żadnego przesunięcia nie trzeba uwzględniać i Twoja poprawka nie jest potrzebna, ale Form1.BorderStyle trzeba obowiązkowo ustawić na bsNone; zapomniałem wspomnieć. Wtedy nie ma żadnego tła (chyba, że jest częścią prostokątnego obszaru komponentu), wszystko można kliknąć i jak na razie nie wychwyciłem żadnych błędów - testując zarówno na stylach standardowych XP, jak i na doinstalowanych przeze mnie.

Wszędzie działa mi OK. Bez problemu działają style.

Działa nawet Form1.AlphaBlendValue ustawiony na półprzezroczystość.

0

Tak masz racje, jak sie da bsnone to juz nie trzeba nic korygowac, dzieki za kod. Pomogles mi niesamowicie <piwo> :)

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