Link to home
Start Free TrialLog in
Avatar of eYes
eYes

asked on

how to retrieve desktop background under current form while form resize or moved or background changed?

Hi friends
I want to know how to retrieve desktop background under current form while form resize or moved or background changed?
Avatar of simonet
simonet
Flag of Brazil image

Can you elaborate a little more on what you're trying to achieve?

Alex
Avatar of koger
koger

This will capture the desktop

procedure TForm1.Button1click;
var
  DeskTopDC: HDc;
  DeskTopCanvas: TCanvas;
  DeskTopRect: TRect;
begin
  DeskTopDC := GetWindowDC(GetDeskTopWindow);
  DeskTopCanvas := TCanvas.Create;
  DeskTopCanvas.Handle := DeskTopDC;
  DeskTopRect := Rect(0,0,Screen.Width,Screen.Height);
  Form1.Canvas.CopyRect   (DeskTopRect,DeskTopCanvas,DeskTopRect);
  ReleaseDC(GetDeskTopWindow,DeskTopDC);
end;
Avatar of eYes

ASKER

sorry, I want to know the Background UNDER current form,
exclude the form itself.
The answer you gave me can retrieve all the desktop (include the form itself) on the screen, not my needed.

I tried SetWindowRgn to set the current form's region to a rect of (0, 0, 1, 1) and RedrawWindow(GetDesktopWindow, nil, 0, RDW_ERASE or RDW_INTERNALPAINT or RDW_INVALIDATE) and copy the desktop bitmaps then reset the current form's Region back.
Unfortunatily, it can get only part of the background, except I sleep(100)--sleep(1000) after RedrawWindow.

the codes like this:
procedure TForm1.Wndproc(var Message: TMessage);
var
  DC: HDC;
  APoint: TPoint;
  ARect: TRect;
  ARegion: HRGN;
begin
  if Message.Msg = WM_MOVE then
  begin
    ARegion := CreateRectRgn(0, 0, 1, 1);
    APoint := ClientToScreen(point(Image1.left, Image1.Top));
    GetWindowRect(Form1.Handle, ARect);
    SetWindowRgn(Form1.Handle, ARegion, True);
    RedrawWindow(GetDesktopWindow, @r, 0, RDW_ERASE or RDW_INTERNALPAINT or RDW_INVALIDATE or RDW_ALLCHILDREN);
    sleep(1000);  // if without this line, cant get correct background
    DC := GetDC(GetdesktopWindow);
    with Image1.Picture.Bitmap do
    begin
      Width := Image1.Width;
      Height := Image1.Height;
      BitBlt(Canvas.Handle, 0, 0, Width, Height, DC,
                        APoint.x, APoint.y, SRCCOPY);
    end;
    ReleaseDC(DC);
    SetWindowRgn(Form1.Handle, 0, true);
    DeleteObject(ARegion);
  end;
  Inherited;
end;

What else can I do?

Why do you need this? Just a q'n.

If you want to make your form 'transparent' then there are other ways to do this.
Avatar of eYes

ASKER

I want a gradient and "half" transparent form.
eYes,
mmmm, don' know about the gradient but transparency is already told lots of times at E-E. just do a search in the previously asked questions. It's not that hard.

Also, ever visited : http://www.lawrenz.com/coolform/index.htm ?

Zif.
mmm, about gradient :

Make form 'half' transparent, and then put a semi-transparent (how?) gradient as the form background.... this might could do it...

Zif.
Avatar of eYes

ASKER

yeah, semi-transparent. sorry for my bad English.
I want a semi-transparent form.
Any other way to do so except getting the desktop bitmap covered by current form?
I can get the background while form creating. but if user moved or resized the form, or, if there's an animation in another window below mine, how can i retrieve the correct background covered by my form?
Avatar of eYes

ASKER

yeah, semi-transparent. sorry for my bad English.
I want a semi-transparent form.
Any other way to do so except getting the desktop bitmap covered by current form?
I can get the background while form creating. but if user moved or resized the form, or, if there's an animation in another window below mine, how can i retrieve the correct background covered by my form?
eYes, you don't need to get the background behind your form!

put this in your code :

private
            procedure CreateParams(var Params: TCreateParams); override;
            procedure WMERASEBKGND(var msg : TMessage); message WM_ERASEBKGND;

procedure TForm1.CreateParams(var Params : TCreateParams);
       begin
       inherited CreateParams(Params);
         Params.ExStyle := Params.ExStyle or WS_EX_TRANSPARENT;
       end;

       procedure TForm1.WMERASEBKGND(var msg : TMessage);
       begin
         msg.Result := 1;
       end;

But, also look at CoolForm. This gives you more flexibility!

Zif.
Avatar of eYes

ASKER

thank you zif. I'll try.
but I think it's no use.
coz i'm writting a component, I cant directly override parent form's CreateParams.
I used following code to instead(It should be same effect as override form's CreateParams I think):
  SetWindowLong(Parent.Handle, GWL_EXSTYLE, GetWindowLong(Parent.Handle,GWL_EXSTYLE) or WS_EX_TRANSPARENT);
  SendMessage(Parent.Handle, CM_RECREATEWND, 0, 0);
but it's no useful. I can only get a blank background from the form while form repaint.
eYes,

You're writing a component? Now, I can't follow anymore, I thought you wanted a 'semi-transparent' form. Please explain.

Zif.
Avatar of eYes

ASKER

yes, a semi-transparent form.
this component herited from TGraphicControl. u can put it on the form and set it's align to alClient. the component's bitmap is desktop's graphic under the form. so the form looks like semi-transparent. ofcoz u can set the form's part semi-transparent if not align to client.
eYes, it seems your major problem is that the desktop window isn't updated immediately, right? In the source code you gave I can't see the flag RDW_UPDATENOW. This flag will ensure that the entire region, including overlapping windows, is redrawn before the function returns. Does this solve the problem?

Ciao, Mike
Avatar of eYes

ASKER

I've already tried RDW_ERASENOW, RDW_UPDATENOW, but no use.
It seems that Desktop's painting thread has lower priority, and it's repainting always interrupted by other threads.
Does it have any way to know if desktop window has finished it's repainting?
Don't you think it slows down if you want to repaint the background everytime your form is moved an itsiebit?
Despite that I agree with ZifNab, RDW_UPDATENOW should not call any thread but directly go to the window's message procedure. I wonder why it does not work, but you can try to call UpdateWindow(). I debugged this down to the API and learned that an UpdatWindow() call will directly go to the message proc. To my knowledge there's no way to get notified when the desktop has finished its painting (I needed this feature too when I implemented an OpenGL window with a "transparent" background).

Ciao, Mike
Avatar of eYes

ASKER

Yes, I think so. The form will flash while it is moved or resized, but I think it's better than the form disappeared  for about one second when it moved. I found a "semi-transparent form" component on the web, it set visible to false and sleep(300) after the form moved, and in it's readme the author suggests that you better change the sleep periods by yourself in order to fit your machine.
I can't believe MS doesn't offer a way to get the background under a window, maybe some undocumented API?
I've written several semi-transparent panels. they all refresh smoothly. Now I want a translucent form.
Can you help me?

ASKER CERTIFIED SOLUTION
Avatar of Dekaabo
Dekaabo

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of eYes

ASKER

have u tested it?
I cant only get part background sometime and  get blank bitmap most time.
i tested it in an onclick-event of an normal button.
sometimes i also get just a bitmap with the background color of the window (clbuttonface), but i don´t know why.
maybe try a little loop before you do the BitBlt-action.