简体   繁体   中英

My QGraphicsItem items are not noticed by the mouse

I am trying to move my item... The only way this works is if I iterate through all my items and check the mouse position:

class Item : public QGraphicsItem
{
    Item() { setFlag(ItemIsMovable); setFlag(ItemIsSelectable); scale = 10; }
    QRectF boundingRect() const;
    void paint(QPainter *painter);   // had to implement this because I don't know how to get the QStyleOptionGraphicsItem to call the paint below
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
               QWidget *widget) {paint(painter);}   // never called
    void update() {}
    int scale, x, y;
};

// scale is Item property set by caller, x and y also set by caller based on viewport position of item center
QRectF Item::boundingRect() const
{
    return QRectF(x - 30 - scale, y - 30 - scale,
                  30 + 3 * scale, 20 + 3 * scale);
}

void Item::paint(QPainter *painter)
{
    update();
    painter->drawRect(boundingRect());
}

class CollectionView : public QGraphicsView
{
    Q_OBJECT    
public:
    CollectionView(QWidget *parent = 0);    
    QList<Item*> *m_items;
protected:
    virtual void paintEvent(QPaintEvent * event);
    virtual void mousePressEvent(QMouseEvent * event);
    virtual void mouseReleaseEvent(QMouseEvent *event);
};

CollectionView::CollectionView(QWidget *parent)
    : QGraphicsView(parent)
{
    QGraphicsScene *s = new QGraphicsScene(this);
    setScene(s);
    setViewportUpdateMode(BoundingRectViewportUpdate);
    m_items = new QList<Item*>();
}

void CollectionView::paintEvent(QPaintEvent * /* event */)
{
    QPainter painter(this->viewport());

    for(int i = 0; i< m_items->size(); i++)
    {
        Item* item = m_items->at(i);
        //scene()->addItem(item);   // this crashes
        item->paint(&painter);
    }
}

void CollectionView::mousePressEvent(QMouseEvent* event)
{
    // if I add this and comment the rest, items don't move
    //QGraphicsView::mousePressEvent(event);

    foreach (QGraphicsItem *item, this->items(event->pos()))
    { /* never gets inside */ }
    foreach (QGraphicsItem *item, this->items(event->globalPos()))
    { /* never gets inside */ }

    // the following works though:
    for (int i = 0; i < m_items->size(); i++)
    {
        Item* currentItem = m_items->at(i);
        if(!currentItem->boundingRect().contains(event->pos()))
            continue;
        if (event->button() == Qt::LeftButton)
            { /* I can get the item index and its relative position to mouse
                 then pass this info to the mouseReleaseEvent, and it works */ }
        break;
    }
}

It would be best if I could use the QGraphicsView / QGraphicsScene / QGraphicsItem methods to move item or get the context menu... I have not figured out how.

But if I have to implement mouse actions, it would be best if I could iterate through he items found at mouse position, instead of all the items in my list (which is likely to be larger).

Why is my try not working ? (alternately, how can I make QGraphicsScene / QGraphicsView do all the work and move the item without my having to write any code ? that is the purpose of the ItemIsMovable.. right ?)

Update : added the code for paintEvent ... Unfortunately I was unable to call the

void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

version of the paint - it would probably be used by something like scene()->addItem(item); - but that specific call makes program crash... the above paint method is never called, but I am aware that it is the official paint method of he QGraphicsItem ... Such a simple code yet such a mess.

Firstly, try with a simple Item and a basic GraphicsScene and View. Like that:

    class GraphicsItem : public QGraphicsItem
{
public:
    GraphicsItem(QWidget* parent) {
        setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
    }
    QRectF boundingRect() const
       {
           qreal penWidth = 1;
           return QRectF(-10 - penWidth / 2, -10 - penWidth / 2,
                         20 + penWidth, 20 + penWidth);
       }

       void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                  QWidget *widget)
       {
           painter->drawRoundedRect(-10, -10, 20, 20, 5, 5);
       }
};

This is a basic Item with will move when you use a basic QGraphicsItem and QGraphicsScene.

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        QGraphicsScene scene;
        scene.addItem(new GraphicsItem(NULL));
        QGraphicsView view(&scene);
        view.show();

        return a.exec();
   }

If the problem in your code seem that you item doesn't move it probably your MousePressEvent.

As we have established in the comments, the problem is the value returned from the boundingRect( ) function.

A QGraphicsItem's bounding rect defines the local coordinates of the item. If the item is regular, matching a rectangle, you would only need to implement the boundingRect(). This is used for collision detection for, amongst other things, detecting the mouse being over the item.

If you have a non-regular (rectangular) object and want a more granular collision detection, then implement the shape() function, in addition to boundingRect(). Both are in local coordinates for the item.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM