LINUX.ORG.RU

Qt QGraphicsScene.items() - получение данных пользовательского класса

 ,


0

2

Здравствуйте, уважаемые форумчане! Мне необходимо добавлять на сцену пользовательские элементы, которые имеют дополнительные поля, такие как, например, имя. Для чего я создал отдельный класс и наследовал его от QGraphicsItem. Добавление на сцену объектов этого класса работает прекрасно. Но теперь мне нужно получить эти объекты. Код

    QList <QGraphicsItem*>objl;
    objl=scene.items();
не подходит, т.к. класс QGraphicsItem не содержит нужных полей, которые содержит наследуемый от него класс. Пробовал так:
    QList <MovingObject*>objl;
    objl=scene.items();
Но компилятор ругается error: no match for 'operator=' in 'objl = QGraphicsScene::items(Qt::SortOrder) const((Qt::SortOrder)1u)' Как поступить? Создать класс от сцены и переопределить там метод? Или я что-то упустил? Подскажите пожалуйста.


У QGraphicsItem есть методы


void QGraphicsItem::setData ( int key, const QVariant & value ) 

QVariant QGraphicsItem::data ( int key ) const

Вот туда можно записывать значения своих данных.

А ваши варианты конечно работать не будут, так как QList <MovingObject*> и QList <QGraphicsItem*> это разные типы данных.

grondek
()
Ответ на: комментарий от grondek

Но ведь один наследуется от другого! Т.е. метод scene.additem(new MovingObject()) работает полностью корректно, хотя это тоже объекты разных классов.

Спасибо, попробую метод setData

gwyllum
() автор топика
Ответ на: комментарий от gwyllum

Указатель типа предок может указывать на наследованный объект, поэтому addItem работает нормально. А вот обратное не работает.

grondek
()
Ответ на: комментарий от grondek

Да, я уже понял) проблему решил так:

  QList <QGraphicsItem*>objl;
    objl=scene.items();
    for(int i=0; i<objl.size(); i++)
    {
       MovingObject * mo = dynamic_cast <MovingObject *> (objl[i]);
       if (mo)
       {
           qDebug()<<mo->name;
       }

gwyllum
() автор топика
Ответ на: комментарий от gwyllum

Это нормально, когда один нестандартный тип объекта на сцене. А вот расширяться будет очень накладно и код будет запутан.

grondek
()
Ответ на: комментарий от gwyllum

dynamic_cast это медленно, проверка на nullptr тут не упала.

x0r ★★★★★
()
Ответ на: комментарий от no-such-file

Если использовать setData() и data() не будет необходимости писать cast для каждого собственного класса. Пока наследованный класс - один-единственный, код будет небольшим, но как только классов будет куча - код сразу стане несопровождаемым.

grondek
()
Ответ на: комментарий от grondek

Я думаю, будет не более 10 классов для отрисовки на сцене. Тогда такой вопрос - если я использую SetData(), мне нужно отказаться от пользовательского класса? И все объекты пихать в один лист, разделяя их например по ключу type?

gwyllum
() автор топика
Ответ на: комментарий от gwyllum

Смотря что вам надо. Можно отказаться, можно не отказываться. Если вам надо например рисовать как-то по-своему - наследовать все равно придется.

grondek
()
Ответ на: комментарий от gwyllum

И 10 классов - это уже очень много для cast'ов. Много лишнего кода будет.

grondek
()
Ответ на: комментарий от grondek

А что ты будешь делать когда потребуется больше одного поля? Хотя вообще говоря у меня сложилось ощущение что ТС пытается из сцены сделать модель приложения, чего в общем-то делать не стоит.

KblCb ★★★★★
()
Ответ на: комментарий от KblCb

В смысле, больше одного? setData имеет два параметра - ключ, значение.

Ну и на самый крайний извращенный случай: в QVariant можно запихнуть QVariantMap ;)

grondek
()
Ответ на: комментарий от grondek

То есть даункаст тебе не нравится, а поиск по словарю в поиске QVariant'а который тоже нужно кастить чёрт знает к чему это ок? Вот ни разу не проще, не нагляднее и не быстрее. Кроме того QVariant это особа фишка Qt (довольно спорная, к слову), а даункаст — общеупотребительная для плюсов.

KblCb ★★★★★
()
Ответ на: комментарий от grondek

Да, Вы правы - скорее всего потребуется переопределение метода paint(), поэтому наследование классов делать придется. В этом случае наверное вряд ли получится работать с setData(), а придется приводить типы...

gwyllum
() автор топика
Ответ на: комментарий от KblCb

Даункаст мне не нравится потому что надо будет для КАЖДОГО наследованного класса писать отдельный кусок кода. И для КАЖДОГО добавляемого класса выискивать места в коде, а где же там надо его добавить.

Про скорость - на Qt получаются весьма шустрые GUI.

QVariant это особа фишка Qt (довольно спорная, к слову), а даункаст — общеупотребительная для плюсов.

Проект-то чисто Qt'шный, почему бы не использовать все его фичи.

grondek
()
Ответ на: комментарий от gwyllum

А нет возможности вообще спрятать от сцены детали реализации наследников?

grondek
()
Ответ на: комментарий от grondek

Эй! У тебя тут рантайм диспетчеризация. Если делать на QVariantMap'е ты будешь писать по обработчику на каждое отдельное поле которых будет не меньше чем классов в иерархии наследования. Злоупотреблять QVariant'ом не стоит. Он ослабляет и без того слабую типизацию.

KblCb ★★★★★
()
Ответ на: комментарий от grondek

Если использовать setData() и data() не будет необходимости писать cast для каждого собственного класса

Необходимо будет писать canConvert() для кастомных данных, а кроме того данные должны быть классом с метаинформацией. Мне представляется, что это работает немногим быстрее, чем dynamic_cast и уж точно медленее, чем qgraphicsitem_cast, который использует if+static_cast. Хотя, я могу и ошибаться.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Дело тут не в скорости работы программы же. А в том, чтобы не писать кучу if-cast для всех собственных классов.

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

grondek
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.