gonzales

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

В теме 59 сообщений

59 минут назад, kami сказал:

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

я про TFrame..  конечно всяким TLable и т.п. имя назначать ни к чему... Фреймы получают имя в designtime и создаются (динамически) с этим именем.

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


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

я про TFrame..  конечно всяким TLable и т.п. имя назначать ни к чему... Фреймы получают имя в designtime и создаются (динамически) с этим именем.

сделай "генератор имен" компонентов!  и при создании назначай!

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


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

сделай "генератор имен" компонентов!  и при создании назначай!

да нет смысла... это сложнее чем назначить пустое имя при создании.

F:=TFrameClass.Create(Self);
F.Name:='';
...

 

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


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

С пустым именем может вообще не пустить. Точно помню...

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


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

С пустым именем может вообще не пустить. Точно помню...

напугать получилось...  дай пять!  да не...  нет проблем с этим...

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


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

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

А разве если создавать по типу 

for i:=0 to 5 do begin

  a := tframe.create(self);

end;

не будет ошибки дублирования? по моему будет. по этой причине именовали := 'frame_'+i.toString;

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


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

будет. но вместо := 'frame_'+i.toString; можно просто "обнулить" имя :='';

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


Ссылка на сообщение
Поделиться на другие сайты
function CreateGUID(): string;
var
    GUID: TGUID;
begin
    if ( System.SysUtils.CreateGUID(GUID) <> 0 ) then
        Result := ''
    else
        Result := GUIDToString(GUID);
end;

...

begin
    ...
    lFrame.Name := CreateGUID();
end;

Это чтобы уж совсем быть уверенным)))

PS. В Delphi 7 - 100% можно создавать компоненты не присваивая ему имя, у нас так все справочники в CRM работали.

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


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

не будет ошибки дублирования? по моему будет. по этой причине именовали := 'frame_'+i.toString;

попробовать религия не позволяет?

Только что написанный код:

var
  i: Integer;
  fr: TFrame13; // отдельный фрейм, у которого в ObjectInspector так и написано: Name = Frame13
begin
  for i := 0 to 5 do
    begin
      fr:=TFrame13.Create(nil);
      fr.Parent:=Self;
      fr.Align:=alRight;
    end;

всё отрабатывает без проблем, никаких вопросов по именованию рантайм-компонентов не возникает.

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


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

замени TFrame13.Create(nil) на TFrame13.Create(Self) только ради бога не спрашивай зачем... проверка на дублирование имени выполняется родителем... а он у тебя nil.

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


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

проверка на дублирование имени выполняется родителем... а он у тебя nil

Родитель-то как раз не nil. Владелец nil.

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

Но вот беда-то... родитель тоже это делает, причем - раньше. И благодаря подпискам на уведомления владелец узнаёт, что компонента, которым он владел, уже нет, т.е. попытки двойного уничтожения НЕ будет.

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


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

Вы выискиваете какие-то обходные маневры, генерацию уникальных имен с привлечением guid, обнуление имени после создания...

а на самом деле ничего из этих костылей не нужно.

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


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

разработчики FMX по каким-то неведомым причинам сделали так, что визуальный контейнер при своем уничтожении так же разрушает и те компоненты, которые отображает (достаточно было просто обнулить Parent). такого никогда не было в VCL. это плохо и неправильно. это работа Owner а не Parent.

Поробуйте создать элемент Create(Owner) и указать какой-нибудь посторонний Parent не принадлежащий Owner. При разрушении получите AV (сначала элемент будет разрушен Parent-ом а затем то же самое попытается сделать и Owner...  нет там никаких нотификаций и подписок).

я постараюсь далее не вступить в спор...  но ничего не обещаю...

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


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

попробовать религия не позволяет?

Только что написанный код:


var
  i: Integer;
  fr: TFrame13; // отдельный фрейм, у которого в ObjectInspector так и написано: Name = Frame13
begin
  for i := 0 to 5 do
    begin
      fr:=TFrame13.Create(nil);
      fr.Parent:=Self;
      fr.Align:=alRight;
    end;

всё отрабатывает без проблем, никаких вопросов по именованию рантайм-компонентов не возникает.

Откуда узнал про религию дядя?

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


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

это работа Owner а не Parent.

Уничтожение и в VCL и в FMX идет именно Parent-ом. Owner получал уведомления (FreeNotification / RemoveFreeNotifications) и убирал высвобожденные ссылки из своего списка на уничтожение. Потом уничтожал свое.
Это дефолтное поведение, сложившееся издавна, оно же без изменений перекочевало в FMX, единственное - находятся методы FreeNotification / RemoveFreeNotifications в разных классах.

1 час назад, slav_z сказал:

При разрушении получите AV (сначала элемент будет разрушен Parent-ом а затем то же самое попытается сделать и Owner...  нет там никаких нотификаций и подписок). 

Нет, это далеко не так. Parent-ом действительно уничтожается всё дочернее. Но Owner после этого ничего сделать уже не может, потому что он уже не знает об уничтоженном компоненте:

destructor TComponent.Destroy;
begin
...
  if FOwner <> nil then FOwner.RemoveComponent(Self);

Ну и напоследок:

procedure TForm12.btn1Click(Sender: TObject);
var
  fm: TForm;
  fr: TFrame13;
  i: Integer;
begin
  fm := TForm12.Create(Self); // создаем дубликат
  try
    for i := 0 to 5 do
      begin
        fr := TFrame13.Create(Self); // Owner - главная форма
        // на фрейм накидал эдитов, лейблов - чтобы не пусто было.
        fr.Name := 'fr' + IntToStr(i);
        fr.Parent := fm; // а Parent - вторая форма того же класса.
        fr.Align := TAlignLayout.Right;
      end;
    fm.ShowModal;
  finally
    fm.Free; // уничтожаем вторую форму
  end;
  // и потом, при закрытии главной формы всё кошерно.
end;

Что я делаю не так?

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


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

Откуда узнал про религию дядя?

Предположил на основании твоего вывода " не будет ошибки дублирования? по моему будет ", который проверяется и опровергается за 2 минуты.
В результате вместо того, чтобы понять откуда ноги растут у ошибки дублирования имен - вы имеете костыли типа "по этой причине именовали := 'frame_'+i.toString; "

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


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

Upd. Нет, похоже в fmx механизм FreeNotification не используется для уничтожения. Но это не мешает всему хозяйству уничтожаться корректно, какие бы родители с владельцами ни указывались

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


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

Предположил на основании твоего вывода " не будет ошибки дублирования? по моему будет ", который проверяется и опровергается за 2 минуты.
В результате вместо того, чтобы понять откуда ноги растут у ошибки дублирования имен - вы имеете костыли типа "по этой причине именовали := 'frame_'+i.toString; "

Предполагай по сути вопроса. А не отвлекаясь на офТоп. Или там в Питере культуре особо не учат? Или тебя ранило походу где-то, чем-то, как-то.
Всем успел накидать я смотрю

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


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

Зря Вы TPurgatory угробили :)
 

Простой пример:

при потере фокуса закрывается всплывающее меню и разрушается всплывающая форма с этим меню,

на OnClick всплывающего меню повешен обработчик,

в обработчике возникает исключение которое приводит к появлению окошка с сообщением об ошибке

появление окна с сообщением об ошибке закрывает и разрушает контекстное меню

получается внутри метода объекта мы совершенно незаметно для себя уничтожили этот объект и на выходе из обработчика OnClick мы уже попадаем ... куда? В код разрушенного объекта. Может там остались старые данные и всё отработает нормально, а может там уже данные другого объекта, или еще какой мусор и приложение аварийно выкидывается из памяти. Как оно в итоге получится зависит от везения и фазы луны.

Подобные ситуации могут возникнуть и в других, менее очевидных случаях. Так что будьте бдительны.

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


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

Да тут баг на баге сидит и погоняет

Вот еще в духе этой темы: грид, лайвбиндинг.В Grid1HeaderClick выполняем обновление запроса (например, для сортировки). После этого форма перестает реагировать на мышь))

Уже впадлу багрепорты писать, штук 15 настрочил наверное а то и больше

Решил пока через таймер...

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


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

Предполагай по сути вопроса. А не отвлекаясь на офТоп. Или там в Питере культуре особо не учат? Или тебя ранило походу где-то, чем-то, как-то.
Всем успел накидать я смотрю

Понаехавших - нет, не учат. Раненых особенно. Тебе эпитеты тоже подобрать? По сути вопроса?

Как ты говоришь "накидывание" возникло от того, что для решения не самого сложного вопроса здесь озвучены (в том числе -тобой)  рекомендации и выводы, от которых потом сложно не удивляться - откуда столько говнокода в экосистеме Делфи?
Да вот отсюда, из таких топиков на форумах, которые неокрепшие (да и окрепшие) умы впитывают и несут потом в массы. Удивительно, что еще не затронули "уникальное имя нужно, потому что по нему потом будем искать этот компонент"...

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


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

Поробуйте создать элемент Create(Owner) и указать какой-нибудь посторонний Parent не принадлежащий Owner. При разрушении получите AV (сначала элемент будет разрушен Parent-ом а затем то же самое попытается сделать и Owner...  нет там никаких нотификаций и подписок).

А есть вообще понимание:

  1. Что такое Овнер для компонентов в делфи?
  2. Какую роль он играет в дизайнере и в рантайме?

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


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

Вы выискиваете какие-то обходные маневры, генерацию уникальных имен с привлечением guid, обнуление имени после создания...

а на самом деле ничего из этих костылей не нужно.

Мой шеф любил говорить:
-Мы сами создаем себе проблемы, а потом героически их преодолеваем.

Штука с GUID была шуткой, я видимо должен был был это указать)))))

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


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

Не ссоритесь девочки пож. :)

В 18.01.2017 в 17:57, gonzales сказал:

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

Помогите советом, как убить кнопку кликнув на нее...

Возвращаясь к сути вопроса. Основная сложность тут в том, что в Delphi нельзя разрушать экземпляр класса внутри метода этого класса за исключением тех случаев, когда метод использует только для разрушения Free, DisposeOf. Почему так, а не иначе, какие есть исключения и почему "уменяфсёработает" объяснять долго, поэтому в первом приближении предлагаю принять это за аксиому.
Обработчики событий OnClick и пр. вызываются из методов классов, так что разрушать контрол внутри события нельзя от слова совсем. Кроме очевидных случаев типа Self.DisposeOf существуют более запутанные варианты, когда к примеру закрывает и разрушается форма, что приводит к разрушению всех дочерних контролов.

Образно говоря, самоубийства строго запрещены, но не запрещено нанимать киллера и в качестве жертвы указывать себя. Т.е. должен быть некий другой (глобальный) объект который будет разрушать объекты, которые хотели бы самоубицо. Реализацию такого объекта можете придумать сами, или использовать TPurgatory (чистилище, в католическом учении — промежуточное место между раем и адом). Но чтобы убедиться в правильности работы можно создать своего наследника TButton в котором перекрыть деструктор и поставить в нем точку останова. При запуске в режиме отладки посмотрите стек вызова деструктора (надо быть внимательным, он может быть длиннющим), ни где в этом стеке не должно быть метода разрушаемого экземпляра. Если в Вы нашли метод разрушаемого объекта (за исключением вышеуказанных), то Ваш способ удаления работает не правильно и с некоторой долей вероятности будет приводить к AV и другим "неприятностям" которые почти невозможно отловить в режиме отладки.

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


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

Для публикации сообщений создайте учётную запись или авторизуйтесь

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

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

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

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