Правильный способ создания стилей для пользовательских компонентов

#delphi #delphi-xe2 #firemonkey

#delphi #delphi-xe2 #firemonkey

Вопрос:

Я вроде как задавал этот вопрос в конце другого поста, но чувствую, что эта тема нуждается в отдельном вопросе…

Если я создал свой собственный компонент с собственным .style, какова правильная процедура для объединения его с определенными стилями, поставляемыми с Delphi, без изменения значений по умолчанию?

Могу ли я встроить стиль по умолчанию в созданный мной компонент и может ли этот встроенный стиль унаследовать большую часть стиля его родительского элемента управления?

Я чувствую, что мне не хватает ссылки, которую я изо всех сил пытаюсь описать. В моем приложении есть TStyleBook, в котором (например) по умолчанию загружен «dark.style». У моего компонента есть свой собственный файл «MyComponent.style». TStyleBook может загружать либо «dark.style», либо «MyComponent.style», но не оба. И кажется неправильным, что приложение должно загружать «MyComponent.style», поскольку на это должен каким-то образом ссылаться компонент. Это не делает компонент очень переносимым, если каждый раз, когда он используется в приложении, также требуется отдельный файл стиля.

Я мог бы отредактировать свой собственный «MyDark.style» и добавить в него MyComponent, но это тоже кажется неправильным, поскольку создает проблему для обновления его с изменениями, внесенными Embarcadero.

Я надеюсь, что я это ясно объяснил. Мартин

Ответ №1:

Спасибо Рэю Конопке, который провел отличный доклад о 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;
  

Я надеюсь, что это поможет кому-то еще, и я обнаружил, что все это очень сложно получить информацию.

Мартин

Комментарии:

1. Очень полезно. Спасибо!

Ответ №2:

Использование: MergeStyle(‘MyComponent.Стиль’, 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;