Перейти к содержанию
Fire Monkey от А до Я
  • 0

Подписка на получение сообщений в конструкторах компонентов


Viktor Chekrygin

Вопрос

Добрый день.

Только что обновился на Tokyo и сразу влетел на ошибку в компоненте TMediaPlayerControl. Этот компонент вообще не держится на форме в дизайнере и исчезает с формы при первом же клике мыши по форме. Саму ошибку я зарегистрировал в Embarcadero и дело собственно не в ней.

Разбираясь с этой проблемой, я обнаружил следующий непонятный текст в файле FMX.Media.pas:

constructor TMediaPlayerControl.Create(AOwner: TComponent);
begin
  inherited;
  TMessageManager.DefaultManager.SubscribeToMessage(TAfterCreateFormHandle, FormHandleAfterCreated);
  TMessageManager.DefaultManager.SubscribeToMessage(TBeforeDestroyFormHandle, FormHandleBeforeDestroyed);
end;
Здесь интересен метод FormHandleAfterCreated. Его текст такой:

procedure TMediaPlayerControl.FormHandleAfterCreated(const Sender: TObject; const Msg: TMessage);
begin
  if (FMediaPlayer <> nil) and (FMediaPlayer.FMedia <> nil) then
  begin
    if Sender is TForm then
      Parent := TForm(Sender);
  end;
end;
То есть, разработчики здесь через подписанный метод, ни много ни мало, пытаются инициализировать Parent компонента! Но странность здесь  в том, что этот метод никогда не будет вызван для компонента, так как сообщение TAfterCreateFormHandle генерится формой сразу после создания Handle формы, что собственно ясно даже из его названия (HandleAfterCreated). То есть, до того, как будут проинициализированы компоненты формы и вызваны их конструкторы с подпиской на этот класс. Следовательно и Parent компонента TMediPlayerControl в этом случае не будет проинициализирован.

Аналогичное использование подписки на TAfterCreateFormHandle я обнаружил и в компоненте TWebBrowser. То есть и там подписка из конструктора никогда не сработает, но тем не менее она и там есть!

Отсюда вопрос. А корректно ли вообще использовать подписки на TAfterCreateFormHandle в конструкторах компонентов? Или здесь есть какой-то скрытый смысл?

PS. Может быть дело в том, что разработчики компонент сами были введены в заблуждение следующими строками файла FMX.Forms.pas?

  /// <summary>Notification about creating real form</summary>
  TAfterCreateFormHandle = class(System.Messaging.TMessage<TCommonCustomForm>);

То есть, здесь в комментарии сказано, что класс TAfterCreateFormHandle это уведомление о создании формы, а не уведомление, о создании Handle формы, как следует даже из его названия.
 

Изменено пользователем Viktor Chekrygin
Ссылка на комментарий

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

  • 0
  • Модераторы

Не будем разбирать конкретно этот случай, пока Токио очень сырой.

Сломали всё что можно было. (обсуждали в чате)

Чтобы не плодить темы на форуме, вернитесь на Берлин апдейт 2, до какого нить хот-фикса от Ембы.

Ссылка на комментарий
  • 0
  • Администраторы

 

3 часа назад, Viktor Chekrygin сказал:

Notification about creating real form

Говорит, что уведомление о РЕАЛЬНОМ создании формы. Форма в обезьяне создается двумя фазами:

  1. Создание экземпляра формы и контролов
  2. Создание нативного хендла формы. Это и есть реальная физическая форма.

Это уведомление, как раз и сообщает, что есть уже у формы хендл и можно к нему подстроить браузер, проигрыватель и тд.

 

Ссылка на комментарий
  • 0

Не совсем так. Дело в том, что во время генерирования сообщения TAfterCreateFormHandle на форме ещё нет компонентов. То есть, сообщение есть, а подписок на этот класс ещё нет. Они будут позднее, на этапе размещения компонентов на форме. А выдаётся это сообщение только один раз, при создании Handle. Таким образом подписываться на него после этого в конструкторах компонентов нет никакого смысла. 

Было бы корректнее подписаться на сообщение TFormsCreatedMessage, то есть, после размещения всех компонентов на форме. В этом случае было бы всё так, как вы пишите. Форма с компонентами готова, подписки готовы, можно выдавать и сообщение. А сейчас всё наоборот получилось.

Изменено пользователем Viktor Chekrygin
Ссылка на комментарий
  • 0
  • Администраторы

Раньше хендл пересоздавался несколько раз. Это приводит к повторной отправке сообщения. Но видимо в последних версиях это поломали.

Как вариант можно вызывать Recreate у формы, чтобы принудительно попробовать пересоздать хендл

Ссылка на комментарий
  • 0
  • Администраторы

А вообще у медиа проигрывателя родитель и так устанавливается. Но то, что родитель меняется - это явный баг. Там максимум хендл мог у окна браться.

Ссылка на комментарий
  • 0
5 часов назад, Равиль Зарипов (ZuBy) сказал:

Не будем разбирать конкретно этот случай, пока Токио очень сырой.

Сломали всё что можно было. (обсуждали в чате)

Чтобы не плодить темы на форуме, вернитесь на Берлин апдейт 2, до какого нить хот-фикса от Ембы.

Что ж вы такое интересное в чате обсуждаете, это же тема не на один час, и даже не на месяц. Могли бы и тему создать. Наверное потому что бот Ярослава постит и закрывает темы, так можно было в той же теме (Whats New in Tokyo) по обсуждать. @brovin-yaroslav это вам на заметку, большая просьба не закрывать темы-новости.

Изменено пользователем ENRGY
Ссылка на комментарий
  • 0
19 часов назад, Brovin Yaroslav сказал:

Раньше хендл пересоздавался несколько раз. Это приводит к повторной отправке сообщения. Но видимо в последних версиях это поломали.

Как вариант можно вызывать Recreate у формы, чтобы принудительно попробовать пересоздать хендл

Скорее всего так и было. Сначала изменили компонент TMediaPlayerControl, всё работало, затем что-то изменили в форме, а когда всё собрали в кучу, TMediaPlayerControl перестал работать.

Recreate помогает в плане того, что да, в realtime подписка по нему срабатывает. Если честно, мне вообще не понятен изначальный смысл Recreate. В каких случаях он может быть полезен, кроме как для аварийного исправления таких вот ошибок? Для чего может понадобиться менять Handle во время работы программы?

19 часов назад, Brovin Yaroslav сказал:

А вообще у медиа проигрывателя родитель и так устанавливается. Но то, что родитель меняется - это явный баг. Там максимум хендл мог у окна браться.

У TMediaPlayerControl дело не в родителе. Parent там указывает на форму. Но вот на форме компонент не держится и исчезает после первого клика. В Берлине же всё работает. В общем в Токио, чего-то там сломали. Так и не понял, в чём там дело.

Ссылка на комментарий
  • 0

Ярослав, спасибо за ответ. Теперь буду знать. Может быть ответите ещё на один вопрос? В исходниках в полях классов я часто вижу такие конструкции:

[weak] FForm: TCommonCustomForm;

Как это можно объяснить? Для интерфейсов, всё понятно. Но для классов? Как это можно использовать? Понятно, что TCommonCustomForm интерфейсный класс. Но слабая ссылка на класс предполагает, что поле будет считаться классом, а не интерфейсом. Как-то не достаточно освещён этот вопрос. 

Изменено пользователем Viktor Chekrygin
Ссылка на комментарий
  • 0
  • Администраторы

на здоровье.

22 минуты назад, Viktor Chekrygin сказал:

Как это можно объяснить?

http://yaroslavbrovin.ru/object_life_cycle_in_delphi_part_2_android_ios-ru/

Ссылка на комментарий
  • 0

Ну я в общем-то так и предполагал, что это для ARC для мобильных платформ сделано. В вашей статье информация по этой теме собрана воедино. Как раз этого лично мне не хватало. Спасибо огромное.

Ссылка на комментарий

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

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

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

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

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

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

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

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

  • Последние посетители   0 пользователей онлайн

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