Mirror

Create a transparent form using regions (Views: 709)


Problem/Question/Abstract:

When I override the CreateParams method of the TForm class and put an "or" clause to include a WS_EX_TRANSPARENT effect, all work fine. My Form appears with a transparent effect (or better, it does not appear. Only controls appear). But if I change the icons positions on the Desktop screen, my form does not get the changes and redraws itself. Well, I call redraw manually, but the form cannot get the desktop screen rectangle to correct the background of the form. How do I solve this problem? Is there a way to get a selected rectangle of the desktop screen to be copied to the canvas on the form?

Answer:

Here's a transparent form method that uses regions. It's so transparent, you can click right through to the underlying windows:

unit Unit1;

{The transparent form effect is done with regions. First create a region that encompasses the entire form. Then, find the client area of the form (Client vs. non-Client) and combine with the full region with RGN_DIFF to make the borders and title bar visible.  Then create a region for each of the controls and combine them with the original (FullRgn) region.}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    Button2: TButton;
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    { Private declarations }
    procedure DoVisible;
    procedure DoInvisible;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  FullRgn, ClientRgn, CtlRgn: THandle;

implementation

{$R *.DFM}

procedure TForm1.DoInvisible;
var
  AControl: TControl;
  A, Margin, X, Y, CtlX, CtlY: Integer;
begin
  Margin := (Width - ClientWidth) div 2;
  {First, get form region}
  FullRgn := CreateRectRgn(0, 0, Width, Height);
  {Find client area region}
  X := Margin;
  Y := Height - ClientHeight - Margin;
  ClientRgn := CreateRectRgn(X, Y, X + ClientWidth, Y + ClientHeight);
  {'Mask' out all but non-client areas}
  CombineRgn(FullRgn, FullRgn, ClientRgn, RGN_DIFF);
  {Now, walk through all the controls on the form and 'OR' them into the existing Full region}
  for A := 0 to ControlCount - 1 do
  begin
    AControl := Controls[A];
    if (AControl is TWinControl) or (AControl is TGraphicControl) then
      with AControl do
      begin
        if Visible then
        begin
          CtlX := X + Left;
          CtlY := Y + Top;
          CtlRgn := CreateRectRgn(CtlX, CtlY, CtlX + Width, CtlY + Height);
          CombineRgn(FullRgn, FullRgn, CtlRgn, RGN_OR);
        end;
      end;
  end;
  {When the region is all ready, put it into effect:}
  SetWindowRgn(Handle, FullRgn, TRUE);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  {Clean up the regions we created}
  DeleteObject(ClientRgn);
  DeleteObject(FullRgn);
  DeleteObject(CtlRgn);
end;

procedure TForm1.DoVisible;
begin
  {To restore complete visibility:}
  FullRgn := CreateRectRgn(0, 0, Width, Height);
  CombineRgn(FullRgn, FullRgn, FullRgn, RGN_COPY);
  SetWindowRgn(Handle, FullRgn, TRUE);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  {We start out as a transparent form ...}
  DoInvisible;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  {This button just toggles between transparent and not transparent}
  if Button1.Caption = 'Show Form' then
  begin
    DoVisible;
    Button1.Caption := 'Hide Form';
  end
  else
  begin
    DoInvisible;
    Button1.Caption := 'Show Form';
  end;
end;

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

procedure TForm1.FormResize(Sender: TObject);
begin
  {Need to address the transparency if the form gets resized. Also, note that Form1 scroll bars are set to VISIBLE/FALSE. I did that to save a little coding here....}
  if Button1.Caption = 'Show Form' then
    DoInvisible
  else
    DoVisible;
end;

end.

<< Back to main page