开发者

Correct way to create styles for custom components

开发者 https://www.devze.com 2023-04-13 05:09 出处:网络
I sort of asked this question at the end of another post but feel this topic needs a question of its own...

I sort of asked this question at the end of another post but feel this topic needs a question of its own...

If I have created my own component with its own .style what is the correct procedure to merge that with the defined styles supplied with Delphi without modifying the defaults?

Can I embed a default style into a component I have created and can that embedded style inherit most of the style of its parent control?

I feel that I am missing a link that I am struggling to describe. My application has a TStyleBook that has (for example) the "dark.style" loaded by default. My component has its own "MyComponent.style" file. The TStyleBook can load either "dark.style" or "MyComponent.style" but not both. And it does not seem right that the application needs to load "MyComponent.style" as this should be somehow referenced by the component. It does not make the component very portable if every time its used in an application a separate style file is needed also.

I could edit my own "MyDark.style" and add MyComponent into it but this does not seem right either as it creates an issue to keep it up to date with changes made by Embarcadero.

I hope I have explaine开发者_StackOverflowd this clearly. Martin


Thanks for Ray Konopka who gave a great talk on CodeRage and put me on the right track to answer these questions.

Question 1. Can I embed a default style into a component?

Yes, you embed the default style you want to distribute with the component into a resource of type RT_RCDATA. Then simply include that resource into the source:

{$R *.res}

Note: You need to remove the outside object (TLayout) if you created it in the layout editor before putting it into the res.

Then override the GetStyleObject method to load the style from the resource.

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;

Question 2: How to merge it with a default style.

In my case the base of my component was a TCornerButton. I trimmed down my .style file so that it just had the code for the extra bits I wanted. In this case a small triangle to indicate a drop down button and a line to split the button:

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

And I put that into a resource in exactly the same way.

In my constructor I set the StyleLookup to be the "cornerbuttonstyle"

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

I then change the GetStyleObject so that it loaded the new stuff and added it to the existing style.

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;

I hope this helps someone else and I found this all very hard to get information on.

Martin


Usage: 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;
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号