Firemonkey:为FMXObject级联样式化的Lookup更改,其他对象继承样式名

时间:2018-03-24 05:33:20

标签: delphi firemonkey tcomponent

我不确定是否有可能 - 但它似乎应该对我而言。基本上,我想在更改StyleLookup时触发所有组件来刷新它们的样式。

我有一个名为BaseStyleLabel的TLabel FMXComponent。组件的StyleName属性是'BaseStyle'。它本身从样式资源中查找其样式,因此其StyleLookup属性设置为'BaseStyle1'。我还有'BaseStyle2''BaseStyle3' ......

我有一个名为MyTextLabel的依赖Tlabel,其StyleLookup属性设置为BaseStyle,即BaseStyleLabel的StyleName。

一切似乎都很好。我看到MyTextLabel继承了'BaseStyle1'MyBaseStyle样式。

当我执行这行代码时

 BaseStyleLabel.StyleLookup := 'BaseStyle2';
 Self.repaint; // repaint whole form

我希望BaseStyleLabel更改为'BaseStyle2'(它确实如此)。但是,MyTextLabel也应该更改样式,然后看起来像'BaseStyle2',但它不会:它仍然是 BaseStyle1 ;

限定符是BaseLabel和MyTextLabel都来自样式资源。它们实际上不是在表单上创建的组件,它们是由样式创建的。

所以我的问题是这个。

  1. 这种方法有效吗?
  2. 是否有标准方法,例如使用我可以更新的样式对象?
  3. 我是不是没有刷新正确的东西;
  4. 用错误的方法刷新,也许是ApplyStyle?
  5. ...编辑....下面是请求的示例...

    unit Unit1;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
      FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls;
    
    type
      TForm1 = class(TForm)
        MyTextLabel: TLabel;
        StyleBook1: TStyleBook;
        BaseStyleLabel: TLabel;
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.fmx}
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      // Set up BaseStyleLabel as a Style Source
      BaseStyleLabel.StyleName := 'BaseStyle';
      // Set its Style to a Resources Style "STYLE ONE"
      BaseStyleLabel.StyleLookup := 'BaseStyle1';
    
     // Point MyTextLabel to whatever "BaseStyleLabel" is styled as...
       MyTextLabel.StyleLookup := 'BaseStyle'; // also says "STYLE ONE"
    
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      //Change BaseStyle Label to "STYLE TWO" (works OK)
      BaseStyleLabel.StyleLookup := 'BaseStyle2';
    
      // ... BUT MyTextLabel stays as "STYLE ONE"
      // can I repaint???
      //   Auto Cascade?
      //   What about when Other TLabels are part of a different component style?
    
    end;
    
    end.
    

    使用以下样式文件

    object TStyleContainer
      object TLabel
        StyleName = 'BaseStyle1'
        DesignVisible = False
        Height = 17.000000000000000000
        Position.X = 521.000000000000000000
        Position.Y = 432.000000000000000000
        Text = 'STYLE ONE'
        Width = 120.000000000000000000
      end
      object TLabel
        StyleName = 'BaseStyle2'
        DesignVisible = False
        Height = 17.000000000000000000
        Position.X = 521.000000000000000000
        Position.Y = 432.000000000000000000
        Text = 'STYLE TWO'
        Width = 120.000000000000000000
      end
      object TLabel
        StyleName = 'BaseStyle3'
        Height = 17.000000000000000000
        Position.X = 521.000000000000000000
        Position.Y = 432.000000000000000000
        Text = 'STYLE 3'
        Width = 120.000000000000000000
      end
    end
    

1 个答案:

答案 0 :(得分:0)

好的 - 我全力以赴可以提出解决方案。

我浏览了TStyledControl的祖先课程。没有全局触发器可以使样式查找级联。单个组件刷新其样式的事实不会导致任何组件(恰好依赖于组件StyleName)进行刷新。因此,您似乎必须手动找到所有受影响的组件并将其全部更新。

这对我来说不够好,所以我为TStyledControl写了一个帮助方法。

unit FMX.CascadingStyleLookup;
// Written by Glen Kleidon - 2018 - twitter: @sobaldrick4
interface

uses System.SysUtils, FMX.Types, FMX.Forms, FMX.Controls;

Type
  TCascadingStyleLookup = Class Helper for TStyledControl
    Procedure CascadeStyleLookup(AStyleLookup: String); overload;
    procedure CascadeStyleLookup(AStyleLookup: string;
      AComponent: TFMXObject); overload;
    Function FindUltimateParentForm(AChild: TFMXObject): TFMXObject;
  End;

implementation

procedure TCascadingStyleLookup.CascadeStyleLookup(AStyleLookup: String);
var
  lUltimateParent: TFMXObject;
begin
  // Apply New style to myself.
  Self.styleLookup := AStyleLookup;

  // Check if I have dependent Styles.
  if (length(Self.StyleName) = 0) then
    exit;

  // Re-Apply my own style to everything.
  lUltimateParent := Self.FindUltimateParentForm(Self);
  if lUltimateParent <> nil then
    CascadeStyleLookup(Self.StyleName, lUltimateParent);
end;

procedure TCascadingStyleLookup.CascadeStyleLookup(AStyleLookup: string;
  AComponent: TFMXObject);
var
  lChild: TFMXObject;
  lStyledControl: TStyledControl;
begin
  if (AComponent = nil) or (AComponent.Children = nil) then
    exit;

  if (AComponent.InheritsFrom(TStyledControl)) then
  begin
    lStyledControl := AComponent as TStyledControl;
    if SameText(AStyleLookup, lStyledControl.styleLookup) then
    begin
      // re-apply
      lStyledControl.styleLookup := AStyleLookup;
      // Re-cascade this style.
      if (length(lStyledControl.StyleName) > 0) and
        (NOT(SameText(lStyledControl.styleLookup, AStyleLookup))) then
        CascadeStyleLookup(lStyledControl.StyleName);
    end;
  end;
  if AComponent.Children = nil then
    exit;

  // Check the children of this component for the style.
  for lChild in AComponent.Children do
    CascadeStyleLookup(AStyleLookup, lChild);

end;

function TCascadingStyleLookup.FindUltimateParentForm(AChild: TFMXObject)
  : TFMXObject;
begin
  Result := nil;
  if (AChild.Parent <> nil) and (NOT(AChild.Parent.InheritsFrom(TForm))) then
    Result := FindUltimateParentForm(AChild)
  else
    Result := AChild.Parent;
end;

end.

这允许为组件所在的整个表单自动搜索和更新任何嵌套的“stylelookup”属性。

我使用附加组件MyTextLabel2更新了原始示例,该组件取决于MyTextLabel的样式。

因此,现在将BaseStyleLabel设置为任何* BaseStyle1,2 3 *将级联到MyTextLabel。当MyTextLabel更改其样式时,它将级联到MyTextLabel2。因此,只需调用BaseStyleLabel.CascadeStyleLookup('BaseStyle2')即可更新BaseStyleLabel时,所有三个标签都会显示“STYLE TWO”;

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes,
  System.Variants,
  FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
  FMX.CascadingStyleLookup
  ;

type
  TForm1 = class(TForm)
    MyTextLabel: TLabel;
    StyleBook1: TStyleBook;
    BaseStyleLabel: TLabel;
    Button1: TButton;
    MyTextLabel2: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Set up BaseStyleLabel as a Style Source
  BaseStyleLabel.StyleName := 'BaseStyle';
  // Set its Style to a Resources Style "STYLE ONE"
  BaseStyleLabel.StyleLookup := 'BaseStyle1';

  // Point MyTextLabel to whatever "BaseStyleLabel" is styled as...
  MyTextLabel.StyleName := 'MyTextBaseStyle';
  MyTextLabel.StyleLookup := 'BaseStyle'; // also says "STYLE ONE"

  // New component MyTextLabel2 points to whatever "MyTextLabel" is styled as...
  MyTextLabel2.StyleLookup := 'MyTextBaseStyle'; // also says "STYLE ONE",
                                                 // (from MyTextLabel)

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // Change BaseStyle Label to "STYLE TWO" (now cascades to all)
  BaseStyleLabel.CascadeStyleLookup('BaseStyle2');

end;