8

我在另一篇文章的结尾问了这个问题,但觉得这个话题需要一个自己的问题......

如果我用自己的 .style 创建了自己的组件,那么在不修改默认值的情况下将其与 Delphi 提供的已定义样式合并的正确程序是什么?

我可以将默认样式嵌入到我创建的组件中,并且该嵌入样式可以继承其父控件的大部分样式吗?

我觉得我错过了一个我很难描述的链接。我的应用程序有一个 TStyleBook,它(例如)默认加载了“dark.style”。我的组件有自己的“MyComponent.style”文件。TStyleBook 可以加载“dark.style”或“MyComponent.style”,但不能同时加载。应用程序需要加载“MyComponent.style”似乎并不正确,因为组件应该以某种方式引用它。如果每次在应用程序中使用它时还需要一个单独的样式文件,它不会使组件非常便携。

我可以编辑自己的“MyDark.style”并将 MyComponent 添加到其中,但这似乎也不正确,因为它会产生一个问题,以使其与 Embarcadero 所做的更改保持同步。

我希望我已经清楚地解释了这一点。马丁

4

2 回答 2

5

感谢 Ray Konopka,他在 CodeRage 上发表了精彩的演讲,让我走上了正确的轨道来回答这些问题。

问题 1. 我可以在组件中嵌入默认样式吗?

是的,您将要与组件一起分发的默认样式嵌入到 RT_RCDATA 类型的资源中。然后只需将该资源包含到源中:

{$R *.res}

注意:如果您在布局编辑器中创建了外部对象 (TLayout),则需要先将其删除,然后再将其放入 res。

然后重写 GetStyleObject 方法以从资源中加载样式。

function TLFButton.GetStyleObject: TControl;
var
  S: TResourceStream;
  obj: TLayout;
const
  Style = 'LFButtonStyle';
begin
  result := inherited GetStyleObject;
  if FStyleLookup = 'cornerbuttonstyle' then
  begin
    if FindResource(HInstance, PChar(Style), RT_RCDATA) <> 0 then
    begin
      S := TResourceStream.Create(HInstance, Style, RT_RCDATA);
      try
        obj := TLayout(TStyleManager.LoadFromResource(HInstance, Style, RT_RCDATA));
        //obj := TLayout( CreateObjectFromStream(nil, S) ); << XE2 version
        Result.AddObject(obj);
        Exit;
      finally
        S.Free;
      end;
    end;
  end;
end;

问题2:如何将其与默认样式合并。

在我的例子中,我的组件的基础是一个 TCornerButton。我修剪了我的 .style 文件,以便它只包含我想要的额外位的代码。在这种情况下,一个小三角形表示一个下拉按钮和一条分割按钮的线:

object TLayout
  Align = alRight
  Position.Point = '(76,0)'
  Locked = True
  Width = 15.000000000000000000
  Height = 24.000000000000000000
  object TPath
    StyleName = 'dropdownbutton'
    Align = alCenter
    Position.Point = '(4,9)'
    Width = 8.000000000000000000
    Height = 5.000000000000000000
    HitTest = False
    Fill.Color = claBlack
    Stroke.Kind = bkNone
    Data.Path = {
      04000000000000000000000000000000010000000000803F0000000001000000
      0000003F0000803F030000000000000000000000}
  end
  object TLine
    StyleName = 'dropdownsplit'
    Align = alLeft
    Width = 1.000000000000000000
    Height = 24.000000000000000000
    HitTest = False
    LineType = ltLeft
  end
end

我以完全相同的方式将其放入资源中。

在我的构造函数中,我将 StyleLookup 设置为“cornerbuttonstyle”

constructor TLFButton.Create(AOwner: TComponent);
begin
  FStyleLookup := 'cornerbuttonstyle';
  FDropDownButton := false;
  inherited;
end;

然后我更改 GetStyleObject 以便它加载新内容并将其添加到现有样式中。

function TLFButton.GetStyleObject: TControl;
var
  S: TResourceStream;
  obj: TLayout;
const
  Style = 'LFButtonStyle';
begin
  result := inherited GetStyleObject;
  if FStyleLookup = 'cornerbuttonstyle' then
  begin
    if FindRCData(HInstance, Style) then
    begin
      S := TResourceStream.Create(HInstance, Style, RT_RCDATA);
      try
        obj := TLayout( CreateObjectFromStream(nil, S) );
        Result.AddObject(obj);
        Exit;
      finally
        S.Free;
      end;
    end;
  end;
end;

我希望这对其他人有所帮助,我发现这一切都很难获得信息。

马丁

于 2011-10-21T01:36:40.780 回答
2

用法: MergeStyle('MyComponent.Style', StyleBook1);

procedure MergeStyle(const aFilename: string; aStyleBook: TStyleBook);
var
  sb: TStyleBook;
  I: Integer;
begin
  sb := TStyleBook.Create(nil);
  try
    sb.FileName := aFilename;

    for I := 0 to sb.Root.ChildrenCount - 1 do
      // Prevent duplicates
      if aStyleBook.Root.FindStyleResource(sb.Root.Children[I].StyleName) = nil then
        aStyleBook.Root.AddObject(sb.Root.Children[I].Clone(aStyleBook.Root));

    aStyleBook.UpdateScenes;
  finally
    sb.Free;
  end;
end;
于 2011-10-18T17:21:57.260 回答