Порядок следования дочерних объектов QObject (стратегический вопрос)

StackOverflow https://stackoverflow.com/questions/1991684

  •  22-09-2019
  •  | 
  •  

Вопрос

Для одного из моих проектов у меня есть дерево производных объектов QObject, которые используют родительскую / дочернюю функциональность QObject для построения дерева.

Это очень полезно, поскольку я использую сигналы и слоты, использую защищенные указатели Qt и ожидаю, что родительские объекты удалят дочерние объекты при их удалении.

Пока все идет хорошо.К сожалению, сейчас мой проект требует, чтобы я управлял / изменял порядок дочерних элементов.QObject не предоставляет никаких средств для изменения порядка своих дочерних элементов (исключение:Функция raise() QWidget - но в данном случае это бесполезно). Итак, теперь я ищу стратегию контроля за порядком следования детей. У меня было несколько идей, но я не уверен в их плюсах и минусах:



Вариант А: Пользовательская переменная-член индекса сортировки

Используйте int m_orderIndex переменная-член в качестве ключа сортировки и предоставляет sortedChildren() метод, который возвращает список QObjects, отсортированных по этому ключу.

  • Легко внедряется в существующую структуру объекта.
  • Проблематично, когда QObject::children() метод переопределен - приведет к проблемам во время циклов при изменении порядка элементов, также является более дорогостоящим, чем реализация по умолчанию.
  • Следует вернуться к порядку объектов QObject, если все ключи сортировки равны или 0 / по умолчанию.

Вариант В: Избыточный список дочерних элементов

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

  • Требуется дорогостоящее отслеживание добавленных / удаленных объектов.Это в основном приводит ко второму дочернему / родительскому отслеживанию и множеству сигналов / слотов.QObject уже выполняет все это внутренне, так что, возможно, не стоит делать это снова.Также кажется, что для такой простой вещи, как изменение порядка следования дочерних элементов, добавляется много наворотов.
  • Хорошая гибкость, поскольку QList дочерних элементов может быть изменен по мере необходимости.
  • Позволяет дочернему элементу находиться в QList более одного раза или не находиться вообще (даже если он все еще может быть дочерним элементом QObject)

Вариант С:...?

Любые идеи или отзывы, особенно от людей, которые уже решили эту проблему в своих собственных проектах, высоко ценятся.С наступающим новым годом!

Это было полезно?

Решение

В последние дни я потратил много времени на рассмотрение всех этих вариантов и тщательно обсуждал их с некоторыми другими программистами.Мы решили пойти на Вариант А.

Каждый из объектов, которыми мы управляем, является дочерним по отношению к родительскому объекту.Поскольку Qt не предоставляет никаких средств изменения порядка этих объектов, мы решили добавить int m_orderIndex свойство для каждого объекта, которое по умолчанию равно 0.

Каждый объект имеет функцию доступа sortedChildren() который возвращает QObjectList детей.Что мы делаем в этой функции:

  1. Используйте обычный QObject::chilren() функция для получения списка всех доступных дочерних объектов.
  2. dynamic_cast все объекты в наш «базовый класс», который обеспечивает m_orderIndex свойство.
  3. Если объект можно приводить, добавьте его во временный список объектов.
  4. использовать qSort с обычаем LessThan функция, чтобы узнать, нужно ли qSort изменить порядок двух объектов.
  5. Вернуть список временных объектов.

Мы сделали это по следующим причинам:

  • Существующий код (особенно собственный код Qt) можно продолжать использовать. children() не беспокоясь о побочных эффектах.
  • Мы можем использовать обычный children() функционировать там, где порядок не имеет значения, без потери производительности.
  • В тех местах, где нам нужен упорядоченный список детей, просто заменяем children() к sortedChildren() и получить желаемый эффект.

Одно из преимуществ этого подхода заключается в том, что порядок дочерних элементов не меняется, если все индексы сортировки установлены в ноль.

Извините, что отвечаю на мой собственный вопрос, надеюсь, что это просветит людей с той же проблемой.;)

Другие советы

А как насчет чего-то вроде...

  1. QList listChildren = (QList)дети();
  2. сортировать списокДети
  3. foreach listChildren setParent( TempParent )
  4. foreach listChildren setParent( OriginalParent )

Неприятный хак: QObject::дети() возвращает ссылку на константу.Вы можете отказаться от константности и, таким образом, напрямую манипулировать внутренним списком.

Однако это довольно зло и может привести к признанию недействительными итераторов, которые QObject хранит внутри себя.

У меня нет отдельного варианта C, но, сравнивая варианты A и B, вы говорите ~4 байта (32-битный указатель, 32-битное целое число) в любом случае, поэтому я бы выбрал вариант B, так как вы можете сохранить этот список отсортирован.

Чтобы избежать дополнительных сложностей с отслеживанием детей, вы можете обмануть и сохранить список отсортированным и аккуратным, но объединить его с методом sortedChildren, который отфильтровывает все недетские элементы.С точки зрения сложности, это должно привести к O(nlogm) (n = дочерние элементы, m = записи списка, предполагая, что m >= n, т.е.дети всегда добавляются), если только у вас нет больших изменений в отношении детей.Назовем этот вариант С.

Быстрая сортировка в предложенном вами варианте A дает вам O(n2) (wc), но также требует, чтобы вы получали указатели, отслеживали их, получали целое число и т. д.Комбинированному методу нужен только список указателей (не более O(n)).

У меня была такая же проблема, и я решил ее с помощью варианта B.Отслеживание не так уж сложно, просто создайте метод "void addChild(тип *ptr);" и еще один для удаления дочернего элемента.

Вы не страдаете от злонамеренной избыточности, если вы храните дочерние элементы исключительно в частном / общедоступном списке дочерних элементов (QList) каждого элемента и удаляете базу QObject.На самом деле довольно легко реализовать автоматическое освобождение от дочерних элементов в free (хотя для этого требуется дополнительный родительский указатель).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top