Перейти к содержанию
  • Регистрация
gonzales

Как убить кнопку кликнув на нее саму

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

Доброго времени суток!

Помогите советом, как убить кнопку кликнув на нее. Создаю на скролбоксе динамический массив кнопок (наследники Trectangle). По нажатию (onClick) любой кнопки из массива весь массив должен уничтожиться. Естественно это приводит к ошибке. В VCL я бы использовал POSTMESSAGE но в firemonkey затрудняюсь ответить. На ум пока приходит только Таймер)))) Но это же жесть)))

Приложение кроссплатформенное, поэтому решение нужно соответствующее.

Заранее всем спасибо за советы. 

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


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

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

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


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

MyControl.Release;

Это отложенное удаление, реализованное самой платформой.

Надо только не забывать после Release заNil-ить ссылку на объект в массиве. Ну и вместо массива лучше использовать дженериковский список.

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

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


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

У TRectangle нет метода release.((

Он никуда не мог деться:

 

Безымянный.png

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


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

Да, извиняюсь, я просто удалял компоненты в цикле

(Form1.RoomsScrollBox.Components[i]).Free;

А когда я написал 

(Form1.RoomsScrollBox.Components[i] as TRoom).Release;

То метод появился. Но это понятно у TComponent его нет, только у TObject. 

Но сути вопроса это не изменило, по Release компонент пропадает, но он еще в памяти, соответственно я не могу создать на его месте другой компонент с таким именем.

 

Вообще задача следующая, есть дерево, находясь на ветке этого дерева я визуализирую все имеющиеся подветки (TRectangle) в ScrollBox. При нажатии на подветку я очищаю весь ScrollBox и выстраиваю новую визуализацию. Может подскажете, как это более грамотно реализовать? 

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


Ссылка на сообщение
Поделиться на другие сайты
1 минуту назад, gonzales сказал:

соответственно я не могу создать на его месте другой компонент с таким именем.

Зачем вообще указывать имя компоненту, создаваемому в runtime? Они прекрасно живут и без этого, а для идентификации конкретного - есть куча свойств TagXXX

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


Ссылка на сообщение
Поделиться на другие сайты
6 минут назад, kami сказал:

Зачем вообще указывать имя компоненту, создаваемому в runtime? Они прекрасно живут и без этого, а для идентификации конкретного - есть куча свойств TagXXX

Обалдеть, спасибо!!!!!!!

Вот изящное решение!!!

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

 

Еще раз спасибо!

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


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

Метод Release объявлен "устаревшим" (10.2.3). Всех поздравляю. Взамен разработчики ничего не предлагают. Теперь корректно разрушить элемент по щелчку на нем не получится. Достаем костыли.

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


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

Метод Release объявлен

метод Release создавал новый поток для каждого удаления, что как бы не очень правильно. Я сделал костыль через список объектов на удаление + таймер

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


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

в XE8 как раз и было реализовано через помещение в объект TPurgatory. (удален из 10)

он как раз и помещал объект к себе в список и удалял "чуть позже" по таймеру (через 10 мс).

unit FMX.Types;

  type
  TPurgatory = class (TComponent)
  public const
    TimerInterval: Integer = 10;
  private
    FInstanceList: TList<Pointer>;
    FTimerHandle: TFMXHandle;
    FPlatformTimer: IFMXTimerService;
    procedure StartTimer;
    procedure StopTimer;
    procedure TimerProc;
    procedure UpdateTimer;
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Clear;
    procedure Add(const Instance: TFmxObject);
    procedure Remove(const Instance: TFmxObject);
    function Contains(const Instance: TFmxObject): Boolean;
  end;

 

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


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

я убиваю в анонимном потоке 

слип(200)

синхронизация (удаление)

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


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

отдельный поток для "убийства" объекта? брутально!

вот как сделано в 10.2.3 :

procedure TFmxObject.Release;
begin
  if not (csDestroying in ComponentState) then
  begin
    if (Application <> nil) and (Action <> nil) then
      Application.UnregisterActionClient(Self);
    Parent := nil;
    TThread.ForceQueue(nil,
      procedure
      begin
        Self.DisposeOf;
      end);
  end;
end;

 

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


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

ну и тут поток. в чем вопрос?

они с этим Release уже мучаются хрен знает сколько и никак до ума не доведут.

основные-то моменты ясны. отцепить от Parent и тогда простой FreeAndNil() вполне подходит. Для ARC он внутри пустой.

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


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

FreeAndNil() не подойдет... проблема в том, что после вызова OnClick() далее еще происходят вызовы методов самого объекта (см. исходники FMX.Forms) и если разрушить объект на OnClick, то будет AV (не каждый раз - а как повезет... ).

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


Ссылка на сообщение
Поделиться на другие сайты
6 часов назад, krapotkin сказал:

ну и тут поток. в чем вопрос?

тут нет потока. forceQueue не использует создание потоков, оно пишет напрямую в структуры синхронизации.

Я у себя уже давно сделал хелпер с одним методом - Release. И его использую не получая сообщений от компилятора.

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


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

@kami все правильно написал. Используйте просто ForceQueue. А внутри либо отлинкуйте контрол от родителя и вызовите Free, либо брутально дергайте DisposeOf.

P.S. документация http://docwiki.embarcadero.com/Libraries/Rio/en/System.Classes.TThread.ForceQueue

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


Ссылка на сообщение
Поделиться на другие сайты
17 часов назад, Brovin Yaroslav сказал:

@kami все правильно написал. Используйте просто ForceQueue. А внутри либо отлинкуйте контрол от родителя и вызовите Free, либо брутально дергайте DisposeOf.

P.S. документация http://docwiki.embarcadero.com/Libraries/Rio/en/System.Classes.TThread.ForceQueue

Намного проще оставить в покое метод Release.

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


Ссылка на сообщение
Поделиться на другие сайты
В 07.01.2019 в 17:45, slav_z сказал:

FreeAndNil() не подойдет... проблема в том, что после вызова OnClick() далее еще происходят вызовы методов самого объекта (см. исходники FMX.Forms) и если разрушить объект на OnClick, то будет AV (не каждый раз - а как повезет... ).

Я имел в виду - в конструкции TTask.Run - Synchronize конечно.
Ну и тот же FreeAndNil  в ForceQueue

Думаю в таком варианте будет все равнозначно.

Главное чтобы DisposeOf не вызывать руками в ARC. Мало ли там в недрах FMX еще кто его потрогать захочет... )))

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

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


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

И еще в тему ForceQueue.

Как-то раз потребовалась мне конструкция типа "отложенное действие после отложенного действия". Дык вот, если сделать вот так:

TThread.ForceQueue(
  procedure
  begin
    SomeAction;
    ForceQueue(SomeAnotherAction);
  end);

то SomeAnotherAction выполнится сразу же вслед за SomeAction, а не на новом витке Application.Idle.
Всё дело в том, что выполнятель Queued-действий просто достает их из списка, пока не закончатся. Т.е. выполняется первый ForceQueue, а вложенный, как таковой, не выполняется: второе действие помещается в список, тут же достается из него и сразу же выполняется!

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

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

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


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

но есть еще проблема:
Если сразу после Release попытаться создать элемент заново (TFrame), то будет ошибка дублирования имени компонента (старый компонент еще жив в списке компонентов родителя).

Поэтому кроме Parent := nil (убрать элемент с экрана) еще необходимо Name := '';

короче...  жуть какая-то.

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


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

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

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


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

P.S. И именно по этой причине, кстати, и был задепрекейчен Release.

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


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

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

теперь все понятно. спасибо.

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


Ссылка на сообщение
Поделиться на другие сайты
12 часов назад, slav_z сказал:

Если сразу после Release попытаться создать элемент заново (TFrame), то будет ошибка дублирования имени компонента (старый компонент еще жив в списке компонентов родителя).

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

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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


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

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

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