2011-10-17 103 views
7

我有点问这个问题在另一篇文章的结束,而是觉得这个题目的正确方法需要自己的问题......创建样式自定义组件

如果我创造我自己的组件与自己.style什么是正确的过程来合并与Delphi提供的定义样式而不修改默认值?

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

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

我可以编辑我自己的“MyDark.style”并添加MyComponent,但这看起来不正确,因为它创建了一个问题,以使其与Embarcadero所做的更改保持同步。

我希望我已经解释清楚。 Martin

回答

4

感谢Ray Konopka在CodeRage上做了一次精彩的演讲,并让我在正确的轨道上回答了这些问题。

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

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

{$R *.res} 

注意:您需要,如果你在布局编辑器把它放入res之前创建它来去除外界物体(TLayout)。

然后覆盖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; 

我希望这可以帮助别人,我发现这一切都很难得到的信息。

Martin

+1

我已经编辑了上述内容,以便在XE3中工作 – Martin

+0

非常有帮助。谢谢! – Nix

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;