设置ItemIsMovable标志时,子项目在QGraphicsView中不可移动

时间:2014-02-13 04:06:31

标签: c++ qt qt5 qgraphicsitem qtgui

要调整QGraphicsView中项目的大小,我将表示顶点的子项放在要移动的项上(使用构造函数中建立的父子关系)。这些是下图中的四个蓝色圆圈:

an example

但是子顶点没有接收鼠标事件。只有父项(红色方块)才能获得鼠标事件。

以下是Item的定义:

Item::Item(QGraphicsItem * parent) :
    QGraphicsItem(parent)
{
    setFlag(ItemIsMovable);
    setFlag(ItemIsSelectable);
    setFlag(ItemSendsGeometryChanges);
    setCacheMode(DeviceCoordinateCache);   
}

void Item::paint(
    QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->fillRect(option->rect,Qt::red);
}

QVariant Item::itemChange(GraphicsItemChange change, const QVariant & value)
{
    switch(change)
    {
        case QGraphicsItem::ItemSelectedHasChanged:
            qWarning() << "item: " + value.toString();
            updateVertices(value.toBool());
            break;
        default:
            break;
    }
    return QGraphicsItem::itemChange(change, value);
}

void Item::updateVertices(bool visible) {
    if(visible) {
        if(vertices.length() == 0) {
            for(int i = 0; i < 4; i++)
                vertices.append(new Vertice(this));
        } else
            for(int i = 0; i < 4; i++)
                vertices[i]->setVisible(true);

        QRectF rect = boundingRect();
        vertices[0]->setPos(rect.topLeft());
        vertices[1]->setPos(rect.topRight());
        vertices[2]->setPos(rect.bottomLeft());
        vertices[3]->setPos(rect.bottomRight());
    } else {
        for(int i = 0; i < 4; i++) {
            p_vertices[i]->setVisible(false);
        }
    }
}

虽然这里是Vertice的定义:

Vertice::Vertice(QGraphicsItem * parent) :
    QGraphicsItem(parent)
{
    setFlag(ItemIsMovable);
    setFlag(ItemIsSelectable);
    setFlag(ItemSendsGeometryChanges);
}

void Vertice::paint(
    QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->setBrush(Qt::blue);
    painter->setPen(Qt::darkGray);
    painter->drawEllipse(-5,-5,10,10);
}

QVariant Vertice::itemChange(GraphicsItemChange change, const QVariant & value)
{
    switch(change) {
        case QGraphicsItem::ItemSelectedHasChanged:
            qWarning() << "vertex: " + value.toString(); // never happened
            break;
        default:
            break;
    }
}

1 个答案:

答案 0 :(得分:4)

你说你的孩子没有得到鼠标事件,但他们是。您可以通过向Vertice添加void mousePressEvent(QGraphicsSceneMouseEvent * event)并注意到它已被调用来验证这一点。

你的问题是Qt忽略了孩子QGraphicsItem上的ItemIsMovable标志。你问的时候甚至没有设置旗帜。

您可以通过更改Vertice构造函数来验证这一点:

Vertice::Vertice(QGraphicsItem * parent) :
    QGraphicsItem(parent)
{
    setFlag(ItemIsMovable);
    Q_ASSERT(flags() & ItemIsMovable); // fails
    setFlag(ItemIsSelectable);
    setFlag(ItemSendsGeometryChanges);
}

现在为什么会这样?正如编程Jedi所说:&#34;使用来源,Luke!&#34;

https://qt.gitorious.org/qt/qtbase/source/7df3321f934e5bd618e2ad00bf801f2b7edd31df:src/widgets/graphicsview/qgraphicsitem.cpp#L1789

请注意,设置标志时它所执行的操作之一就是itemChange通过ItemFlagsChange通知进行检查。不仅如此,它还允许标志被该调用的结果覆盖。但是看看你在Vertice上的itemChange()的实现:

QVariant Vertice::itemChange(GraphicsItemChange change, const QVariant & value)
{
    switch(change) {
        case QGraphicsItem::ItemSelectedHasChanged:
            qWarning() << "vertex: " + value.toString(); // never happened
            break;
        default:
            break;
    }
}

糟糕,没有退货结果!将此行添加到最后,就像在项目中一样:

return QGraphicsItem::itemChange(change, value);

......你有它。其他说明:

  • Singular of&#34; Vertices&#34; is actually "Vertex"

  • 如果您有这样的案例,请考虑从您正在编写的任何特定程序中删除它。如果您可以使用一个子项和一个父项来演示问题,那么为什么要创建四个循环呢?如果选择不是问题的一部分 - 并且不需要涉及隐藏和显示顶点的代码 - 那么为什么要涉及呢?使用您提供的代码来提供所需的虚拟方法(如boundingRect())而不是让其他人编写它来进行测试会好得多。请参阅Short, Self-Contained, Compilable Example

  • Qt源码具有相当的可读性和组织性,所以要养成查看它的习惯......!