Перейти к содержанию

Вопросы

ЧАВО:

Опишу "багофичу" на которую я наткнулся.

Предположим что вы пишете свой компонент, наследуемый от TStyledControl (или любого другого компонента, который происходит от  TStyledControl), для доступа к элементам стиля обычно используют FindStyleResource('ИмяРесурса') (есть вариант в виде FindStyleResource<Класс>('ИмяРесурса', Переменная)) , например компонент TImageControl получает Image так:

procedure TImageControl.ApplyStyle;
begin
  inherited;
  if FindStyleResource<TImage>('image', FImage) then
    UpdateImage;
end;

И FindStyleResource работает отлично, пока в дереве стиля искомый объект лежит на НЕ TStyledControl-ах, то есть FindStyleResource будет успешно находить объект, который расположен на TRectangle, но не найдет его же, но на TPanel!

Пример:

Код, в процедуре ApplyStyle:

procedure TEsImageSelection.ApplyStyle;
var
  T: TControl;
begin
  inherited ApplyStyle;
  if FindStyleResource<TControl>('selection', T) then
    ShowMessage('"selection" founded!');
end;

Что делает данный код? - При нахождении стилевого объекта выдает соответствующее сообщение.

Рассмотрим стиль:

zz.png

Как видите в варианте A, "Selection" лежит на НЕ наследнике TStyledControl. Запустив программу можно убедиться что FindStyleResource<TControl>('selection', T) найдет объект "Selection".

В варианте B, при запуске можно с удивлением обнаружить что FindStyleResource<TControl>('selection', T) не находит объект "Selection"!

Почему так?

Судя по исходникам поиск во вложенных TStyledControl-ах сломан специально, дабы не всплывали еще большие глюки\проблемы.(но я не изучал вопрос очень подробно, во внутренний код работы с загрузкой и поиском стилей - кромешный ад, с наслаиванием истории Fire-Monkey разных лет).

Как можно обойти проблему?

Я нашел следующее решение:

(Однако я совершенно не уверен в отсутствии побочных эффектов, возможно @Brovin Yaroslav сможет прокомментировать его?)

Данный код находит искомый стилевой объект, в отличии от FindStyleResource.

procedure TEsImageSelection.ApplyStyle;
var
  T: TControl;
begin
  inherited ApplyStyle;
  
  T := nil;
  EnumObjects(
    function (Obj: TFmxObject): TEnumProcResult
    begin
      if Obj.StyleName.ToLower = 'selection' then
      begin
        T := TControl(Obj);
        Result := TEnumProcResult.Stop;
      end else
        Result := TEnumProcResult.Continue;
    end);

  if T <> nil then
    ShowMessage('"selection" founded!');
end;

 

Процедура-замена FindStyleResource, работает как ожидается:

type
  TOpenStyledControl = class(TStyledControl);

function EsFindStyleResource(Self: TStyledControl; StyleName: string): TFmxObject;
var
  StyleObject: TFmxObject;
begin
  // если Self.ChildrenCount < 1 то в компоненте не загружен стиль,
  // т.к. известно что главный эллемент стиля ВСЕГДА находиться по нулевому индексу.
  if (TOpenStyledControl(Self).ResourceLink = nil) or (Self.ChildrenCount < 1) then
    Exit(nil);

  StyleObject := nil;

  Self.Children[0].EnumObjects(
    function (Obj: TFmxObject): TEnumProcResult
    begin
      if Obj.StyleName.ToLower = StyleName.ToLower then
      begin
        Result := TEnumProcResult.Stop;
        StyleObject := Obj;
      end else
        Result := TEnumProcResult.Continue;
    end);

  Result := StyleObject;
end;

 

Отредактировал Error

Поделиться сообщением


Ссылка на сообщение

Рекомендуемые сообщения

  • 0

Не ищет потому что так и не планировалось. Так как компонент не обязательно используется в стиле.

Например по второй картинке:

selection является дочерним к панели. И есть предположение, что FindStyleResource должен найти его. С одной стороны логично.

С другой стороны такая же картинка может быть на форме. И в этом случае FindStyleResource уже не должен найти selection. По скольку в FindStyleResource нету контекста, в чем мы ищем, поэтому он всегда ищет объект только в стиле для стилевых компонентов.

Поделиться сообщением


Ссылка на сообщение
  • 0

Да и вообще использование вложенных стилей не предусматривалось и никогда не рассматривалось в таких примерах. Поскольку любая фича для стилей сказывается плохо на производительности.

Поделиться сообщением


Ссылка на сообщение
  • 0
1 час назад, Brovin Yaroslav сказал:

Не ищет потому что так и не планировалось. Так как компонент не обязательно используется в стиле.

Например по второй картинке:

selection является дочерним к панели. И есть предположение, что FindStyleResource должен найти его. С одной стороны логично.

С другой стороны такая же картинка может быть на форме. И в этом случае FindStyleResource уже не должен найти selection. По скольку в FindStyleResource нету контекста, в чем мы ищем, поэтому он всегда ищет объект только в стиле для стилевых компонентов.

Собственно, я предполагал что это так, но насколько плох мой подход по обходу его?

Я проверял, да - если на мой компонент кинуть кнопку и прописать ей StyleName := 'selection', то при отсутствии в стиле объекта 'selection', мой метод найдет кнопку, что неверно, однако зачем вообще прописывать кнопке на форме StyleName?

 

Кроме того, я придумал другой метод, который ищет только среди объектов стиля, то есть не обладает недостатком, который я привел выше.

Требую критики :)

function EsFindStyleResource(Self: TStyledControl; StyleName: string): TFmxObject;
var
  StyleObject: TFmxObject;
begin
  // если Self.ChildrenCount < 1 то в компоненте не загружен стиль,
  // т.к. известно что главный эллемент стиля ВСЕГДА находиться по нулевому индексу.
  if Self.ChildrenCount < 1 then
    Exit(nil);

  StyleObject := nil;

  Self.Children[0].EnumObjects(
    function (Obj: TFmxObject): TEnumProcResult
    begin
      if Obj.StyleName.ToLower = StyleName.ToLower then
      begin
        Result := TEnumProcResult.Stop;
        StyleObject := Obj;
      end else
        Result := TEnumProcResult.Continue;
    end);

  Result := StyleObject;
end;

procedure TEsImageSelection.ApplyStyle;
var
  T: TControl;
begin
  inherited ApplyStyle;

  T := EsFindStyleResource(Self, 'selection') as TControl;

  if T <> nil then
    ShowMessage('"selection" founded!');
end;

Имхо, это не плохой метод, главное чтобы не было дополнительных подводных камней...

Поделиться сообщением


Ссылка на сообщение
  • 0
57 минут назад, Brovin Yaroslav сказал:

Да и вообще использование вложенных стилей не предусматривалось и никогда не рассматривалось в таких примерах. Поскольку любая фича для стилей сказывается плохо на производительности.

Да производительность стилей, это конечно отдельная тема...

Поделиться сообщением


Ссылка на сообщение
  • 0
2 часа назад, Error сказал:

Требую критики :)

Костыль: Self.Children[0] - Объект в стиле, использующий стиль может его и не загрузить, но при этом иметь вложенные контролы. Поэтому физически у него еще нет стиля, но один контрол внутри есть. (Подсказка, смотреть ResourceLink)

Поделиться сообщением


Ссылка на сообщение
  • 0
22 минуты назад, Brovin Yaroslav сказал:

Костыль: Self.Children[0] - Объект в стиле, использующий стиль может его и не загрузить, но при этом иметь вложенные контролы. Поэтому физически у него еще нет стиля, но один контрол внутри есть. (Подсказка, смотреть ResourceLink)

Согласен, однако вызывать EsFindStyleResource я собираюсь только в ApplyStyle, после inherited ApplyStyle, и как я понимаю, стиль к этому моменту уже будет загружен...

Но костыль, да, поэтому с учетом замечания, я переписал процедуру EsFindStyleResource, теперь, как я понимаю все хорошо? :)

type
  TOpenStyledControl = class(TStyledControl);

function EsFindStyleResource(Self: TStyledControl; StyleName: string): TFmxObject;
var
  StyleObject: TFmxObject;
begin
  // если Self.ChildrenCount < 1 то в компоненте не загружен стиль,
  // т.к. известно что главный эллемент стиля ВСЕГДА находиться по нулевому индексу.
  if (TOpenStyledControl(Self).ResourceLink = nil) or (Self.ChildrenCount < 1) then
    Exit(nil);

  StyleObject := nil;

  Self.Children[0].EnumObjects(
    function (Obj: TFmxObject): TEnumProcResult
    begin
      if Obj.StyleName.ToLower = StyleName.ToLower then
      begin
        Result := TEnumProcResult.Stop;
        StyleObject := Obj;
      end else
        Result := TEnumProcResult.Continue;
    end);

  Result := StyleObject;
end;

 

Поделиться сообщением


Ссылка на сообщение

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


  • Похожий контент

    • От trl
      Не нашел ответа на форуме.  не могу понять почему FindStyleResource  не возвращает объекта.
      procedure TMainForm.Button1Click(Sender: TObject); var item :  TListBoxItem;       lbName:TLabel; begin     Item := TListBoxItem.Create(Self);     Item.Parent := ListBox;      Item.StyleLookup := 'lyItemBoxDetail';        lbName := Self.FindStyleResource('lbname') as TLabel; // Здесь получаю nil     ShowMessage(  Item.StylesData['lbname.Text'].AsString) // А этот код работает end;  
    • От max7ka
      Подскажите где можно найти структуру StyleLookup для объектов, чтобы можно было использовать в FindStyleResource?
       
      Например
       
       CheckBox
          checkboxunchecked
          checkboxchecked
          checkmark
          ...
       
       TGrid
         header
         focus
         selection
         ...
    • От Ra72
      Создал компонент:
      type TTube = class(TFmxObject) private FTheColor: TAlphaColor; public constructor Create(AOwner: TComponent); override; published property TheColor: TAlphaColor read FTheColor write FTheColor; end; constructor TTube.Create(AOwner: TComponent); begin inherited; FTheColor := $FFFFFFFF; end; Вставил его в StyleBook.
      object TTube StyleName = 'tube1' TheColor = claViolet end Ищу его в стилизованном контроле:
       
      var tube: TTube; begin tube := ATarget.FindStyleResource('tube1') as TTube; Не находится компонент. 
      Стандартные Text, Rectangle... находятся таким способом, а свой - нет.
      Что я делаю не так?
    • От estra
      Редактирую стиль, добавляю к нему компонент TImage и для свойства RotateAngle создаю FloatAnimation (параметры анимации на скрине). Но при запуске никакой анимации нет. Почему? И как все же добиться работоспособности анимации для элемента стиля?
    • От estra
      Почему метод FindStyleResource  в OnCreate и OnShow формы возвращает nil, а после запуска программы (в Button1.OnClick) возвращает указатель на объект? Как получить доступ к объекту стиля в момент запуска программы?
    • От Nix0N
      Для примера:
       
      Есть объект ListBoxItem. В StyleBook загружен стиль по умолчанию. Для итема лист бокса задан стандартный стиль:
      ListBoxItem.Stylename = "listboxitemlabel" Если заглянуть в StyleBook, то мы увидим что "listboxitemlabel" это TLayout.
      Каким образом можно изменить/получить свойства этого объекта, к примеру текущую его высоту для нашего ListBoxItem?
  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...