2011-10-17 153 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;