• 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;

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

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


Ссылка на сообщение
Поделиться на других сайтах

9 ответов на этот вопрос

  • 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;

типа так...

Rusland понравилось это

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


Ссылка на сообщение
Поделиться на других сайтах
  • 0

или воспользоваться TThread.Queue(procedure begin ....... end);

Изменено пользователем krapotkin

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


Ссылка на сообщение
Поделиться на других сайтах
  • 1
2 часа назад, AlexG сказал:

типа так...

так не пойдет

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

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

 

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

Изменено пользователем kami
Ra72 понравилось это

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


Ссылка на сообщение
Поделиться на других сайтах
  • 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
Error, AlexG и rareMax понравилось это

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


Ссылка на сообщение
Поделиться на других сайтах
  • 0
3 часа назад, kami сказал:

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

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

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

Согласен!

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


Ссылка на сообщение
Поделиться на других сайтах
  • 0
16 часов назад, kami сказал:

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

Вот это работает, спасибо!

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


Ссылка на сообщение
Поделиться на других сайтах
  • 1

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

rareMax, Ra72, Error и 2 другим понравилось это

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


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!


Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.


Войти сейчас

  • Похожие публикации

    • Автор: Ktulho
      Чтобы использовать Drag and Drop, устанавливаю у компонента TListBoxItem свойство HitTest:= True.
      Почему у этого компонента не срабатывает событие OnClick?
      P.S. Win32, XE7.
    • Автор: haword
      Уперся в проблему и думаю как ее можно красиво решить. Короче смысл такой. На форме один ListView. В нем список. При выбора записи нужно перезаполнить ListView данными из подкатегории на которую ссылается выбранное поле. Проблема в том что в OnItemClick нельзя очищать ListView, после выхода из обработки выскакивает ошибка обращения к этому Item так как оно используется после отработки события. Попробовал сделать на OnClick. Вышла другая проблема, при использовании тачэкрана, когда HasTouchTracking выдает true, приходится два раза нажимать на поле или задержку пальцем делать что бы получить нужные данные через Selected или ItemIndex. Пока что придумал так это сделать два ListView и через visible переключать их. Но это грабли. Может у кого то есть более красивое решение? 
    • Автор: d7d1cd
      Привет всем.
       
      Столкнулся то ли с багом XE7, то ли с не знанием. Проект FMX под Windows. На форме Edit1, создаю событие Edit1Click. При запуске приложения и щелчке на Edit1 событие Edit1Click не вызывается. В чем причина?
    • Автор: Tarik02
      Смотрел вот http://fire-monkey.ru/topic/619-pochemu-u-menia-ne-rabotaet-onclick-po-3d-obektu/, но там ничего не понял, у меня есть форма TForm3D, и на ней TDummy, а на этом TDummy находится TModel3D. Вот при клике на эту модель, нужно чтобы работало событие OnClick. Но оно не работает!
    • Автор: Igor
      Порой прослеживается такой глюк: создаю объекты в run-time, создаю обработчики событий, процедуры объявлены, но клик по объекту не работает, в другие разы при таком же подходе работает.
      Решал проблему отключением HitTest родительского объекта объектов по которым кликаю, + BringToFront SendToBack помогал кажется. Сейчас же клик не работает, хит тесты и бринги-сенды не помогают.
      Куда смотреть?
    • Автор: estra
      Ярослав,

      По каким соображениям у форм отсутствуют события OnClick и OnDblClick?
      Они бы очень даже не помешали, введите их со следующим апдейтом или в крайнем случае в XE7.
  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу