c++ - 当设置 ItemIsMovable 标志时,子项在 QGraphicsView 中不可移动

标签 c++ qt qt5 qgraphicsitem qtgui

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

an example

但是子顶点没有接收到鼠标事件。只有父项(红色方 block )正在获取鼠标事件。

下面是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;
    }
}

最佳答案

您说您的子项没有获得鼠标事件,但它们确实有。您可以通过向 Vertice 添加 void mousePressEvent(QGraphicsSceneMouseEvent * event) 并注意它正在被调用来验证这一点。

您的问题是 Qt 忽略了子 QGraphicsItem 上的 ItemIsMovable 标志。当您询问时,它甚至没有设置标志。

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

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

为什么会这样呢?正如编程绝地所说:“使用源代码,卢克!”

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);

...这就给你了。其他说明:

  • “顶点”的单数 is actually "Vertex"

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

  • Qt 源代码可读性强且组织良好,因此请养成查看它的习惯...!

关于c++ - 当设置 ItemIsMovable 标志时,子项在 QGraphicsView 中不可移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21745025/

相关文章:

c++ - 调用 QGLWidget::setFormat = 无绘图

Qt QNetworkAccessManager 和多个QNetworkReply

android - 在 Qt Android 应用程序中使用 Holo 主题

c++ - 文件属性对话框中的自定义选项卡

c++ - 带有wxsqlite3运行时错误的Sqlite数据库加密

c++ - '../controlpanel.ui' 需要 Qt : No rule to make target 'ui_controlpanel.h' ,。停止

qt - 动态添加到 qml tabbar 和 stacklayout

c++ - Qt5 用户界面编译器 : -i option not available

c++ - 为可变参数宏的元素添加前缀

c++ - 访问声明已弃用,取而代之的是使用声明;建议 : add the ‘using’ keyword