[Moved] determing subclass of QGraphicsItem



  • hello,

    I have created two subclasses of QGraphicsItem:

    • GraphicsItemShield
    • GraphicsItemBullet

    I have the following loop
    @
    foreach (QGraphicsItem *item, itemlist) {
    // ...
    }
    @

    and I like to know of the item is a GraphicsItemShield or a GraphicsItemBullet...

    If have tried:
    @
    if (item->type() == GraphicsItemShield::Type) {
    // ...
    }
    @

    but it doesn't work :-(

    Any idea?

    Thanks for your support.
    Kind regards,
    David DC



  • Can you show more code please? What you've shown should work if all other is ok.



  • Hi,

    I will paste the advance function of the GraphicsItemBullet below...
    What I try to do (to learn the Graphics of Qt) is to show one moving 'shield' en two moving 'bullets'.
    In case the bullet hits the shield, the bullet should turn.
    In case the bullet hits another bullet, a new bullet will be created
    (I will have to implement a limit of number of bullets to avoid an overflow)

    @
    // implement protected functions

    void GraphicsItemBullet::advance(int phase)
    {
    if (!phase) return;

    // turn in case to close to the border
    QRectF r = boundingRect();
    QPointF mypoint(pos());
    if (mypoint.x() > (500-r.width())) directionX = -1;
    if (mypoint.x() < 1) directionX = 1;
    if (mypoint.y() > (500-r.height())) directionY = -1;
    if (mypoint.y() < 1) directionY = 1;
    
    
    // turn to avoid collision with shield
    // and create a new bullet in case two bullets have collision
    QList<QGraphicsItem *> itemlist = scene()->items();
    foreach (QGraphicsItem *item, itemlist) {
        if (item == this) continue;
        if (item->type() == GraphicsItemShield::Type) {
           QPointF checkpoint(item->pos());
           if ((mypoint.x() > checkpoint.x() - 30)
                && (mypoint.x() < checkpoint.x() + 30)
                && (mypoint.y() > checkpoint.y() - 30)
                && (mypoint.y() < checkpoint.y() + 30))
           {
               directionX = directionX * -1;
               directionY = directionY * -1;
           }
        } // if type = GraphicsItemShield
    
        if (item->type() == GraphicsItemBullet::Type) {
           QPointF checkpoint(item->pos());
           if ((mypoint.x() == checkpoint.x())
                && (mypoint.y() == checkpoint.y())
               )
           {
               GraphicsItemBullet *bullet = new GraphicsItemBullet;
               bullet->setPos(5, 5);
               scene()->addItem(bullet);
           }
        } // if type = GraphicsItemBullet
    } // for each...
    
    // move
    setPos(mapToParent(1 * directionX, 1 * directionY));
    

    }

    @



  • one thing you can do is to do a qobject_cast

    @foreach (QGraphicsItem item, itemlist) {
    // ...
    if(qobject_cast<GraphicsItemShield
    >(item)) {
    // item is GraphicsItemShield type
    } else if(qobject_cast<GraphicsItemBullet*>(item) {
    // item is GraphicsItemBullet type
    }
    }
    @



  • qgraphicsitem_cast fits here better. These items can be derived from QGraphicsItem, not QGraphicsObject. In this case qobject_cast will not work.

    daviddc, can you show headers with these classes and their type() methods?



  • Change qobject_cast on static_cast
    @
    foreach (QGraphicsItem item, itemlist) {
    // ...
    if(static_cast<GraphicsItemShield
    >(item)) {
    // item is GraphicsItemShield type
    } else if(static_cast<GraphicsItemBullet*>(item) {
    // item is GraphicsItemBullet type
    }
    }
    @
    With type() you can make like this, implement common enum
    @
    enum { ShieldType = QGraphicsItem::UserType + 1,
    BulletType };
    @
    In class GraphicsItemShield reimplement func
    @int GraphicsItemShield::type () const { return ShieldType; }@
    In class GraphicsItemBullet reimplement func
    @int GraphicsItemBullet::type () const { return BulletType; }@

    and in your code
    @
    //...
    // turn to avoid collision with shield
    // and create a new bullet in case two bullets have collision
    QList<QGraphicsItem *> itemlist = scene()->items();
    foreach (QGraphicsItem *item, itemlist) {
    if (item == this) continue;
    switch (item->type())
    {
    case ShieldType: //do smth
    break;
    case BulletType: //do another smth
    break;
    }
    //...
    }
    @
    swith gives you more scalable code (because if you, for example, want MagicBulletItem :-) just add another case)


  • Moderators

    @
    enum { ShieldType = QGraphicsItem::UserType + 1,
           BulletType };
    @

    You didn't set BulletType like you did with ShieldType



  • enum do it automatic (he iterate BulletType him self using the previous value, BulletType = ShieldType + 1 and so on)



  • Adding enum with single value in each class will be better.



  • [quote author="Denis Kormalev" date="1307294343"]Adding enum with single value in each class will be better.[/quote]
    of course, but in this case programmer must watch the iteration he did. He can mistake and did like this
    @
    int GraphicsItemShield::type () const
    {
    return QGraphicsItem::UserType + 1;
    }
    @

    @
    int GraphicsItemBullet::type () const
    {
    return QGraphicsItem::UserType + 1;
    }
    @
    Update: and if you want to add another class you just add ClassNameType to enum and return this in new class
    Sorry if I undestood you wrong



  • Hi,

    Thanks for your feedback
    I'm rather late home from work
    I will give it a try tomorrow and let you know :)

    David DC



  • Hi,

    I have Holiday and found some time to try out your advice.

    It works fine with enum type.

    @
    enum { ShieldType = QGraphicsItem::UserType + 1, BulletType };
    @

    thanks for your support.

    Kind regards,
    David DC


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.