鼠标事件重新实现后对QGraphicsView的奇怪影响

时间:2016-12-13 19:39:50

标签: c++ qt qgraphicsview

我使用这个源代码开始了一个小项目:

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QGraphicsLineItem>

class CustomRectItem : public QGraphicsRectItem
{
public:
    CustomRectItem (const QRectF& rect) : QGraphicsRectItem(rect) {
    setFlag(QGraphicsItem::ItemIsMovable);
    setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
    setAcceptHoverEvents(true);
}

void addLine(QGraphicsLineItem *line1, QGraphicsLineItem *line2) {
    if (this->data(0).toString() == "_p1") {
        this->leftLine = line1;
        this->topLine = line2;
    }
    if (this->data(0).toString() == "_p2") {
        this->topLine = line1;
        this->rightLine = line2;
    }
    if (this->data(0).toString() == "_p3") {
        this->rightLine = line1;
        this->bottomLine = line2;
    }
    if (this->data(0).toString() == "_p4") {
        this->bottomLine = line1;
        this->leftLine = line2;
    }
}

QPointF center(void) {
    return QPointF((rect().x() + rect().width() / 2),
                   (rect().y() + rect().height() / 2));
}

QVariant itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == ItemPositionChange && scene()) {
        // value is the new position.
        QPointF newPos = value.toPointF();

        moveLineToCenter(newPos, this->data(0).toString());
    }
    return QGraphicsItem::itemChange(change, value);
}

void moveLineToCenter(QPointF newPos, QString pointString) {
    // Converts the polygon upper left position
    // to the upper left "handle"-rect center position
    qreal xOffset = rect().x() + rect().width()/2;
    qreal yOffset = rect().y() + rect().height()/2;

    QPointF newCenterPos = QPointF(newPos.x() + xOffset, newPos.y() + yOffset);

    QPointF p1;
    QPointF p2;

 // upper-left point
    if (pointString == "_p1") {
        p1 = leftLine->line().p1();
        p2 = newCenterPos;
        leftLine->setLine(QLineF(p1, p2));
        p1 = newCenterPos;
        p2 = topLine->line().p2();
        topLine->setLine(QLineF(p1, p2));
  // upper-right point
    } else if (pointString == "_p2") {
        p1 = topLine->line().p1();
        p2 = newCenterPos;
        topLine->setLine(QLineF(p1, p2));
        p1 = newCenterPos;
        p2 = rightLine->line().p2();
        rightLine->setLine(QLineF(p1, p2));
  // lower-right point
    } else if (pointString == "_p3") {
        p1 = rightLine->line().p1();
        p2 = newCenterPos;
        rightLine->setLine(QLineF(p1, p2));
        p1 = newCenterPos;
        p2 = bottomLine->line().p2();
        bottomLine->setLine(QLineF(p1, p2));
  // lower-left point
    } else if (pointString == "_p4") {
        p1 = bottomLine->line().p1();
        p2 = newCenterPos;
        bottomLine->setLine(QLineF(p1, p2));
        p1 = newCenterPos;
        p2 = leftLine->line().p2();
        leftLine->setLine(QLineF(p1, p2));
    } else {
        return;
    }
}

/////////////////////////////////////////////////////
/* -- comment-in this block to observe problem --  //
/////////////////////////////////////////////////////

protected:
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) {
    Q_UNUSED(event);
    this->setCursor(Qt::SizeAllCursor);
}
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) {
    Q_UNUSED(event);
    this->unsetCursor();
}
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) {
    Q_UNUSED(event);
    this->setCursor(Qt::BlankCursor);
}
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
    Q_UNUSED(event);
    this->unsetCursor();
    this->data(0).toString();
    if (this->isUnderMouse()) {
           this->setCursor(Qt::SizeAllCursor);
    }
}

/////////////////////////////////////////////////////
//       -- end of problem-causing block --        //
///////////////////////////////////////////////////// */

private:
QGraphicsLineItem *topLine;
QGraphicsLineItem *rightLine;
QGraphicsLineItem *bottomLine;
QGraphicsLineItem *leftLine;
};

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    QGraphicsScene scene;

    CustomRectItem *custRect1 = new CustomRectItem(QRectF(30, 30, 10, 10));
    scene.addItem(custRect1);
    custRect1->setData(0, "_p1");

    CustomRectItem *custRect2 = new CustomRectItem(QRectF(70, 30, 10, 10));
    scene.addItem(custRect2);
    custRect2->setData(0, "_p2");

    CustomRectItem *custRect3 = new CustomRectItem(QRectF(70, 70, 10, 10));
    scene.addItem(custRect3);
    custRect3->setData(0, "_p3");

    CustomRectItem *custRect4 = new CustomRectItem(QRectF(30, 70, 10, 10));
    scene.addItem(custRect4);
    custRect4->setData(0, "_p4");

    QGraphicsLineItem *topLine = scene.addLine(QLineF(custRect1->center(), custRect2->center()));
    QGraphicsLineItem *rightLine = scene.addLine(QLineF(custRect2->center(), custRect3->center()));
    QGraphicsLineItem *bottomLine = scene.addLine(QLineF(custRect3->center(), custRect4->center()));
    QGraphicsLineItem *leftLine = scene.addLine(QLineF(custRect4->center(), custRect1->center()));

    custRect1->addLine(leftLine, topLine);
    custRect2->addLine(topLine, rightLine);

    custRect3->addLine(rightLine, bottomLine);
    custRect4->addLine(bottomLine, leftLine);

    QGraphicsView view(&scene);
    view.show();

    return a.exec();
}

编译上面的代码应该最终得到一个小窗口,其中只包含QGraphivsView,一个Polygon和四个附加到Polygons顶点的Handles。 现在用鼠标移动一个Handle。再次移动它。 一切都应该像任何图形编辑器一样表现。 接下来,在代码块中注释重新实现一些鼠标事件,基本上只是在悬停并拖动手柄时更改光标。 重新编译并重新开始移动句柄。再次移动相同的手柄......看看发生了什么! WTF?它跳回到它的初始位置。 有谁知道如何解释这种行为以及如何解决它?

谢谢!

2 个答案:

答案 0 :(得分:2)

确保在实现后调用基类事件,以确保保持正常的功能。

virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) {
    this->setCursor(Qt::SizeAllCursor);
    //
    QGraphicsRectItem::hoverEnterEvent( event );
}
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) {
    this->unsetCursor();
    //
    QGraphicsRectItem::hoverLeaveEvent( event );

}
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) {
    this->setCursor(Qt::BlankCursor);
    //
    QGraphicsRectItem::mousePressEvent( event );
}
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
    this->unsetCursor();
    this->data(0).toString();
    if (this->isUnderMouse()) {
           this->setCursor(Qt::SizeAllCursor);
    }
    //
    QGraphicsRectItem::mouseReleaseEvent( event );
}

答案 1 :(得分:0)

您需要为mousePressEvent和mouseReleaseEvent方法调用基类实现:

QGraphicsRectItem::mousePressEvent (event);

QGraphicsRectItem::mouseReleaseEvent (event);

根据文档,基本实现处理鼠标抓取,移动和选择,因此在这种情况下需要调用它们。手柄移动时我感到有些惊讶,但很明显,但物品的位置在内部处理得不好。