--- ---

To do that kind of stuff right, create a new control derived for example from TGroupbox, and override its CreateParams method like this:

    protected {in control declaration}

    procedure CreateParams(var params: TCreateParams); override;

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

    {Add a handler for the WM_ERASEBKGND message}
    procedure WMEraseBkGnd(var msg: TWMEraseBkGnd); message WM_ERASEBKGND;

    procedure TTransparentGroupbox.WMEraseBkGnd(var msg: TWMEraseBkGnd);
    begin
      SetBkMode (msg.DC, TRANSPARENT);
      msg.result := 1;
    end;

That is the basic frame for a TWinControl descendent. For a TGraphicsControl you would drop the CreateParams (since only WinControls have that method) and override the create constructor. After calling the inherited constructor you modify the ControlStyle of the control:

    ControlStyle := ControlStyle - [csOpaque];

## Demo code

A ready made project containing this demo code is available. View the project.

In this demo we'll create a new transparent group box (TGroupBoxEx) and, to demonstrate a transparent TGraphicControls, a new transparent label (TLabelEx). I know that TLabel has a Transparent property, but this is just a proof of concept example!

Start a new Delphi VCL application and create OnPaint and OnCreate event handlers for the main form. Name the form "Form1" and save the form unit as `Unit1.pas`.

Now code Unit1 as follows:

    unit Unit1;

    interface

    uses
      Forms, Classes, Controls, StdCtrls, Messages;

    type
      // Example of a TWinControl derived control
      TGroupBoxEx = class(TGroupBox)
      protected
        procedure CreateParams(var params: TCreateParams); override;
        procedure WMEraseBkGnd(var msg: TWMEraseBkGnd);
          message WM_ERASEBKGND;
      end;

      // Example of a TGraphicControl derived control
      TLabelEx = class(TLabel)
      public
        constructor Create(AOwner: TComponent); override;
      end;

    type
      TForm1 = class(TForm)
        procedure FormCreate(Sender: TObject);
        procedure swe3(Sender: TObject);
      private
        fGB: TGroupBox;     // standard group box
        fGBX: TGroupBoxEx;  // transparent group box
        fLbl: TLabel;       // standard label
        fLblX: TLabelEx;    // transparent label
      end;

    var
      Form1: TForm1;

    implementation

    uses
      Windows, Graphics;

    {$R *.dfm}

    { TForm1 }

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      // Normal group box
      fGB := TGroupBox.Create(Self);
      fGB.Parent := Self;
      fGB.Caption := 'TGroupBox';
      fGB.Top := 20;
      fGB.Left := 20;
      // Special group box
      fGBX := TGroupBoxEx.Create(Self);
      fGBX.Parent := Self;
      fGBX.Caption := 'TGroupBoxEx';
      fGBX.Top := 20;
      fGBX.Left := fGB.Left + fGB.Width + 20;
      // Normal label
      fLbl := TLabel.Create(Self);
      fLbl.Parent := Self;
      fLbl.Caption := 'TLabel';
      fLbl.Top := fGB.Top + fGB.Height + 20;
      fLbl.Left := fGB.Left;
      // Special label
      fLblX := TLabelEx.Create(Self);
      fLblX.Parent := Self;
      fLblX.Caption := 'TLabelEx';
      fLblX.Top := fGBX.Top + fGBX.Height + 20;
      fLblX.Left := fGBX.Left;
    end;

    // Paint form in yellow / white candy stripes
    procedure TForm1.swe3(Sender: TObject);
    var
      Idx: Integer;
    begin
      for Idx := 0 to ClientHeight div 8 do
      begin
        if Odd(Idx) then
          Canvas.Brush.Color := clWhite
        else
          Canvas.Brush.Color := $aaffff;  // pale yellow
        Canvas.FillRect(Rect(0, Idx * 8, ClientWidth, Idx * 8 + 8));
      end;
    end;

    { TGroupBoxEx: implemented per tip #87 for TWinControls }

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

    procedure TGroupBoxEx.WMEraseBkGnd(var msg: TWMEraseBkGnd);
    begin
      SetBkMode (msg.DC, TRANSPARENT);
      msg.result := 1;
    end;

    { TLabelEx: implemented per tip #87 for TGraphicControls }

    constructor TLabelEx.Create(AOwner: TComponent);
    begin
      inherited;
      ControlStyle := ControlStyle - [csOpaque];
    end;

    end.

We've painted a candy stripe background on the form to help demonstrate transparency. You'll see the normal label and group box use the form's default colour as a background, while the new components are truly transparent (except for the label of the group box) and the candy stripes show through.

Demo by Peter Johnson

Transparency actually works better for TGraphicControls than for TWinControls. The latter have problems if the control is moved or the background needs to change. Delphi container controls (like form or panel) are always created with the WS_CLIPCHILDREN style, which automatically excludes the area under child controls from updates, so the background will not be updated if required. Removing the WS_CLIPCHILDREN style from a controls parent is possible with:

    SetWindowLong(
      parent.handle, GWL_STYLE,
      GetWIndowLong(parent.handle, GWL_STYLE) and not WS_CLIPCHILDREN
    );

But that may lead to excessive flicker on screen updates.