Pregunta

I have a class MenuItem which inherits from QGraphicsItem and reimplemented boundingRect(), shape(), paint(), outlineRect():

MenuItem::MenuItem(const QString& qsText, qreal qrYPos)
{
    m_qsText = qsText;
    m_BackgroundColor = Qt::white;
    m_OutlineColor = Qt::darkBlue;
    m_TextColor = Qt::darkGreen;
    qDebug() << pos();
    setPos(mapToParent(200,200));  //<-- when calling this method, mousePressEvent()
                                   // behaves not as expected
    qDebug() << pos(); 
}

QRectF MenuItem::boundingRect() const
{
    const int iMargin = 1;
    return outlineRect().adjusted(-iMargin, -iMargin, +iMargin, +iMargin);

}

QPainterPath MenuItem::shape() const
{
    QRectF rect = outlineRect();

    QPainterPath path;
    path.addRect(rect);

    return path;
}

void MenuItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QPen pen(m_OutlineColor);

    painter->setPen(pen);
    painter->setBrush(m_BackgroundColor);

    QRectF rect = outlineRect();
    painter->drawRect(rect);

    painter->setPen(m_TextColor);
    painter->drawText(rect, Qt::AlignCenter, m_qsText);
}

void MenuItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "Item Mouse Pressed";
}

QString MenuItem::getText() const
{
    return m_qsText;
}

QRectF MenuItem::outlineRect() const
{
    const int iPadding = 8;
    QFontMetricsF metrics = QFontMetricsF(QApplication::font());
    QRectF rect = metrics.boundingRect(m_qsText);
    rect.adjust(-iPadding, -iPadding, +iPadding, +iPadding);
    rect.translate(-rect.center());
    return rect;
}

In another class, called Menu which inherits from QGraphicsScene, I added one instance of MenuItem:

Menu::Menu()
    : QGraphicsScene()
{
    setSceneRect(0, 0, 800, 600);

    m_miNewGame = new MenuItem("New Game", 300);
    this->addItem(m_miNewGame);
    //m_miNewGame->setPos(200,200);
}

The Menu class reimplements mousePressEvent

void Menu::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    //qDebug() << "Menu Mouse Pressed";
    MenuItem *gi = dynamic_cast<MenuItem*>(itemAt(event->pos(), QTransform()));
    if (gi)
        qDebug() << gi->getText();
    QGraphicsScene::mousePressEvent(event); // this forwards the event to the item
    if (itemAt(event->pos(), QTransform()))
    {
        qDebug() << "You Pressed an Item";

    }
}

If I use setPos() method inside the MenuItem constructor the MenuItem gets positioned right but inside the Menu::mousePressEvent() method, MenuItem* returned from itemAt() is always NULL.

Omitting the setPos() method, the MenuItem stays in the top left corner (0,0) of the scene and mousePressEvents are handled as expected: returning the MenuItems Text with the getText() method.

Why is the MenuItem* NULL when calling setPos()? Do I have to reimplement setPos() or what am I doing wrong?

Any help is welcome.

¿Fue útil?

Solución

In MenuItem() constructor you use mapToParent. But your item doesn't have any parent item. So using mapToParent is pointless, it's equivalent to mapToScene in this case. And since your item's initial position is (0, 0) and no transformation has been applied, mapToScene will return its argument's value without changes. So it's equivalent to setPos(200, 200). It seems strange to use the result of mapToParent or mapToScene in setPos. I don't understand what you were trying to do.

QGraphicsSceneMouseEvent::pos returns coordinates of the event in target item's coordinates. Since you're using it in QGraphicsScene::keyPressEvent, the event has not been propagated to any item, and pos() always returns (0, 0). The documentation isn't clear about it, but I've checked it.

If you didn't use setPos, your item's position will be (0, 0) and itemAt(0, 0) will find your item (regardless of the point the user have actually clicked). But if you did use setPos, itemAt(0, 0) returns 0 because there is no item at this point. If you replace event->pos() with event->scenePos(), it will work correct.

However, it's unusual to reimplement QGraphicsScene::keyPressEvent to catch clicking on item. You should reimplement QGraphicsItem::mousePressEvent instead. It will be called only if the item has been clicked, and you don't have to check event's coordinates to determine that.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top