Interactive QGraphicsRectItem: Left-Edge Resizing and Shape Dragging in Qt

To create interactive rectangles in a Qt QGraphicsScene, you can subclass QGraphicsRectItem and override its mouse event hendlers. This approach allows you to implement specific behaviors, such as resizing the shape by dragging a specific edge or moving the antire shape across the scene.

Left-Edge Resizing Implementation

The first implementation demonstrates how to restrict resize interactions to the left boundary of the rectangle. By calculating the distance between the mouse cursor and the left edge during a press event, we can activate a resize state only when the cursor falls within a defined pixel threshold. During the move event, the rectangle's geometry is dynamically updated to reflect the new left coordinate and width, while preserving the original height and top position.


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

class LeftEdgeResizableRect : public QGraphicsRectItem {
public:
    LeftEdgeResizableRect(const QRectF &bounds, QGraphicsItem *parent = nullptr)
        : QGraphicsRectItem(bounds, parent),
          isResizing(false),
          initialWidth(0.0),
          resizeOrigin(QPointF()) {}

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event) override {
        if (event->button() == Qt::LeftButton) {
            QRectF currentBounds = rect();
            QPointF cursorPos = event->pos();
            const qreal threshold = 8.0; // Detection zone in pixels

            // Check if the cursor is near the left edge
            if (qAbs(cursorPos.x() - currentBounds.left()) <= threshold) {
                isResizing = true;
                initialWidth = currentBounds.width();
                resizeOrigin = cursorPos;
            }
        }
        QGraphicsRectItem::mousePressEvent(event);
    }

    void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override {
        if (isResizing) {
            QPointF currentCursorPos = event->pos();
            qreal deltaX = currentCursorPos.x() - resizeOrigin.x();
            qreal updatedWidth = initialWidth - deltaX;
            qreal updatedLeft = currentCursorPos.x();

            // Prevent the width from collapsing to zero or negative values
            if (updatedWidth > 0) {
                setRect(updatedLeft, rect().y(), updatedWidth, rect().height());
            }
        } else {
            QGraphicsRectItem::mouseMoveEvent(event);
        }
    }

    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override {
        isResizing = false;
        QGraphicsRectItem::mouseReleaseEvent(event);
    }

private:
    bool isResizing;
    qreal initialWidth;
    QPointF resizeOrigin;
};

class DisplayView : public QGraphicsView {
public:
    DisplayView(QWidget *parent = nullptr) : QGraphicsView(parent) {
        QGraphicsScene *canvas = new QGraphicsScene(this);
        setScene(canvas);

        LeftEdgeResizableRect *shape = new LeftEdgeResizableRect(QRectF(30, 30, 200, 100));
        canvas->addItem(shape);
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    DisplayView window;
    window.resize(400, 300);
    window.show();
    return app.exec();
}

Whole Shape Dragging Implementation

The second scenario involves moving the entire rectangular shape rather than altering its dimensions. In this case, any left-button click inside the shape initiates a move operation. The displacement between the current and previous cursor positions is calculated during the move event, and the moveBy method is used to shift the item's coordinates accordingly.


#include <QApplication>
#include <QMainWindow>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QGraphicsSceneMouseEvent>

class FullyDraggableRect : public QGraphicsRectItem {
public:
    FullyDraggableRect(const QRectF &bounds, QGraphicsItem *parent = nullptr)
        : QGraphicsRectItem(bounds, parent),
          isMoving(false) {}

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event) override {
        if (event->button() == Qt::LeftButton) {
            isMoving = true;
            previousCursorPos = event->pos();
        }
        QGraphicsRectItem::mousePressEvent(event);
    }

    void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override {
        if (isMoving) {
            QPointF displacement = event->pos() - previousCursorPos;
            moveBy(displacement.x(), displacement.y());
            previousCursorPos = event->pos();
        } else {
            QGraphicsRectItem::mouseMoveEvent(event);
        }
    }

    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override {
        isMoving = false;
        QGraphicsRectItem::mouseReleaseEvent(event);
    }

private:
    bool isMoving;
    QPointF previousCursorPos;
};

class ApplicationWindow : public QMainWindow {
public:
    ApplicationWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
        QGraphicsScene *canvas = new QGraphicsScene(this);
        QGraphicsView *viewport = new QGraphicsView(canvas, this);
        setCentralWidget(viewport);

        FullyDraggableRect *shape = new FullyDraggableRect(QRectF(50, 50, 180, 120));
        canvas->addItem(shape);
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    ApplicationWindow window;
    window.resize(500, 400);
    window.show();
    return app.exec();
}

Tags: Qt QGraphicsRectItem C++ Event Handling QGraphicsView

Posted on Fri, 16 Oct 2026 16:08:02 +0000 by Nimbuz