DevExpress Skin 正常情况下只能对他自己的组件和系统组件添加皮肤效果,而第三方组件无法使用。如果程序里面使用了非DevExpress的组件,切换皮肤时会导致非DevExpress 组件与DevExpress组件界面不搭配。DevExpress VCL Skin Adapter 就是来解决这个问题的。
cxLookAndFeels 单元有一个RootLookAndFeel全局变量,替换此全局变量的OnChanged方法为自定义的方法,然后在自定义的OnChanged中通知其他组件程序皮肤已经切换,其他组件做对应的皮肤调整。
uDxSkinAdapter.pas 单元源码
unit uDxSkinAdapter; interface uses System.SysUtils,System.Classes,Winapi.Messages,Winapi.Windows,System.SyncObjs,cxLookAndFeels,dxSkinsForm; type IcxLookAndFeelHandler = interface //第三方组件继承此接口 ['{8CB3F0DB-3B89-4D03-ADEA-A11735736205}'] procedure LookAndFeelChanged(Sender: TcxLookAndFeel; AChangedValues: TcxLookAndFeelValues); //当皮肤切换时调用此函数,组件做对应皮肤调整 end; TDxSkinAdapter=class(TObject) private FLock:TCriticalSection; FList:TList; FSavLookAndFeelChanged: TcxLookAndFeelChangedEvent; procedure LookAndFeelChanged(Sender: TcxLookAndFeel; AChangedValues: TcxLookAndFeelValues); procedure SetLookAndFeelChangedHandler(Attach: Boolean); public constructor Create(); destructor Destroy; override; procedure AddHandler(Component: TComponent);//添加需要通知皮肤切换事件的组件 procedure RemoveHandler(Component: TComponent);//删除组件的皮肤切换通知 end; var DxSkinAdapter:TDxSkinAdapter;//全局变量 implementation procedure TDxSkinAdapter.SetLookAndFeelChangedHandler(Attach: Boolean); var CrtLookAndFeel: TcxLookAndFeel; IsAttached: Boolean; begin CrtLookAndFeel := RootLookAndFeel(); if CrtLookAndFeel <> nil then begin IsAttached := (TMethod(CrtLookAndFeel.OnChanged).Data = Self) and (TMethod(CrtLookAndFeel.OnChanged).Code = @TDxSkinAdapter.LookAndFeelChanged); if Attach and not IsAttached then begin FSavLookAndFeelChanged := CrtLookAndFeel.OnChanged; CrtLookAndFeel.OnChanged := LookAndFeelChanged; end else if not Attach and IsAttached then begin CrtLookAndFeel.OnChanged := FSavLookAndFeelChanged; FSavLookAndFeelChanged := nil; end; end; end; procedure TDxSkinAdapter.LookAndFeelChanged(Sender: TcxLookAndFeel; AChangedValues: TcxLookAndFeelValues); var i:Integer; Component: TComponent; AIntf:IcxLookAndFeelHandler; begin FLock.Enter; try for i := 0 to FList.Count-1 do begin Component:=TComponent(FList[i]); if (Component<>nil) and (Component.GetInterface(IcxLookAndFeelHandler,AIntf)) then begin AIntf.LookAndFeelChanged(Sender,AChangedValues); end; end; finally FLock.Leave; end; end; procedure TDxSkinAdapter.AddHandler(Component: TComponent); var AIntf:IcxLookAndFeelHandler; begin FLock.Enter; try if (Component<>nil) and (Component.GetInterface(IcxLookAndFeelHandler,AIntf)) then FList.Add(Component); finally FLock.Leave; end; end; procedure TDxSkinAdapter.RemoveHandler(Component: TComponent); var Index:Integer; begin FLock.Enter; try Index:=FList.IndexOf(Component); if Index>=0 then FList.Delete(Index); finally FLock.Leave; end; end; constructor TDxSkinAdapter.Create(); begin FList:=TList.Create; FLock:=TCriticalSection.Create; SetLookAndFeelChangedHandler(True); end; destructor TDxSkinAdapter.Destroy; begin SetLookAndFeelChangedHandler(False); FreeAndNil(FLock); FreeAndNil(FList); end; initialization DxSkinAdapter := TDxSkinAdapter.Create();//全局初始化 finalization FreeAndNil(DxSkinAdapter); end.使用方法
unit uChart; interface uses System.Classes,Vcl.Controls,VCLTee.Chart,uDxSkinAdapter,cxLookAndFeels; type TAdvChart = class(TChart,IcxLookAndFeelHandler) //第三方组件继承接口 private procedure ChangeLookAndFeel(); public procedure LookAndFeelChanged(Sender: TcxLookAndFeel; AChangedValues: TcxLookAndFeelValues);//接口函数,皮肤切换通知 constructor Create(AOwner: TComponent);override; destructor Destroy;override; end; implementation procedure TAdvChart.ChangeLookAndFeel(); begin Gradient.StartColor := RootLookAndFeel.Painter.DefaultContentColor; Gradient.EndColor := RootLookAndFeel.Painter.DefaultContentColor; end; procedure TAdvChart.LookAndFeelChanged(Sender: TcxLookAndFeel; AChangedValues: TcxLookAndFeelValues); begin ChangeLookAndFeel; end; constructor TAdvChart.Create(AOwner: TComponent); begin inherited; Gradient.Visible:=True; View3DWalls:=False; View3D:=False; BevelOuter:=bvNone; ChangeLookAndFeel; DxSkinAdapter.AddHandler(Self);//此组件需要获取皮肤切换事件 end; destructor TAdvChart.Destroy; begin DxSkinAdapter.RemoveHandler(Self);//删除皮肤切换通知事件 inherited; end;
效果:
顺便贴上 TMS Component Skin 皮肤切换在第三方组件上的应用,详细介绍见http://www.tmssoftware.com/site/atbdev3.asp
unit AdvChart; interface uses Classes,TeeProcs, TeEngine, Chart,DBChart, Series, AdvStyleIF,Controls,Graphics; type TAdvChart = class(TChart, ITMSStyle) public procedure SetComponentStyle(AStyle: TTMSStyle); end; TDBAdvChart = class(TDBChart, ITMSStyle) public procedure SetComponentStyle(AStyle: TTMSStyle); end; implementation procedure TAdvChart.SetComponentStyle(AStyle: TTMSStyle); begin Gradient.Visible:=True; View3DWalls:=False; View3D:=False; BevelOuter:=bvNone; case AStyle of tsOffice2003Blue: begin Gradient.StartColor := $00FDEADA; Gradient.EndColor := $00E4AE88; end; tsOffice2003Silver: begin Gradient.StartColor := $00F7F3F3; Gradient.EndColor := $00E6D8D8; end; tsOffice2003Olive: begin Gradient.StartColor := $00CFF0EA; Gradient.EndColor := $008CC0B1; end; tsOffice2003Classic: begin Gradient.StartColor := clWhite; Gradient.EndColor := $00C9D1D5; end; tsOffice2007Luna: begin Gradient.StartColor := $FAF1E9; Gradient.EndColor := $EDD8C7; end; tsOffice2007Obsidian: begin Gradient.StartColor := $CFC6C1; Gradient.EndColor := $C5BBB4; end; tsWindowsXP: begin Gradient.StartColor := clBtnFace; Gradient.EndColor := clBtnFace; end; tsWhidbey: begin Gradient.StartColor := clWhite; Gradient.EndColor := $00D9E9EC; end; tsCustom: ; tsOffice2007Silver: begin Gradient.StartColor := $F6F1EE; Gradient.EndColor := $E7DCD5; end; tsWindowsVista: begin Gradient.StartColor := $FDF8F1; Gradient.EndColor := $FCEFD5; end; tsWindows7: begin Gradient.StartColor := $FCEBDC; Gradient.EndColor := $FCDBC1; end; tsTerminal: begin Gradient.StartColor := clBtnFace; Gradient.EndColor := clBtnFace; end; tsOffice2010Blue: begin Gradient.StartColor := $FDF6EF; Gradient.EndColor := $F0DAC7; end; tsOffice2010Silver: begin Gradient.StartColor := $FFFFFF; Gradient.EndColor := $EDE5E0; end; tsOffice2010Black: begin Gradient.StartColor := $BFBFBF; Gradient.EndColor := $919191; end; end; end; procedure TDBAdvChart.SetComponentStyle(AStyle: TTMSStyle); begin Gradient.Visible:=True; View3DWalls:=False; View3D:=False; BevelOuter:=bvNone; case AStyle of tsOffice2003Blue: begin Gradient.StartColor := $00FDEADA; Gradient.EndColor := $00E4AE88; end; tsOffice2003Silver: begin Gradient.StartColor := $00F7F3F3; Gradient.EndColor := $00E6D8D8; end; tsOffice2003Olive: begin Gradient.StartColor := $00CFF0EA; Gradient.EndColor := $008CC0B1; end; tsOffice2003Classic: begin Gradient.StartColor := clWhite; Gradient.EndColor := $00C9D1D5; end; tsOffice2007Luna: begin Gradient.StartColor := $FAF1E9; Gradient.EndColor := $EDD8C7; end; tsOffice2007Obsidian: begin Gradient.StartColor := $CFC6C1; Gradient.EndColor := $C5BBB4; end; tsWindowsXP: begin Gradient.StartColor := clBtnFace; Gradient.EndColor := clBtnFace; end; tsWhidbey: begin Gradient.StartColor := clWhite; Gradient.EndColor := $00D9E9EC; end; tsCustom: ; tsOffice2007Silver: begin Gradient.StartColor := $F6F1EE; Gradient.EndColor := $E7DCD5; end; tsWindowsVista: begin Gradient.StartColor := $FDF8F1; Gradient.EndColor := $FCEFD5; end; tsWindows7: begin Gradient.StartColor := $FCEBDC; Gradient.EndColor := $FCDBC1; end; tsTerminal: begin Gradient.StartColor := clBtnFace; Gradient.EndColor := clBtnFace; end; tsOffice2010Blue: begin Gradient.StartColor := $FDF6EF; Gradient.EndColor := $F0DAC7; end; tsOffice2010Silver: begin Gradient.StartColor := $FFFFFF; Gradient.EndColor := $EDE5E0; end; tsOffice2010Black: begin Gradient.StartColor := $BFBFBF; Gradient.EndColor := $919191; end; end; end; end.