如何在我自己的组件中实现主题支持?

Psh*_*mas 5 delphi vcl delphi-10.4-sydney

我正在尝试制作自己的组件,其主题与应用程序的其余部分相同(主题在 中设置Project > Options > Application > Appearance)。

该控件源自TWinControl(下图红框中)。如何将应用程序主题应用到我的组件?我将在上面使用很多标准控件,如按钮、编辑等。

图像

我试图在谷歌中找到一些东西,但也许我的英语是问正确问题的问题:)

小智 2

没有为您的组件指定特殊的皮肤数据,因此您需要从 VCL 中挑选其他类似组件中与您的组件相似的部分。然后你需要查看这个组件的源代码,并根据你的具体更改实现相同的绘制。\n你没有提供你的组件的详细描述,所以这一切都取决于我们的幻想。比方说:您想要像 TPanel 这样的东西,中间有一个红色矩形的自定义选项卡。\n我们将选择 TCustomControl(而不是 TWinControl)作为父级,因为我们已经为自定义绘图和主题实现了 Canvas支持。我们将重写 UpdateStyleElements 以对主题更改做出反应并为我们的绘图绘制(TCustomPanel 执行相同操作,我们使用其绘制功能的一部分)。

\n
unit Component1;\n\ninterface\n\nuses\n  System.SysUtils, System.Classes, vcl.Controls, vcl.Styles, WinApi.Windows,\n  vcl.Themes, Vcl.Graphics, Vcl.ExtCtrls;\n\ntype\n  TComponent1 = class(TCustomControl)\n  private\n  protected\n    procedure Paint; override;\n    procedure UpdateStyleElements; override;\n  end;\n\nprocedure Register;\n\nimplementation\n\nprocedure Register;\nbegin\n  RegisterComponents(\'Samples\', [TComponent1]);\nend;\n\n{ TComponent1 }\n\nprocedure TComponent1.Paint;\nconst\n  Alignments: array[TAlignment] of Longint = (DT_LEFT, DT_RIGHT, DT_CENTER);\n  VerticalAlignments: array[TVerticalAlignment] of Longint = (DT_TOP, DT_BOTTOM, DT_VCENTER);\nvar\n  Rect: TRect;\n  LColor: TColor;\n  LStyle: TCustomStyleServices;\n  LDetails: TThemedElementDetails;\n  TopColor, BottomColor: TColor;\n  BaseColor, BaseTopColor, BaseBottomColor: TColor;\n  Flags: Longint;\n\n  procedure AdjustColors(Bevel: TPanelBevel);\n  begin\n    TopColor := BaseTopColor;\n    if Bevel = bvLowered then\n      TopColor := BaseBottomColor;\n    BottomColor := BaseBottomColor;\n    if Bevel = bvLowered then\n      BottomColor := BaseTopColor;\n  end;\n\nbegin\n  //get rect, where we will drawing\n  Rect := GetClientRect;\n\n  //initilize colors\n  BaseColor := Color;\n  BaseTopColor := clBtnHighlight;\n  BaseBottomColor := clBtnShadow;\n\n  //get style\n  LStyle := StyleServices(Self);\n  if LStyle.Enabled and (seClient in StyleElements) then\n  begin\n    //get detail(background) of our style, which we will use\n    LDetails := LStyle.GetElementDetails(tpPanelBackground);\n    //check, if in this style our color is changed - we take it\n    if LStyle.GetElementColor(LDetails, ecFillColor, LColor) and (LColor <> clNone) then\n      BaseColor := LColor;\n\n    //get detail(border) of our style, which we will use\n    LDetails := LStyle.GetElementDetails(tpPanelBevel);\n    //check, if in this style our color is changed - we take it\n    if LStyle.GetElementColor(LDetails, ecEdgeHighLightColor, LColor) and (LColor <> clNone) then\n      BaseTopColor := LColor;\n    if LStyle.GetElementColor(LDetails, ecEdgeShadowColor, LColor) and (LColor <> clNone) then\n      BaseBottomColor := LColor;\n  end;\n\n  //draw top border\n  if BevelOuter <> bvNone then\n  begin\n    AdjustColors(BevelOuter);\n    Frame3D(Canvas, Rect, TopColor, BottomColor, BevelWidth);\n  end;\n\n  //if style does not draw borders - do it by ourselves\n  if not (LStyle.Enabled and (csParentBackground in ControlStyle)) then\n    Frame3D(Canvas, Rect, BaseColor, BaseColor, BorderWidth)\n  else\n    InflateRect(Rect, -Integer(BorderWidth), -Integer(BorderWidth));\n\n  if BevelInner <> bvNone then\n  begin\n    AdjustColors(BevelInner);\n    Frame3D(Canvas, Rect, TopColor, BottomColor, BevelWidth);\n  end;\n\n  with Canvas do\n  begin\n    if not LStyle.Enabled or not ParentBackground or not (seClient in StyleElements) or\n       (not LStyle.IsSystemStyle and (Parent <> nil) and (Parent is TCustomPanel) and\n       TCustomPanel(Parent).DoubleBuffered {and not CheckParentBackground(Parent)})\n    then\n    begin\n      //set curect brush color\n      Brush.Color := BaseColor;\n      //and fill all client rect with it\n      FillRect(Rect);\n    end;\n\n    //drawing red rectangle\n    Brush.Style := bsClear;\n    Pen.Color := clRed;\n    InflateRect(Rect, -30, -30);\n    Rectangle(Rect);\n\n    if LStyle.Enabled then begin\n      //draw\n      //make tab smaller\n      InflateRect(Rect, -10, -10);\n      //move tab to bottom of recrangle\n      OffsetRect(Rect, 0, 10 - 1);\n      //get slyled tab\n      LDetails := LStyle.GetElementDetails(ttTabItemSelected);\n      //draw tab\n      LStyle.DrawElement(Handle, LDetails, rect);\n\n      //draw some text on tab\n      Brush.Style := bsClear;\n      Font := Self.Font;\n      Flags := DT_EXPANDTABS or DT_SINGLELINE or\n        VerticalAlignments[taVerticalCenter] or Alignments[taCenter];\n      Flags := DrawTextBiDiModeFlags(Flags);\n      if LStyle.Enabled and (seFont in StyleElements) then\n      begin\n        LDetails := LStyle.GetElementDetails(tpPanelBackground);\n        if not LStyle.GetElementColor(LDetails, ecTextColor, LColor) or (LColor = clNone) then\n          LColor := Font.Color;\n        LStyle.DrawText(Handle, LDetails, \'CustomCaption\', Rect, TTextFormatFlags(Flags), LColor)\n      end\n      else\n        DrawText(Handle, Caption, -1, Rect, Flags);\n    end;\n  end;\nend;\n\nprocedure TComponent1.UpdateStyleElements;\nbegin\n  inherited;\nend;\nend.\n
Run Code Online (Sandbox Code Playgroud)\n

您可以在模块 \xe2\x80\x98Vcl.Themes\xe2\x80\x99 中找到样式的另一个标准部分。\n源已简化,但您可以从这一点开始。

\n

PS 如果您的组件有更高级的绘图 \xe2\x80\x93 您可以使用与其他高级组件相同的样式挂钩。查看 \xe2\x80\x98 类构造函数\xe2\x80\x99 和 \xe2\x80\x98 类析构函数\xe2\x80\x99。\n在此输入图像描述

\n

在此输入图像描述

\n