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

Уничтожение фрейма при нажатии на кнопку


Ra72

Вопрос

Есть фрейм, на фрейме кнопка. Фрейм создается динамически. При нажатии на кнопку, осуществляем действие и уничтожаем фрейм. Приложение валится с AV на секции finally.

procedure TControl.Click;
var
  LAction: TCustomAction;
begin
...
        if Assigned(FOnClick) then
          FOnClick(Self);
  finally
    if ActionClient and (Action is TCustomAction) then
      TCustomAction(Action).ShortCutPressed := False;
  end;
end;

Как правильно уничтожить фрейм по нажатию на кнопку, которая на нем?

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

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

  • 0

При нажатии на кнопку отправить сообщение главной форме, а в обработчике этого сообщения, на который главная форма (условно, можно вообще любую форму) подписана - удалять соответственно этот фрейм.

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

у фрейма:

  private
    fOnCloseInfo : TNotifyEvent;
  protected
    procedure DoOnCloseInfo; dynamic;
  public
    { Public declarations }
    /// <summary> Обработчик события закрытия фрейма </summary>
    property OnCloseInfo : TNotifyEvent read fOnCloseInfo write fOnCloseInfo;
  end;

procedure TframeInfo.DoOnCloseInfo;
begin
  // Если обработчик назначен, то запускаем его.
  if Assigned(fOnCloseInfo) then
    fOnCloseInfo(Self);
end;

при инициализации фрейма (не важно где и как - когда создается):

frameInfo.OnCloseInfo := fmMain.DoOnCloseInfo;

при нажатии на кнопку:

DoOnCloseInfo;

в главной (или любой другой форме, которая будет отрабатывать нажатие кнопки во фрейме):

// можно в любой секции, смотря что нам нужно
procedure DoOnCloseInfo(Sender: TObject);


procedure TfmMain.DoOnCloseInfo(Sender: TObject);
begin
  if Assigned(frameInfo) then
    FreeAndNil(frameInfo);
end;

типа так...

Ссылка на комментарий
  • 1
2 часа назад, AlexG сказал:

типа так...

так не пойдет

На Windows - получим тот же AV, ибо по нажатию на кнопку вызовется DoOnCloseInfo, по завершению которой фрейма и кнопки на нем уже не будет. А во внутренностях TControl по завершению вызова OnClick еще идет обращение к себе.

На мобильной платформе - ничего не случится, потому что ARC и фрейм еще присутствует у своего родителя, простое за nil-ивание ссылки ничего не даст.

 

Правильный выход - непосредственно в обработчике кнопки сделать fr.Release;

Изменено пользователем kami
Ссылка на комментарий
  • 0
3 минуты назад, kami сказал:

так не пойдет

На Windows - получим тот же AV, ибо по нажатию на кнопку вызовется DoOnCloseInfo, по завершению которой фрейма уже не будет. А во внутренностях TControl по завершению вызова OnClick еще идет обращение к себе.

На мобильной платформе - ничего не случится, потому что ARC и фрейм еще присутствует у своего родителя, простое за nil-ивание ссылки ничего не даст.

 

Правильный выход - непосредственно в обработчике кнопки сделать fr.Release;

Именно так и пойдет! И под виндой и в других платформах )

Во-первых - DoOnCloseInfo лишь вызовет обработчик этого события в главной форме.

Разве что - только добавить синхронизацию

procedure TframeInfo.DoOnCloseInfo;
begin
  if Assigned(fOnCloseInfo) then
    TThread.Synchronize(nil, procedure
    begin
      fOnCloseInfo(Self);
    end);
end;
Ссылка на комментарий
  • 0
2 часа назад, AlexG сказал:

Во-первых - DoOnCloseInfo лишь вызовет обработчик этого события в главной форме.

Нет, не пойдет. Потому что DoOnCloseInfo по прежнему вызывается из внутренностей TButton.Click. Если ваш код отрабатывает на Windows - это ваша недоработка, а не показатель правильности. Причины я изложил выше. А на мобильных платформах с фреймом визуально просто ничего не произойдет. Причины опять-таки изложил выше.

2 часа назад, AlexG сказал:

Разве что - только добавить синхронизацию

И в таком виде тоже не пойдет.

Потому что Synchronize и Queue, будучи вызванными из главного потока, моментально передают управление в метод, а не дожидаются очередного витка выборки сообщений у Application. В таком виде вы просто добавляете несколько вложенных вызовов, увеличивая занятость стека. Не меняя при этом концепцию работы.

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

Нет, не пойдет. Потому что DoOnCloseInfo по прежнему вызывается из внутренностей TButton.Click. Если ваш код отрабатывает на Windows - это ваша недоработка, а не показатель правильности. Причины я изложил выше. А на мобильных платформах с фреймом визуально просто ничего не произойдет. Причины опять-таки изложил выше.

И в таком виде тоже не пойдет.

Потому что Synchronize и Queue, будучи вызванными из главного потока, моментально передают управление в метод, а не дожидаются очередного витка выборки сообщений у Application. В таком виде вы просто добавляете несколько вложенных вызовов, увеличивая занятость стека. Не меняя при этом концепцию работы.

Согласен!

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

В качестве послесловия.
Деструктор объекта не может быть вызван внутри метода этого объекта (самоубийства запрещены). Всегда можно поставить точку останова на вызов метода Free/FreeAndNil. И внимательно посмотреть стек вызова, если где-то в стеке вызова присутствует разрушаемый объект, то это не правильно. Сложности добавляет то, что это не обязательно приводит возникновению AV, вполне может быть, что у вас всё будет работать без ошибок, а на другом компьютере, или на другой платформе с ошибками.
Release на самом деле приводит к отложенному удалению не внутри вызывающего метода, т.е. объект просто помечается как готовый к удалению.

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

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

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

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

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

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

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

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

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

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