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 ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.