16

Im Designing a Form with Delphi 2009, and Im trying to figure out the TPageControl element. Im trying to make separate dialogs for each tab. I can make the TTabSheets, and I can place my elements on the TabSheets, but my problem is that they are barley visible, as the default background for a TTabSheet appears to be white. Ive tried to place a panel on the TabSheet, but for whatever reason, the panel always appears behind the TabSheet. So my question: Is there any way to change the color of a tab sheet to the standard windows beige, or is their a way to place a TPanel on the tab page, accomplishing the same goal?

Ben313
  • 1,662
  • 3
  • 20
  • 32
  • When I see a dialog box using a tab control (with tabs) in which the pages are `clBtnFace` coloured, I think, "Oh, that's an old, ugly application, written long before the advent of themes". But if I understand you correctly, you do not want to use the tab control as a 'normal' tab control, with the tabs visible. Instead, you want to have several 'pages' (but no tabs!) in a dialog box, don't you? Maybe you want to add 'Next' and 'Back' buttons to the bottom of the dialog? In other you want to create a *wizard*? – Andreas Rejbrand May 06 '11 at 00:29
  • @Andreas You have certainly misunderstood, although i admit i am very new to this, and probably not explaining correct. – Ben313 May 06 '11 at 08:02

5 Answers5

27

Set the style property to tsFlatButtons
The background ~colour~ will revert to beautiful clBtnFace

Johan
  • 74,508
  • 24
  • 191
  • 319
  • +1 I didn't know that. Is that because tsFlatButtons is old school? – David Heffernan May 05 '11 at 23:22
  • 1
    Well, you can also set it to `tsButtons`. (The options are `tsTabs`, `tsButtons`, and `tsFlatButtons`.) This will disable visual theming of the tab control altogether. Themes only work for normal tabs. – Andreas Rejbrand May 06 '11 at 00:24
  • 1
    +1 for this trick. Should really be -1 for describing clBtnFace as beautiful (not in XP Luna blue anyway) – Gerry Coll May 06 '11 at 00:52
  • +1, I just found this out recently while maintaining some older application for which we cannot enable theming. – R-D May 06 '11 at 12:44
  • This seems to work (at least using Delphi 10.2) only if the tab position is tpTop. In my case I also have tab position at tpBottom, and then when I try to change the style to anything other than tsTabs, it gives me the exception: "tab style incompatible with current tab position". – DelphiUser Jul 23 '20 at 12:03
6

The standard Windows colour for a tab sheet is white. That standard came into being when XP themes were introduced. If a user switches back to Windows Classic then they will get a grey background. [You do mean grey rather than beige don't you? Beige would be truly vile!]

A panel inside a tab sheet can never be behind the page since it is inside the page. What is actually happening is that the panel is being drawn transparently so that the standard tab sheet colour prevails.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • @David, can the color be changed into say blue?, or are we stuck with default colors? Oh and +1 for the structure pane. – Johan May 05 '11 at 21:47
  • @Johan I'm sure with some effort the colour can be changed. You'd need to hack the page control and possibly some other controls, I'd guess. The point I'm trying to make is that if OP wants the standard behaviour then it is white. – David Heffernan May 05 '11 at 21:49
  • @David, I was asking it for myself :-( – Johan May 05 '11 at 22:00
  • 2
    To make the panel use its own background, set `ParentBackground := false` on the `TPanel`. – Andreas Rejbrand May 06 '11 at 00:27
  • @Andreas My recollection is that this results in a funny white background around the edge of the panel. Do you need to handle background painting in the the tab sheet too? – David Heffernan May 06 '11 at 02:41
  • @David: You mean in this particular case, when the panel is `alClient` in a tab sheet? Yes, then you get a funny white border around the panel. Still, I think it is a terribly bad idea to make the client area of a tab sheet `clBtnFace` if the tab control is an ordinary tab control. It looks dreadful. – Andreas Rejbrand May 06 '11 at 10:11
  • 3
    Sounds like a job for a non-ms-windows-common-controls-tabsheet. – Warren P May 06 '11 at 19:28
3

Use this unit in your Form at the interface:

unit MSCtrlsStyleHook;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.ExtCtrls, Vcl.Themes,
  Winapi.CommCtrl;

type
  TTabSheet = class(Vcl.ComCtrls.TTabSheet)
  private
    procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
  end;

  TPageControl = class(Vcl.ComCtrls.TPageControl)
  private
    procedure TCMAdjustRect(var Msg: TMessage); message TCM_ADJUSTRECT;
  end;

implementation

{ TPageControl }

procedure TPageControl.TCMAdjustRect(var Msg: TMessage);
begin
  inherited;
  if Msg.WParam = 0 then
    InflateRect(PRect(Msg.LParam)^, 3, 3)
  else
    InflateRect(PRect(Msg.LParam)^, -3, -3);
end;

{ TTabSheet }

procedure TTabSheet.WMEraseBkgnd(var Message: TWMEraseBkgnd);
var
  LRect  : TRect;
  LCanvas: TCanvas;
begin
  if (PageControl <> nil) and StyleServices.Enabled and
     ((PageControl.Style = tsTabs) or TStyleManager.IsCustomStyleActive) then
  begin
    //Get the bounds of the Tabsheet
    GetWindowRect(Handle, LRect);
    OffsetRect(LRect, -LRect.Left, -LRect.Top);
    //create a TCanvas for erase the background, using the DC of the message
    LCanvas := TCanvas.Create;
    try
      LCanvas.Handle := Message.DC;
      LCanvas.Brush.Color:= $fafafa;// Color You need;
      LCanvas.FillRect(LRect);
    finally
      LCanvas.Handle := 0;
      LCanvas.Free;
    end;

    Message.Result := 1;
  end
  else
    inherited;
end;

end.
MohsenB
  • 1,669
  • 18
  • 29
  • With this I was able to get the background of my tsTabs, position tpBottom tab sheets to clBtnFace. Still the focused tab indicator (the "tab") is white, but that's less different-looking.The old versio is made with Delphi 6, new with 10.2. The tabs (and buttons) in the old version are "more 3D" than in the new one, where they are more flat. – DelphiUser Jul 23 '20 at 14:34
0

Not liking either solution much, this is what I'm doing to thwart the problem you're having. You don't need to sacrifice windows themes to make it work:

just check:

if ThemeServices.ThemesEnabled then
  FormBGColor := clBtnHighlight
else
  FormBGColor := clBtnFace;

and set the color of the form before you show it on your tabs.

(personally, I never liked this solution, but it's how a major part of the program I work on was programmed before I started, so to make it not look like crap on my compuer XOR terminal servers that's what I had to do)


ThemeServices is in themes.pas

Peter Turner
  • 11,199
  • 10
  • 68
  • 109
0

If you wish to preserve the PageControl Style property as tsTabs then you'll need to hack the TTabSheet class ...

Just above your form's type declaration add the following ...

  TTabSheet = class(ComCtrls.TTabSheet)
  protected
    procedure PaintWindow(DC: HDC); override;
  end;

Then in the unit's implementation section ...

  var brushBtnFace: HBrush;

  procedure TTabSheet.PaintWindow(DC: HDC);
  var
    rec: TRect;
  begin
    rec := ClientRect;
    windows.FillRect(DC, rec, brushBtnFace);
  end;

And finally create and destroy your brush in the unit's initialization and finalization sections ...

  initialization
    brushBtnFace := CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  finalization
    DeleteObject(brushBtnFace);
Angus Johnson
  • 4,565
  • 2
  • 26
  • 28