[help] Coders, Please Help A ****ie :-)

Hy.

I'm trying to make a little application that shows some semi transparent PNG images on the screen. I've tried with GDI+ since it's quite easy to use and has a function for loading PNG files.

My problem is, for now all i managed to do is to show a semitransparent PNG on the main window of my application (using the WM_PAINT message), but i would like to make the entire application be only the semitransparent PNG image (like for example the ObjectDock, or RainLander).

If anybody can point me to a simple application that can do this (so i can extend on it) i would be more than happy :D

:smartass: I've found something similar on CodeProject (it's called "Per Pixel Alpha Blend"), but that's example uses some custom libraries, and i would really like to use GDI+ (since it's included in all WinXP and over)

Thanx in advance.

---------------------------------

Help threads need [Help] tags ;)

The Topic Has Been Tagged

// Seph

#180361

You need to define the WS_EX_LAYERED exstyle for your window. A layered window doesn't send you WM_PAINT messages, you'll need to provide it a bitmap to show.

Then you can use a code snippet to set a GDI+ Bitmap for the window.

// errorchecking/handling code omitted
UINT BitmapIntoLayeredWindow(HWND hWnd, Bitmap& bmp)
{
 HDC screenDC( GetDC(0) );
 POINT sourcePos = {0};
 HDC sourceDC( CreateCompatibleDC(screenDC) );

 HBITMAP bufferBitmap = {0};
 bmp.GetHBITMAP(0, bufferBitmap);

 HBITMAP oldBmpSelInDC ( SelectObject(sourceDC, bufferBitmap) );

 // left and top are the x,y-pos where your window will be shown
 POINT pos = {Left, Top};
 SIZE  size = {bmp.GetWidth(),bmp.GetHeight()};

 BLENDFUNCTION blendFunction = {0};
 blendFunction.blendOp = AC_SRC_OVER;
 blendFunction.SourceConstantAlpha = 255;
 blendFunction.AlphaFormat = AC_SRC_ALPHA;

 COLORREF colorKey( RGB(255,0,255) );
 DWORD flags( ULW_ALPHA);

 UINT res = UpdateLayeredWindow(hWnd, screenDC,
 &pos, & size,
 sourceDC, &sourcePos,
 colorKey, &blendFunction, flags
 );

 SelectObject(sourceDC, oldBmpSelInDC);
 DeleteObject(bufferBitmap);
 DeleteDC(sourceDC);
 
 ReleaseDC(0, screenDC);

 return res;
}

#180919

Hy.

Just one question,

since there's no WM_PAINT message, whenever i want to change the image of the window i call the BitmapIntoLayeredWindow function ?

(for example if i make a weather app and the weather data changes, i'll create the new bitmap and draw it with the above function ? )

Thanx for your help (and specially for the code sample :D )

#180925

since there's no WM_PAINT message, whenever i want to change the image of the window i call the BitmapIntoLayeredWindow function ?

Yep. Btw, you can control the transparency by setting blendFunction.SourceConstantAlpha to another value (ranges from 0 to 255)

BLENDFUNCTION blendFunction = {0};
blendFunction.blendOp = AC_SRC_OVER;
blendFunction.SourceConstantAlpha = 255;
blendFunction.AlphaFormat = AC_SRC_ALPHA;

#180929

Andreas

i try your code snippet but... no luck :(

if i try SetLayeredWindowAttributes to set transparency - its work but with UpdateLayeredWindow - not...

function BitmapIntoLayeredWindow(hwnd: HWND; bmp: TBitmap): boolean;
var
screenDC, sourceDC: HDC;
sourcePos, pos: TPoint;
oldBmpSelInDC, bufferBitmap: HBITMAP;
blendF: BLENDFUNCTION;
colorKey: COLORREF;
flags: DWORD;
siz: SIZE;
res: boolean;
begin
screenDC := GetDC(0);
sourcePos.x := 0;
sourcePos.y := 0;
sourceDC := CreateCompatibleDC(screenDC);

bufferBitmap := bmp.handle;

oldBmpSelInDC := SelectObject(sourceDC, bufferBitmap);

// left and top are the x,y-pos where your window will be shown
pos.x := 100;//Left;
pos.y := 100;//Top;

siz.cx := bmp.width; //{bmp.GetWidth(),bmp.GetHeight()};
siz.cy := bmp.Height;

blendF.blendOp := AC_SRC_OVER;
blendF.SourceConstantAlpha := 128;
blendF.AlphaFormat := AC_SRC_ALPHA;

colorKey := RGB(255,0,255);
flags := ULW_ALPHA;

// res := UpdateLayeredWindow(hWnd, screenDC, @pos, @siz, sourceDC, @sourcePos,
// colorKey, @blendF, flags);
SetLayeredWindowAttributes(hwnd, 0, 128, LWA_ALPHA);

SelectObject(sourceDC, oldBmpSelInDC);
DeleteObject(bufferBitmap);
DeleteDC(sourceDC);

ReleaseDC(0, screenDC);

result := res;
end;

a code is from snippet. only adapted to Pascal... am i miss something?

PS

its Delphi...

#253124

SetLayeredWindowAttributes cannot be used if you use UpdateLayeredWindow.

#254111

i know.

but ( '//' is "comment" :) you know ;) )

this work for me - windows become transparent

// res := UpdateLayeredWindow(hWnd, screenDC, @pos, @siz, sourceDC, @sourcePos,
// colorKey, @blendF, flags);
SetLayeredWindowAttributes(hwnd, 0, 128, LWA_ALPHA);

and this not :( window is invisible at all...

res := UpdateLayeredWindow(hWnd, screenDC, @pos, @siz, sourceDC, @sourcePos,
colorKey, @blendF, flags);
//SetLayeredWindowAttributes(hwnd, 0, 128, LWA_ALPHA);

#255537

i found this on internet

To make a form transparent you should put these 2 lines in form's creation procedure:



procedure TForm1.FormCreate(Sender: TObject);

begin

Form1.Brush.Style:=bsClear;

Form1.BorderStyle:=bsNone;

end;



If you use only that you will notice that the form is transparent but if you put something

over it, it will not clear its own background and traces of that object will be left on the

form. To solve that you need to make sure that the transparent form's Paint procedure (WM_PAINT)

will be called last. To do that you need to override the TWinControl (TForm's ancestor)

CreateParams procedure and set the Form's extended style (ExStyle) to WS_EX_TRANSPARENT.



Here's the full code for making a form transparent:



type

TForm1 = class(TForm)

procedure CreateParams(var Params:TCreateParams); override;

procedure FormCreate(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;



var

Form1: TForm1;



implementation



{$R *.DFM}



procedure TForm1.CreateParams(var Params:TCreateParams);

Begin

inherited CreateParams(Params);

Params.ExStyle:=WS_EX_TRANSPARENT;

End;



procedure TForm1.FormCreate(Sender: TObject);

begin

Form1.Brush.Style:=bsClear;

Form1.BorderStyle:=bsNone;

end;

but it still not working properly, if i just use Form1.Brush.Style:=bsClear; there will be some traces of objects on the form.

#257274

there more stylish solution here :)

http://www.aqua-soft.org/board/showthread.php?t=23081

and make form just transparent is simple. it was hard to draw a form like AveDesk do :) - transparent png-as-form. see above link for sample. it works.

now im looking how to put a controls on such form... have i draw it myself? simply create a button oh such form doesn't work or works but button is not visible... reading net/msdn for this...

#257282

The works fine in Delphi unless we put some components like Button or Panel ,etc.

They will be all disappear. how can we show some components after redraw ?

I am beginner so plz give me a simple example

I appreciate that

#264047

NilColor, my friend, try this snippet. Some long time ago I asked AVe for help on those nice transparent windows. This is what I use in a few Delphi Projects now:

function GDIPlusBitampIntoLayeredWindow(frm:Tform;bmp:TGPBitmap):Integer;

var

winLong:Cardinal;

ABlendFunction:Blendfunction;

AScreenDC,ASourceDC:HDC;

ASourcePosition,FPosition:TPoint;

FSize:TSize;

ABufferBitmap,AOldBitmapSelectedInCanvasDC :HBitmap;

FColorKey:TColor;

FFlags:DWORD;

res:Integer;

begin

(*

Conditions:

pre: bmp is not nil, frm is not nil.

post: TRUE has been returned iff the bitmap has been set to the

window, otherwise, FALSE has been returned.

*)

if (frm = nil)or(bmp = nil) then

begin

GDIPlusBitampIntoLayeredWindow := 0;

end

else

begin

(* ensure we are dealing with a layered window by setting

the window exstyle to WS_EX_LAYERED *)

winLong:=GetWindowLong(frm.Handle,GWL_EXSTYLE);

winLong:= winLong or WS_EX_LAYERED;

SetWindowLong(frm.Handle,GWL_EXSTYLE,winLong);



{Added by RIMMER

ULW consumes only 32bit bitmaps with PREMULTYPLIED alpha.

GDI+ can do it automatically through the following code}

If bmp.GetPixelFormat <> PixelFormat32bppPARGB then begin

bmp:=bmp.Clone(0,0,bmp.GetWidth,bmp.GetHeight,PixelFormat32bppPARGB);

end;

{end of Added by RIMMER}



(* create a device context compatible with the screen *)

AScreenDC := GetDC(0);

ASourceDC := CreateCompatibleDC(AScreenDC);



(* get a HBITMAP from the GDI+ bitmap *)

bmp.GetHBITMAP(0, ABufferBitmap);



(* select it into the device context we have just created *)

(* we don't forget to save the old bitmap that was selected in the dc, *)

(* otherwise, we will have a GDI mem-leak *)

AOldBitmapSelectedInCanvasDC := SelectObject(ASourceDC, ABufferBitmap);



(* set up source position *)

ASourcePosition.x := 0;

ASourcePosition.y := 0;



(* set up a blendfunction structure to pass to ULW *)

ABlendFunction.BlendOp := AC_SRC_OVER;

ABlendFunction.BlendFlags := 0;

ABlendFunction.SourceConstantAlpha := 255;

ABlendFunction.AlphaFormat := AC_SRC_ALPHA;



(* set up x,y pos and size *)

FPosition.X := frm.Left;

FPosition.Y := frm.Top;

{Corrected by RIMMER

TSize doesn't have Width and Height members, but cx and cy instead}

FSize.cx :=bmp.GetWidth();

FSize.cy := bmp.GetHeight();

{end of Corrected by RIMMER}



(* not used colorkey, because we use the hbitmaps native *)

(* per-pixel alpha level *)

FColorKey := RGB(255,0,255);

FFlags := ULW_ALPHA;



(* call the ULW api that copies or hbitmap derived from the *)

(* GDI+ bitmap to the screen content *)

{Corrected by RIMMER

UpdateLayeredWindow is declared to return BOOL in Delphi,

so we return -1 if it returns True (ie OK), ... }

if UpdateLayeredWindow(frm.Handle, AScreenDC,@FPosition,

@FSize,

ASourceDC,

@ASourcePosition,

FColorKey,

@ABlendFunction,

FFlags

)

then res :=-1

{... and the code of last error if it fails.}

else res:=GetLastError;

{end of Corrected by RIMMER}



(* clean up used GDI objects *)

SelectObject(ASourceDC, AOldBitmapSelectedInCanvasDC);

DeleteObject(ABufferBitmap);

DeleteDC(ASourceDC);

ReleaseDC(0, AScreenDC);



GDIPlusBitampIntoLayeredWindow := res;



end;

end;

#264068

Thanx RIMMER for the reply

Still cant understand how can we show other components like Button etc,

when we use this function

could you plz tell me how do you do that urself?

#264110

My previous post is to solve the ****ies' problem when just loaded pngs dont work.

About controls: You'll have to draw them by yourself over the bitmap OR there's another way: the controls are contained on the another form with the same size and position as the layered one. But the second form is not layered. When this second form is built, you create a region for it (do you know what regions are?) which consists of the rectangles of visible controls. The second form is always to be on top of the first one, you'll have to control it by yourself, as well as to set the focus to the second form, when user clicks somewhere in the first one. Also you'll have to move both forms simultaneously when user tries to drag only one of them, to make us think this is still one beautiful form. And this is just a top of iceberg, I think.

In my current projects I don't rely on Delphi VCL at all. The controls which are few in number are all somewhat unique not found in standard Windows GUI. The menu popups for example are the most nicest and lightest things to make without VCL. Did you see those beautiful semitransparent shadowed menu popups with stem over the Dock of divine Macs? Try make it, you should like...

#264412

NilColor, my friend, try this snippet. Some long time ago I asked AVe for help on those nice transparent windows. This is what I use in a few Delphi Projects now:

Hi RIMMER! :D

How your McBar lives? ;)

Thanks for code. Now i know how to make a GDI+ usable bitmap :cool:

Check my new "project" -> iMinimize ;)

http://www.aqua-soft.org/board/showthread....3691#post263691

Edit:

Oh, can show me a menus you are talking about?

Screenshot or .exe ;)

#264594