I need to change the color of a TPanel when the VCL styles are enabled. I tried using and modifying the code listed in the article Changing the color of Edit Controls with VCL Styles Enabled, but it is not working for a TPanel. How I can change the color of a TPanel with the VCL Styles enabled?
Asked
Active
Viewed 1.5k times
3 Answers
21
The TPanel
doesn't use a style hook to draw the control, so you can't use the technique described in the article. instead you must override the paint
method.
Check this sample using a interposer class.
type
TPanel=Class(Vcl.ExtCtrls.TPanel)
protected
procedure Paint; override;
End;
Uses
Vcl.Styles,
Vcl.Themes;
{$R *.dfm}
{ TPanel }
procedure TPanel.Paint;
const
Alignments: array[TAlignment] of Longint = (DT_LEFT, DT_RIGHT, DT_CENTER);
VerticalAlignments: array[TVerticalAlignment] of Longint = (DT_TOP, DT_BOTTOM, DT_VCENTER);
var
Rect: TRect;
LColor: TColor;
LStyle: TCustomStyleServices;
LDetails: TThemedElementDetails;
TopColor : TColor;
BottomColor : TColor;
LBaseColor : TColor;
LBaseTopColor : TColor;
LBaseBottomColor: TColor;
Flags: Longint;
procedure AdjustColors(Bevel: TPanelBevel);
begin
TopColor := LBaseTopColor;
if Bevel = bvLowered then
TopColor := LBaseBottomColor;
BottomColor := LBaseBottomColor;
if Bevel = bvLowered then
BottomColor := LBaseTopColor;
end;
begin
Rect := GetClientRect;
LBaseColor := Color;//use the color property value to get the background color.
LBaseTopColor := clBtnHighlight;
LBaseBottomColor := clBtnShadow;
LStyle := StyleServices;
if LStyle.Enabled then
begin
LDetails := LStyle.GetElementDetails(tpPanelBevel);
if LStyle.GetElementColor(LDetails, ecEdgeHighLightColor, LColor) and (LColor <> clNone) then
LBaseTopColor := LColor;
if LStyle.GetElementColor(LDetails, ecEdgeShadowColor, LColor) and (LColor <> clNone) then
LBaseBottomColor := LColor;
end;
if BevelOuter <> bvNone then
begin
AdjustColors(BevelOuter);
Frame3D(Canvas, Rect, TopColor, BottomColor, BevelWidth);
end;
if not (LStyle.Enabled and (csParentBackground in ControlStyle)) then
Frame3D(Canvas, Rect, LBaseColor, LBaseColor, BorderWidth)
else
InflateRect(Rect, -Integer(BorderWidth), -Integer(BorderWidth));
if BevelInner <> bvNone then
begin
AdjustColors(BevelInner);
Frame3D(Canvas, Rect, TopColor, BottomColor, BevelWidth);
end;
with Canvas do
begin
if not LStyle.Enabled or not ParentBackground then
begin
Brush.Color := LBaseColor;
FillRect(Rect);
end;
if ShowCaption and (Caption <> '') then
begin
Brush.Style := bsClear;
Font := Self.Font;
Flags := DT_EXPANDTABS or DT_SINGLELINE or
VerticalAlignments[VerticalAlignment] or Alignments[Alignment];
Flags := DrawTextBiDiModeFlags(Flags);
if LStyle.Enabled then
begin
LDetails := LStyle.GetElementDetails(tpPanelBackground);
if not LStyle.GetElementColor(LDetails, ecTextColor, LColor) or (LColor = clNone) then
LColor := Font.Color;
LStyle.DrawText(Handle, LDetails, Caption, Rect, TTextFormatFlags(Flags), LColor)
end
else
DrawText(Handle, Caption, -1, Rect, Flags);
end;
end;
end;

RRUZ
- 134,889
- 20
- 356
- 483
-
1there seems to be a much easier way, see the other answer – George Birbilis Dec 18 '16 at 18:31
-
ecEdgeHighLightColor is close enough, but which would be the actual constant for getting the color used to paint the body of a TPanel? – Gabriel Jul 11 '20 at 16:17
-
I have found the answer: tpPanelBackground + ecFillColor. It will work with most themes but not with 'Auric'. But for Auric it will give a close-enough result. -------------------------- Update: This will always work: cl:= TStyleManager.ActiveStyle.GetSystemColor(clBtnFace); – Gabriel Jul 11 '20 at 16:25
20
In XE5, if you turn off the seClient flag in the StyleElements property, then the Color property works again as expected.

approxiblue
- 6,982
- 16
- 51
- 59

boggy
- 3,674
- 3
- 33
- 56
-
Thanks for the tip, was upgrading some old Delphi code of mine to Berlin 10.1 Update 2 and it wasn't painting the background of a TPanel control descendent I was using – George Birbilis Dec 18 '16 at 18:24
-
3@GeorgeBirbilis: Glad it helped you. The accepted answer seemed overkill. – boggy Dec 18 '16 at 22:13
-
Brilliant! playing around with style elements of a TSpeedButton in XE5, I was able to change its font color and style despite visual theme enabled. May help someone. – user30478 Jul 30 '18 at 18:12
4
Based on @costa's answer, use:
StyleElements := StyleElements - [seClient];
in the constructor of your TPanel descendent class
or if you just have some TPanel (or descendent class) instance you can do:
with myPanel do StyleElements := StyleElements - [seClient];
The -[...] syntax is used since the StyleElements is a set
For more on StyleElements read this article:
Tuning VCL Styles for Forms and Controls - http://edn.embarcadero.com/article/42812

George Birbilis
- 2,782
- 2
- 33
- 35
-
1This is a much simpler solution. Works on for Delphi 2007 as well using TControlStyle. { ControlStyle := MyPanel.ControlStyle; Exclude(ControlStyle, csParentBackground); MyPanel.ControlStyle := ControlStyle; } – Airs Mar 23 '18 at 18:42
-
1I was on the verge of switching to C# and XAML until I found this solution. – Phil Rogers Feb 20 '21 at 17:24