5

I have inherited from TGroupBox of the Delphi native control and overriden its Paint method to draw rounded rectangle.

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

After overriding the Create params, the Paint method is as below.

   procedure TclTransparentGroupBox.Paint;
   begin
     // Draw the rounded rect to show the group box bounds
     Canvas.Pen.Color := clWindowFrame;
     Canvas.RoundRect(5, 15, ClientRect.Right - 5, ClientRect.Bottom - 5, 10, 10);
     if Caption <> EmptyStr then
     begin
       Canvas.Brush.Style := bsClear;
       Canvas.TextOut(10, 0, Caption);
     end;
   end;

The major problem i m facing is that, i have few labels on top of the transparent group box. When i open the form the labels look fine, but when the text changes, some bounding rectangles of the labels will be visible. This is looking weird on top of transparent box.

Even when i resize the form, the group box itself disappears, when i change the focus to another application and bring back my application, the group box draws itself.

Am i missing anything with respect to drawing? Any windows messages that i need to take care of???

Thanks in advance Rahul

RRUZ
  • 134,889
  • 20
  • 356
  • 483
Rahul W
  • 833
  • 11
  • 26
  • 3
    Are you handling the `WM_ERASEBKGND` message? – RRUZ Jan 19 '12 at 15:49
  • Am I the only one who feels that the word `transparent` is ambiguous? As a "contract" what are the rules for a transparent control? – Warren P Jan 19 '12 at 16:01
  • @Warren, what you don't get on term `transparent` ? Just fully translucent with fully visible parent background (where all windows that are beneath the window are not obscured by the control with this style). – TLama Jan 19 '12 at 16:20
  • No i am not handling the WM_ERASEBKGND message. But, should i be redrawing there again if i handle? – Rahul W Jan 19 '12 at 16:20
  • 5
    @TLama [Raymond Chen has this to say on the matter](http://blogs.msdn.com/b/oldnewthing/archive/2011/10/28/10230811.aspx): The WS_EX_TRANSPARENT style doesn't mean "transparent"; it means "paint over siblings." The style is called "transparent" not because it makes the window transparent but because it makes transparency possible. It is one of the steps (but not the only one) for making child controls render transparently. Another important step is ensuring that the control does not erase its background in its WM_ERASE­BKGND, and that's the step that the On­Ctl­Color override performs. – David Heffernan Jan 19 '12 at 16:21
  • @DavidHeffernan +1 Good recall of Raymond's post. I was on my way to find that. – EMBarbosa Jan 19 '12 at 17:16

1 Answers1

5

To make a control transparent you have to :

Make it non-opaque

ControlStyle := ControlStyle - [csOpaque]

Handle WM_ERASEBKGND:

procedure TTransPanel.WM_ERASEBKGND(var Msg: TWM_ERASEBKGND); 
var
    SaveDCInd: Integer;
    Position: TPoint;
begin
    SaveDCInd := SaveDC(Msg.DC); 
    //save device context state (TCanvas does not have that func)
    GetViewportOrgEx(Msg.DC, Position);
    SetViewportOrgEx(Msg.DC, Position.X - Left, Position.Y - Top, nil);
    IntersectClipRect(Msg.DC, 0, 0, Parent.ClientWidth, Parent.ClientHeight);
    try
        Parent.Perform(WM_ERASEBKGND, Msg.DC, 0 );
        Parent.Perform(WM_PAINT, Msg.DC, 0);
        //or
        // Parent.Perform(WM_PRINTCLIENT, Msg.DC, prf_Client); //Themeing
    except
    end;       
    RestoreDC(Msg.DC, SaveDCInd);
    Canvas.Refresh;       
    Msg.Result := 1; //We painted out background
end;

In the proc above you first save device context state, then draw the canvas of our parent (TForm maybe) onto our canvas (TGroupBox). At the end restore DC and return 1 to indicate that we did paint the background.

Mihaela
  • 2,482
  • 3
  • 21
  • 27
  • Thank you very much Michaela....this worked like a charm. If possible can you explain me the IntersectClipRect part. – Rahul W Jan 21 '12 at 16:36
  • We are intersecting DC drawing area (of our GroupBox) with the parent's DC rectangle, to make sure that we start from (0,0). Otherwise we might get black areas in our GroupBox. – Mihaela Jan 22 '12 at 00:17
  • And also so that we take into account the whole parent's DC rect. If the parent is smaller than our GroupBox, it wouldn't matter for the GroupBox would be clipped. – Mihaela Jan 22 '12 at 00:22