简体   繁体   English

鼠标没有注意到我的QGraphicsItem项目

[英]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. 最好是我可以使用QGraphicsView / QGraphicsScene / QGraphicsItem方法来移动项目或获取上下文菜单...我还没有弄清楚怎么做。

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 ?) (或者,如何使QGraphicsScene / QGraphicsView完成所有工作并移动项目,而无需编写任何代码?这是ItemIsMovable的目的。。对吗?)

Update : added the code for paintEvent ... Unfortunately I was unable to call the 更新 :添加了paintEvent的代码...不幸的是我无法调用

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

version of the paint - it would probably be used by something like scene()->addItem(item); 绘画版本-可能会被诸如scene()->addItem(item);类的东西使用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. -但是该特定调用使程序崩溃...从未调用上述paint方法,但我知道它是QGraphicsItem的官方paint方法...这样简单的代码却是如此混乱。

Firstly, try with a simple Item and a basic GraphicsScene and View. 首先,尝试使用简单的Item以及基本的GraphicsScene和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. 这是一个基本项目,当您使用基本QGraphicsItem和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. 如果代码中的问题似乎表明您的项目无法移动,则可能是您的MousePressEvent。

As we have established in the comments, the problem is the value returned from the boundingRect( ) function. 正如我们在注释中确定的那样,问题是从boundingRect()函数返回的值。

A QGraphicsItem's bounding rect defines the local coordinates of the item. QGraphicsItem的边界矩形定义了项目的局部坐标。 If the item is regular, matching a rectangle, you would only need to implement the boundingRect(). 如果该项是常规的,匹配矩形,则只需实现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(). 如果您有一个非规则(矩形)对象,并且希望进行更细粒度的碰撞检测,那么除了boundingRect()之外,还可以实现shape()函数。 Both are in local coordinates for the item. 两者都在该项目的本地坐标中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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