Firemonkey: каскадное изменение стиля поиска для FMXObject, где другие объекты наследуют стилевое имя
Я не уверен, возможно ли это, но мне кажется, что так и должно быть. По сути, я хочу, чтобы все компоненты обновляли свои стили при изменении StyleLookup.
У меня есть FMXComponent, который называется TLabel BaseStyleLabel
, StyleName
Свойство компонента - BaseStyle. Он сам ищет свой стиль из ресурса стиля, поэтому его StyleLookup
свойство установлено в "BaseStyle1". У меня также есть "BaseStyle2", "BaseStyle3"...
У меня есть зависимый Tlabel, который называется MyTextLabel
И его StyleLookup
свойство установлено в BaseStyle
то есть StyleName BaseStyleLabel
,
Кажется, что все работает нормально. я вижу это MyTextLabel
наследует стиль от MyBaseStyle
BaseStyle1.
Когда я выполняю эту строку кода
BaseStyleLabel.StyleLookup := 'BaseStyle2';
Self.repaint; // repaint whole form
Я ожидаю что BaseStyleLabel
меняется на "BaseStyle2" (что он делает). Тем не мение, MyTextLabel
также должен изменить стиль и затем выглядеть как "BaseStyle2", но это не так: он остается BaseStyle1
;
Спецификатор заключается в том, что BaseLabel и MyTextLabel также являются источниками стилей. На самом деле они не являются компонентом, созданным в форме, они создаются стилем.
Итак, мой вопрос заключается в следующем.
- Этот подход действителен?
- Существует ли стандартный подход, например, использование объекта стиля, который я могу обновить?
- Разве я не обновил правильную вещь или;
- использовал неправильный метод для обновления, может быть, ApplyStyle?
... РЕДАКТИРОВАТЬ.... Ниже запрошенный пример...
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 ответ
ОК - я работал через все это, может придумал решение.
Я просмотрел класс предков для 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. Таким образом, все три метки будут отображать "STYLE TWO", когда BaseStyleLabel обновляется простым вызовом BaseStyleLabel.CascadeStyleLookup('BaseStyle2')
;
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;