gonzales Опубликовано 18 января, 2017 Опубликовано 18 января, 2017 Доброго времени суток! Помогите советом, как убить кнопку кликнув на нее. Создаю на скролбоксе динамический массив кнопок (наследники Trectangle). По нажатию (onClick) любой кнопки из массива весь массив должен уничтожиться. Естественно это приводит к ошибке. В VCL я бы использовал POSTMESSAGE но в firemonkey затрудняюсь ответить. На ум пока приходит только Таймер)))) Но это же жесть))) Приложение кроссплатформенное, поэтому решение нужно соответствующее. Заранее всем спасибо за советы. Цитата
gonzales Опубликовано 18 января, 2017 Автор Опубликовано 18 января, 2017 PS. Причем, что самое странное ошибка возникает не всегда, она плавающая, причем по какой-то неведомой причине возникает только при клике на третью кнопку))). Сама ошибка никак не сказывается на работоспособности программы, все продолжает работать корректно и больше ошибка не повторяется, но при перезапуске программы опять всплывает Цитата
kami Опубликовано 18 января, 2017 Опубликовано 18 января, 2017 (изменено) MyControl.Release; Это отложенное удаление, реализованное самой платформой. Надо только не забывать после Release заNil-ить ссылку на объект в массиве. Ну и вместо массива лучше использовать дженериковский список. Изменено 18 января, 2017 пользователем kami Brovin Yaroslav 1 Цитата
gonzales Опубликовано 18 января, 2017 Автор Опубликовано 18 января, 2017 У TRectangle нет метода release.(( Цитата
kami Опубликовано 18 января, 2017 Опубликовано 18 января, 2017 1 час назад, gonzales сказал: У TRectangle нет метода release.(( Он никуда не мог деться: RoschinSpb и Brovin Yaroslav 2 Цитата
gonzales Опубликовано 19 января, 2017 Автор Опубликовано 19 января, 2017 Да, извиняюсь, я просто удалял компоненты в цикле (Form1.RoomsScrollBox.Components[i]).Free; А когда я написал (Form1.RoomsScrollBox.Components[i] as TRoom).Release; То метод появился. Но это понятно у TComponent его нет, только у TObject. Но сути вопроса это не изменило, по Release компонент пропадает, но он еще в памяти, соответственно я не могу создать на его месте другой компонент с таким именем. Вообще задача следующая, есть дерево, находясь на ветке этого дерева я визуализирую все имеющиеся подветки (TRectangle) в ScrollBox. При нажатии на подветку я очищаю весь ScrollBox и выстраиваю новую визуализацию. Может подскажете, как это более грамотно реализовать? Цитата
kami Опубликовано 19 января, 2017 Опубликовано 19 января, 2017 1 минуту назад, gonzales сказал: соответственно я не могу создать на его месте другой компонент с таким именем. Зачем вообще указывать имя компоненту, создаваемому в runtime? Они прекрасно живут и без этого, а для идентификации конкретного - есть куча свойств TagXXX Brovin Yaroslav и gonzales 2 Цитата
gonzales Опубликовано 19 января, 2017 Автор Опубликовано 19 января, 2017 6 минут назад, kami сказал: Зачем вообще указывать имя компоненту, создаваемому в runtime? Они прекрасно живут и без этого, а для идентификации конкретного - есть куча свойств TagXXX Обалдеть, спасибо!!!!!!! Вот изящное решение!!! Действительно, все работает без всяких имен. Вот что значит привычка, всегда писал с присвоением имени)))) Даже не думал, что можно не указывать имя вообще! Еще раз спасибо! Цитата
slav_z Опубликовано 3 января, 2019 Опубликовано 3 января, 2019 Метод Release объявлен "устаревшим" (10.2.3). Всех поздравляю. Взамен разработчики ничего не предлагают. Теперь корректно разрушить элемент по щелчку на нем не получится. Достаем костыли. Цитата
Nick Peterson Опубликовано 3 января, 2019 Опубликовано 3 января, 2019 2 часа назад, slav_z сказал: Метод Release объявлен метод Release создавал новый поток для каждого удаления, что как бы не очень правильно. Я сделал костыль через список объектов на удаление + таймер Цитата
slav_z Опубликовано 3 января, 2019 Опубликовано 3 января, 2019 в 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; Ingalime 1 Цитата
FREEFAR Опубликовано 5 января, 2019 Опубликовано 5 января, 2019 я убиваю в анонимном потоке слип(200) синхронизация (удаление) Цитата
slav_z Опубликовано 5 января, 2019 Опубликовано 5 января, 2019 отдельный поток для "убийства" объекта? брутально! вот как сделано в 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; Цитата
krapotkin Опубликовано 7 января, 2019 Опубликовано 7 января, 2019 ну и тут поток. в чем вопрос? они с этим Release уже мучаются хрен знает сколько и никак до ума не доведут. основные-то моменты ясны. отцепить от Parent и тогда простой FreeAndNil() вполне подходит. Для ARC он внутри пустой. Цитата
slav_z Опубликовано 7 января, 2019 Опубликовано 7 января, 2019 FreeAndNil() не подойдет... проблема в том, что после вызова OnClick() далее еще происходят вызовы методов самого объекта (см. исходники FMX.Forms) и если разрушить объект на OnClick, то будет AV (не каждый раз - а как повезет... ). Цитата
kami Опубликовано 7 января, 2019 Опубликовано 7 января, 2019 6 часов назад, krapotkin сказал: ну и тут поток. в чем вопрос? тут нет потока. forceQueue не использует создание потоков, оно пишет напрямую в структуры синхронизации. Я у себя уже давно сделал хелпер с одним методом - Release. И его использую не получая сообщений от компилятора. Brovin Yaroslav 1 Цитата
Администраторы Brovin Yaroslav Опубликовано 7 января, 2019 Администраторы Опубликовано 7 января, 2019 @kami все правильно написал. Используйте просто ForceQueue. А внутри либо отлинкуйте контрол от родителя и вызовите Free, либо брутально дергайте DisposeOf. P.S. документация http://docwiki.embarcadero.com/Libraries/Rio/en/System.Classes.TThread.ForceQueue Yarpda и Виталий Иванов 2 Цитата
slav_z Опубликовано 8 января, 2019 Опубликовано 8 января, 2019 17 часов назад, Brovin Yaroslav сказал: @kami все правильно написал. Используйте просто ForceQueue. А внутри либо отлинкуйте контрол от родителя и вызовите Free, либо брутально дергайте DisposeOf. P.S. документация http://docwiki.embarcadero.com/Libraries/Rio/en/System.Classes.TThread.ForceQueue Намного проще оставить в покое метод Release. Ingalime 1 Цитата
krapotkin Опубликовано 8 января, 2019 Опубликовано 8 января, 2019 (изменено) В 07.01.2019 в 17:45, slav_z сказал: FreeAndNil() не подойдет... проблема в том, что после вызова OnClick() далее еще происходят вызовы методов самого объекта (см. исходники FMX.Forms) и если разрушить объект на OnClick, то будет AV (не каждый раз - а как повезет... ). Я имел в виду - в конструкции TTask.Run - Synchronize конечно. Ну и тот же FreeAndNil в ForceQueue Думаю в таком варианте будет все равнозначно. Главное чтобы DisposeOf не вызывать руками в ARC. Мало ли там в недрах FMX еще кто его потрогать захочет... ))) Изменено 8 января, 2019 пользователем krapotkin Цитата
kami Опубликовано 8 января, 2019 Опубликовано 8 января, 2019 (изменено) И еще в тему ForceQueue. Как-то раз потребовалась мне конструкция типа "отложенное действие после отложенного действия". Дык вот, если сделать вот так: TThread.ForceQueue( procedure begin SomeAction; ForceQueue(SomeAnotherAction); end); то SomeAnotherAction выполнится сразу же вслед за SomeAction, а не на новом витке Application.Idle. Всё дело в том, что выполнятель Queued-действий просто достает их из списка, пока не закончатся. Т.е. выполняется первый ForceQueue, а вложенный, как таковой, не выполняется: второе действие помещается в список, тут же достается из него и сразу же выполняется! Как результат - при таком вызове де-факто получается срабатывает только первый ForceQueue, а вместо второго выполняется прямой вызов действия. Изменено 8 января, 2019 пользователем kami Цитата
slav_z Опубликовано 8 января, 2019 Опубликовано 8 января, 2019 но есть еще проблема: Если сразу после Release попытаться создать элемент заново (TFrame), то будет ошибка дублирования имени компонента (старый компонент еще жив в списке компонентов родителя). Поэтому кроме Parent := nil (убрать элемент с экрана) еще необходимо Name := ''; короче... жуть какая-то. Цитата
Администраторы Brovin Yaroslav Опубликовано 8 января, 2019 Администраторы Опубликовано 8 января, 2019 Надо уметь мыслить в терминах асинхронного программирования. Тогда такие вещи не будут удивлять и не будет проблем. krapotkin 1 Цитата
Администраторы Brovin Yaroslav Опубликовано 8 января, 2019 Администраторы Опубликовано 8 января, 2019 P.S. И именно по этой причине, кстати, и был задепрекейчен Release. krapotkin 1 Цитата
slav_z Опубликовано 8 января, 2019 Опубликовано 8 января, 2019 1 час назад, Brovin Yaroslav сказал: Надо уметь мыслить в терминах асинхронного программирования. Тогда такие вещи не будут удивлять и не будет проблем. теперь все понятно. спасибо. Barbanel и Yarpda 2 Цитата
kami Опубликовано 9 января, 2019 Опубликовано 9 января, 2019 12 часов назад, slav_z сказал: Если сразу после Release попытаться создать элемент заново (TFrame), то будет ошибка дублирования имени компонента (старый компонент еще жив в списке компонентов родителя). помнится, отвечал уже кому-то на форуме. Для динамически создаваемых компонентов просто не указывайте имя. Не нужно оно им. Тогда эта проблема отпадает сама собой. Ingalime 1 Цитата
Рекомендуемые сообщения
Присоединяйтесь к обсуждению
Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.