[Interest] Unable to receive mouse move events by a QGraphicsItem.

Dmitrii Volosnykh dmitrii.volosnykh at gmail.com
Fri Jan 17 09:21:09 CET 2014


Hi,

basically, I am trying to implement edition of polyline. I construct it by
a set of QGraphicsEllipseItem's connected with QGraphicsLineItem's. All of
them are descendants of PolylineItem inherited from QGraphicsItem.

In order to make vertices moveable I need to intercept mouse move events in
QGraphicsEllipseItem.

The main.cpp is autogenerated and does not need to be changed for the
purpose of minimal example. Construction of the scene is done in the
constructor of MainWindow class:

[code]
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtWidgets/QMainWindow>
#include <QtCore/QScopedPointer>

namespace Ui {class MainWindow;}
QT_FORWARD_DECLARE_CLASS(QGraphicsScene)


class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget* parent = nullptr);
    virtual ~MainWindow();

private:
    const QScopedPointer<QGraphicsScene> m_scene;
    const QScopedPointer<Ui::MainWindow> ui;
};

#endif // MAINWINDOW_H
[/code]

Here's MainWindow.cpp:

[code]
#include "mainwindow.h"
#include "polylineitem.h"
#include "ui_mainwindow.h"
#include <QtCore/QTimer>
#include <QtWidgets/QGraphicsScene>


MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
    , m_scene(new QGraphicsScene)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    ui->graphicsView->setScene(m_scene.data());

    auto* const polyline = new PolylineItem;
    polyline->addPoint(QPointF(10, 10));
    polyline->addPoint(QPointF(100, 100));

    auto pen = polyline->linePen();
    pen.setWidthF(4);
    pen.setCosmetic(true);
    polyline->setPen(pen);

    m_scene->setSceneRect(QRectF(-50, -50, 200, 200));

    m_scene->addItem(polyline);
}

MainWindow::~MainWindow()
{}
[/code]

The polyline class follows:

[code]
#ifndef POLYLINEITEM_H
#define POLYLINEITEM_H

#include <QtGui/QPen>
#include <QtWidgets/QGraphicsItemGroup>


class PolylineItem : public QGraphicsItem
{
public:
    explicit PolylineItem(QGraphicsItem* parent = nullptr);

    void addPoint(const QPointF& point, bool highlighted = false);

    bool isEmpty() const;

    QRectF boundingRect() const override;
    void paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
QWidget* widget = nullptr) override;

    void pointMoved(QGraphicsEllipseItem* point);

    void setPen(const QPen& pen);

    void setLinePen(const QPen& pen);
    QPen linePen() const;

    void setPointPen(const QPen& pen);
    QPen pointPen() const;

protected:
    bool sceneEvent(QEvent* event) override;
    void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;

private:
    QList<QGraphicsEllipseItem*> m_points;
    QList<QGraphicsLineItem*> m_lines;
    QPen m_linePen;
    QPen m_pointPen;
};

#endif // POLYLINEITEM_H
[/code]


And polylineitem.cpp:

[code]
#include "polylineitem.h"
#include <QtWidgets/QGraphicsSceneEvent>

#include <QtCore/QtDebug>


namespace
{
    const qreal POINT_RADIUS_RATIO = 1.5;
    const QColor POINT_HIGHLIGHT_COLOR = Qt::green;


    class PointItem : public QGraphicsEllipseItem
    {
    public:
        explicit PointItem(PolylineItem* polyline = nullptr);

        void setHighlighted(bool highlighted);
        bool highlighted() const;

    protected:
        bool sceneEvent(QEvent* event) override;
        void hoverEnterEvent(QGraphicsSceneHoverEvent* event) override;
        void hoverLeaveEvent(QGraphicsSceneHoverEvent* event) override;
        void mousePressEvent(QGraphicsSceneMouseEvent* event) override;
        void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;
        void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override;

    private:
        PolylineItem* const m_polyline;
        QColor m_color;
        bool m_moving;
        QPointF m_prevPos;
    };


    PointItem::PointItem(PolylineItem* const polyline)
        : QGraphicsEllipseItem(polyline)
        , m_polyline(polyline)
    {
        setAcceptHoverEvents(true);
    }

    void PointItem::setHighlighted(const bool highlighted)
    {
        auto p = pen();
        if (highlighted) {
            m_color = p.color();
            p.setColor(POINT_HIGHLIGHT_COLOR);
        } else {
            p.setColor(m_color);
            m_color = QColor();
        }
        setPen(p);
    }

    bool PointItem::highlighted() const
    {
        return m_color.isValid();
    }

    bool PointItem::sceneEvent(QEvent* const event)
    {
        qDebug() << "PointItem::sceneEvent" << event->type();

        return QGraphicsEllipseItem::sceneEvent(event);
    }

    void PointItem::hoverEnterEvent(QGraphicsSceneHoverEvent* const event)
    {
        setHighlighted(true);

        QGraphicsEllipseItem::hoverEnterEvent(event);
    }

    void PointItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* const event)
    {
        setHighlighted(false);

        QGraphicsEllipseItem::hoverLeaveEvent(event);
    }

    void PointItem::mousePressEvent(QGraphicsSceneMouseEvent* const event)
    {
        m_moving = true;
        m_prevPos = event->scenePos();

        QGraphicsEllipseItem::mousePressEvent(event);
    }

    void PointItem::mouseMoveEvent(QGraphicsSceneMouseEvent* const event)
    {
        qDebug() << "PointItem::mouseMoveEvent";

        QGraphicsEllipseItem::mouseMoveEvent(event);
    }

    void PointItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* const event)
    {
        QGraphicsEllipseItem::mouseReleaseEvent(event);

        m_moving = false;
    }
}


PolylineItem::PolylineItem(QGraphicsItem* const parent)
    : QGraphicsItem(parent)
{
    setFlag(QGraphicsItem::ItemHasNoContents);
}

void PolylineItem::addPoint(const QPointF& point, const bool highlighted)
{
    const qreal r = m_pointPen.widthF() * POINT_RADIUS_RATIO;

    auto* const newPointItem = new PointItem(this);
    newPointItem->setPos(point);
    newPointItem->setRect(-r, -r, 2 * r, 2 * r);
    newPointItem->setPen(m_pointPen);
    newPointItem->setFlag(QGraphicsItem::ItemIgnoresTransformations);
    newPointItem->setZValue(zValue() + 1);
    newPointItem->setHighlighted(highlighted);
    m_points.append(newPointItem);

    if (m_points.size() > 1) {
        auto* const prevPointItem = m_points[m_points.size() - 2];

        auto* const lineItem = new QGraphicsLineItem(this);
        lineItem->setLine(QLineF(prevPointItem->pos(),
newPointItem->pos()));
        lineItem->setPen(m_linePen);
        m_lines.append(lineItem);
    }
}

bool PolylineItem::isEmpty() const
{
    return m_points.isEmpty();
}

QRectF PolylineItem::boundingRect() const
{
    QRectF result;

//    for (int i = 0; i < m_points.size(); ++i) {
//        result |=
m_points[i]->boundingRect().translated(m_points[i]->pos());
//    }

    return result;
}

void PolylineItem::paint(QPainter* const painter, const
QStyleOptionGraphicsItem* const option, QWidget* const widget)
{
    Q_UNUSED(painter);
    Q_UNUSED(option);
    Q_UNUSED(widget);
}

void PolylineItem::pointMoved(QGraphicsEllipseItem* const point)
{
    const int pointIndex = m_points.indexOf(point);
    Q_ASSERT(pointIndex >= 0);

    // TODO
}

void PolylineItem::setPen(const QPen& pen)
{
    setLinePen(pen);
    setPointPen(pen);
}

void PolylineItem::setLinePen(const QPen& pen)
{
    m_linePen = pen;

    foreach (QGraphicsLineItem* const line, m_lines) {
        line->setPen(pen);
    }
}

QPen PolylineItem::linePen() const
{
    return m_linePen;
}

void PolylineItem::setPointPen(const QPen& pen)
{
    m_pointPen = pen;

    foreach (QGraphicsEllipseItem* const point, m_points) {
        point->setPen(pen);
    }
}

QPen PolylineItem::pointPen() const
{
    return m_pointPen;
}

bool PolylineItem::sceneEvent(QEvent* const event)
{
    qDebug() << "PolylineItem::sceneEvent" << event->type();

    return QGraphicsItem::sceneEvent(event);
}

void PolylineItem::mouseMoveEvent(QGraphicsSceneMouseEvent* const event)
{
    qDebug() << "PolylineItem::mouseMoveEvent";

    QGraphicsItem::mouseMoveEvent(event);
}
[/code]


When I run application and move mouse over one of the circles at the ends
of line segment, I get the following debug output log:

 PolylineItem::sceneEvent 24

PointItem::sceneEvent 24

PointItem::sceneEvent 24

PointItem::sceneEvent 160

PointItem::sceneEvent 161

PointItem::sceneEvent 161

PointItem::sceneEvent 161

PointItem::sceneEvent 161

PointItem::sceneEvent 161

PointItem::sceneEvent 161

PointItem::sceneEvent 161

PointItem::sceneEvent 162

PolylineItem::sceneEvent 25

PointItem::sceneEvent 25

PointItem::sceneEvent 25


So, disregarding any WindowActivate = 24 and WindowDeactivate = 25 events,
I get only a set of GraphicsSceneHoverEnter = 160, GraphicsSceneHoverMove =
161, and GraphicsSceneHoverLeave = 162 events.

Hover move event is not sufficient for me, because the point moving
behaviour gets broken with rapid mouse motion. That's why need
mouseMoveEvent() to be called.

Any suggestions on where this event might be blocked? I have re-read the
"Event Handling and Propagation" chapter of QGraphicsScene manual, but
still striking with the issue.

Regards,
Dmitrii.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20140117/beb8fd23/attachment.html>


More information about the Interest mailing list