• 0
Alex7wrt

Определить, к какому TObjectList принадлежит элемент

Вопросы

Добрый день

Столкнулся с такой задачей:

Существует несколько TObjectList<TRectangle>. При создании каждого из них  AOwnsObjects задано как True. 

RectList[i]:=TObjectList<TRectangle>.Create(True);
............
Nrect:=TRectangle.Create(nil);
Nrect.Parent:=Form1;
RectList[i].Add(Nrect);

Существует ли способ определить, к какому из  TObjectList принадлежит элемент

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


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

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

  • 0

Вряд ли. Списков может быть очень много. Нужно у каждого спрашивать, есть ли в нем нужный объект? Есть ли способ у самого объекта получить ссылку на тот ObjectList, к которому он принадлежит?

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


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

А что если сами списки также поместить в один список и перебрать все во всех

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


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

При создании TRectangle - нужно указывать кто Owner - владелец, вместо nil.

У каждого Rectangle Owner и будет нужный класс TObjectList .

И вообще нужно всегда указывать Owner - ведь TObjectList отвечает за их уничтожение, это основная фича владельцев.

Я недавно баг поймал с фреймом - если при создании TFrame указать Owner nil - то на фрейме не будет работать анимация TFloatAnimation . Так что TFrame.Create(Self формы) - все заработало.

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

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


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

Ваш пример с фреймом немного из другой оперы,  поскольку TObjectList нельзя указать в качестве Owner. Это список, а не комонент, иначе все было бы гораздо проще.

А для управления жизненным циклом обьектов как раз и установлен в True параметр AOwnsObjects.

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

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


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

 

Существует ли способ определить, к какому из  TObjectList принадлежит элемент

Пишите в TagObject элемента  экземпляр TObjectList ! И все!

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


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

Пишите в TagObject элемента  экземпляр TObjectList ! И все!

Да, такой подход допустим, его рассматривал среди прочего. Но хочется узнать, есть ли более "прямолинейный подход" в FMX.

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


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

 

47 минут назад, Alex7wrt сказал:

Ваш пример с фреймом немного из другой оперы,  поскольку TObjectList нельзя указать в качестве Owner. Это список, а не комонент, иначе все было бы гораздо проще.

А для управления жизненным циклом обьектов как раз и установлен в True параметр AOwnsObjects.

Согласен, я только добрался до компа. Owner TComponent, а TObjectList <T> дженерик, а не обычный TObjectList еще больше усложняет. Как вытащить дженерик из указателя я не курсе, с обычным TObjectList это просто, но это уже другой вопрос.

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

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


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

уществует ли способ определить, к какому из  TObjectList принадлежит элемент

нет. Потому что элемент не принадлежит никакому листу.

Это список знает, что при удалении элемента нужно сделать ему Free / заNil-ить ссылку на элемент. Только список.

Сам объект (элемент списка) не подозревает о том, что он кому-то там "принадлежит".

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


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

Можно это обойти (и довольно неплохо, не костыльно)... но это нужно кодить. Готового механизма  нет.

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


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

Можно это обойти (и довольно неплохо, не костыльно)... но это нужно кодить. Готового механизма  нет.

Самый простой и быстрый вариант уже указали - TagObject, здесь самое сложное это вытащить из указателя дженерик класс. Я не знаю возможно ли это вообще, т.к. встречал на стэке инфу о том что никак.

Самый простой вариант использовать классический TObjectList, НЕ дженерик тогда вытащить ссылку из TagObject просто  - TagObject is TObjectList,  TagObject as TObjectList или TObjectList(TagObject).

Если нужно отличать один TObjectList от другого, я бы отнаследовался от него и сделал свой метод Add где устанавливал бы в Rect ссылку на список, там же можно добавить функцию для определения ID списка из Rect, а также ввел какой то идентификатор для списка. 

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

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


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

самое сложное это вытащить из указателя дженерик класс.

В рантайме нет никаких дженериков. Компилятор преобразует все дженерики в реальные списки с необходимой типизацией. Поэтому - действительно никак. Вполне возможно, что даже is TObjectList<TMyClass> не сработает - компилятор вполне вправе посчитать исходный класс TObjectList<TMyClass> не тем, с которым производится is.

8 часов назад, ENERGY сказал:

я бы отнаследовался от него и сделал свой метод Add

Это неправильно. Потому что есть еще Insert, есть Update (в том числе - и InsertRange). Правильно - перекрыть метод Notify или реализовать обработчик события OnNotify (последнее даже создания наследников не требует).

Вообще, если по каким-то причинам необходимо знать "владельца", было бы совсем хорошо сделать наследника от TRectangle, который будет реализовывать интерфейс наподобие такого:
 

IOwneredIntf = interface
    ['{ADF563F3-B4CE-4E96-9559-F0FFC2936D5Z}']
    function GetOwner: TObject;
    procedure SetOwner(const Value: TObject);

    property Owner: TObject read GetOwner write SetOwner;
  end;

Список, который хочет установить владельческие отношения с этим TRectangle, в своем методе Notify приводит его к интерфейсу и устанавливает intf.Owner:=Self

Ну и в обратном порядке - тоже.

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

И если список сделать тоже с поддержкой интерфейса (не знаю, какие методы в нем необходимы), то и сам объект может работать со своим владельцем абсолютно не интересуясь его типом.

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


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

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

Если требуется выполнить данную задачу, то  лучше не побояться написать один дополнительный класс "Менеджер объектов", которому вы будите делегировать данную задачу.

Чтобы поиск был быстрый, нужно использовать словарь. Время поиска будет O(1) против поиска в списке. Один из вариантов реализации может быть таким:

  1. В менеджере есть набор ваших списков (логические группы объектов) - список списков
  2. В менеджере есть словарь соответствия контрол -> индекс списка из (1)
  3. при добавлении контрола добавляете его в список и заносите контрол в словарь
  4. Поиск за О(1)

Вариант, который предложил Kami хороший для вариантов, когда объекты ваши. А вот если вы хотите для штатных контролов это сделать, то чтобы подмешать такой интерфейс, вам потребуется сделать наследников для каждого UI контрола. А если эти контролы еще и на форме лежат, то там придется изрядно попотеть, чтобы добавить в IDE ваши версии штатных контролов с этим интерфейсом.

P.S. Избегайте паттерна один контрол "владеется" несколькими списками. Это к "При создании каждого из них  AOwnsObjects задано как True.". Такой подход рано или поздно при усложнии логики закончится AV и сложным дебаггингом, кто кого удалил и когда и почему. Используйте золотое правило: "Один объект может иметь только одного владельца, один объект может использовать во многих других местах. Только владелец отвечает удаление объекта и в хорошем случае и за его создание. Клиенты объекта только пользуются им и не удаляют его."

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


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

золотые слова )

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

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


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

золотые слова )

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

Грех не написать подробный ответ нашему постоянному пользователю с времен зарождения форума :)

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


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

Чтобы поиск был быстрый, нужно использовать словарь. Время поиска будет O(1) против поиска в списке. Один из вариантов реализации может быть таким:

  1. В менеджере есть набор ваших списков (логические группы объектов) - список списков
  2. В менеджере есть словарь соответствия контрол -> индекс списка из (1)
  3. при добавлении контрола добавляете его в список и заносите контрол в словарь
  4. Поиск за О(1)

Проще использовать бинарный поиск для поиска своего индекса-идентификатора контрола, готовый бинарный поиск реализован в TList и его потомках, также в массивах.

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

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


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

Если я все помню, то поиск в не упорядоченном списке Бинарным поиском - это O(nlog(n)). А поиск в словаре О(1).

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


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

Если я все помню, то поиск в не упорядоченном списке Бинарным поиском - это O(nlog(n)). А поиск в словаре О(1).

Но ведь  еще нужно время чтобы в словаре найти сответствие.

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


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

Так поиск в словаре O(1). Вычисление хеша и получение индекса.

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


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

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

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

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

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

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

Войти

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

Войти

  • Похожий контент

    • От Anasazi
      Всем привет. Чиатю книгу Осипова по Delphi. В книге есть один пример создания простой игры, вроде бы в нем все понятно кроме одного момента.
      По задумке один таймер должен создавать шарики и присваивать им случайные координаты. Второй таймер должен опускать шарики вниз.
      С первым все просто и понятно понятно:
      procedure TForm1.Timer1Timer(Sender: TObject); Var Circle:Tcircle; begin Randomize; Circle:=TCircle.Create(nil); List.Add(circle); Circle.Parent:=Form1; Circle.Position.Y:=0; Circle.Position.X:=Random(Round(Form1.Width-Circle.Width)); end; А вот со вторым какие-то чудеса:
      procedure TForm1.Timer2Timer(Sender: TObject); var i: integer; begin For i:=0 to List.Count-1 do with List.Items do begin Position.Y:=Position.Y+0.5; Я не могу понять почему при перемещении шариков вниз мы пишем просто Position.Y:=Position.Y+0.5;
      Как компилятор понимает что это Position.Y именно шарика, а не формы допустим или квадрата?
      Я привык обращаться к свойству Position так Rectengle1.Position.Y.
      Подскажите пожалуйста как так.
    • От ivadimos
      Извиняюсь за псевдокод.

      Есть класс (A), у него есть несколько дочерних(B1.B2...)
      Создаю лист объектов TList<A>, в него добавляю объекты классов B1, B2...
       
      Есть третий класс С, который имеет перегруженный метод для всех дочерних классов (A).
      procedure p(obj: B1);
      procedure p(obj B2);

      Но объект в классе С всегда воспринимается как объект класса А.
      Как я могу решить проблему?
       
    • От PFC
      Есть класс:
      class TMyObjectInt : public TObject { private: int Value; public: __fastcall TMyObjectInt (int _Value); __fastcall ~TMyObjectInt(); }; Есть ComboBox:
      for (int i = 1; i <= 10; i++) cbxItems->Items->AddObject(IntToStr(i), new TMyObjectInt(i)); Почему при вызове ->Clear() не вызываются деструкторы для TObject'ов? Казалось бы базовый TObject замечательно для этого подходит, даже деструктор у него виртуальным объявлен.
      Я могу написать свою функцию очистки, но это потенциально приводит к ошибкам, особенно если я отдаю указатель на ComboBox за пределы своей формы.
       
      Кстати, так же ведут себя и многие другие контролы, да и в VCL было так же.
  • Последние посетители   0 пользователей онлайн

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