restrict movable area of qgraphicsitem

2019-04-10 16:25发布

问题:

Is there a way to restrict the area where a QGraphicsItem like QRect can be moved when setFlag(ItemIsMovable) is set?

I'm new to pyqt and trying to find a way to move an item with the mouse, and the restrict it to only vertically/horizontally.

回答1:

If you want to keep a limited area you can reimplement the ItemChanged()

Declare:

#ifndef GRAPHIC_H
#define GRAPHIC_H
#include <QGraphicsRectItem>
class Graphic : public QGraphicsRectItem
{
public:
    Graphic(const QRectF & rect, QGraphicsItem * parent = 0);
protected:
    virtual QVariant    itemChange ( GraphicsItemChange change, const QVariant & value );
};

#endif // GRAPHIC_H

implementation : ItemSendsGeometryChanges flag is needed to capture the change in position of QGraphicsItem

#include "graphic.h"
#include <QGraphicsScene>

Graphic::Graphic(const QRectF & rect, QGraphicsItem * parent )
    :QGraphicsRectItem(rect,parent)
{
    setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemSendsGeometryChanges);
}

QVariant Graphic::itemChange ( GraphicsItemChange change, const QVariant & value )
{
    if (change == ItemPositionChange && scene()) {
        // value is the new position.
        QPointF newPos = value.toPointF();
        QRectF rect = scene()->sceneRect();
        if (!rect.contains(newPos)) {
            // Keep the item inside the scene rect.
            newPos.setX(qMin(rect.right(), qMax(newPos.x(), rect.left())));
            newPos.setY(qMin(rect.bottom(), qMax(newPos.y(), rect.top())));
            return newPos;
        }
    }
    return QGraphicsItem::itemChange(change, value);
}

Then we define the rectangle of the scene, in this case will be 300x300

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    QGraphicsView * view = new QGraphicsView(this);
    QGraphicsScene * scene = new QGraphicsScene(view);
    scene->setSceneRect(0,0,300,300);
    view->setScene(scene);
    setCentralWidget(view);
    resize(400,400);

    Graphic * graphic = new Graphic(QRectF(0,0,100,100));
    scene->addItem(graphic);
    graphic->setPos(150,150);

}

This is to keep the graph within an area, good luck



回答2:

re implement the mouseMoveEvent(self,event) in the QGraphicScene like the following :

def mousePressEvent(self, event ):

    self.lastPoint = event.pos()

def mouseMoveEvent(self, point):

    if RestrictedHorizontaly: # boolean to trigger weather to restrict it horizontally 
        x = point.x()
        y = self.lastPoint.y()
        self.itemSelected.setPos(QtCore.QPointF(x,y))<br> # which is the QgraphicItem that you have or selected before

hope it helps



回答3:

You would probably need to re-implement the QGraphicsItem's itemChange() function.

Pseudocode:

if (object position does not meet criteria):
    (move the item so its position meets criteria)

Repositioning the item will cause itemChange to get called again, but that's ok because the item will be positioned correctly and won't be moved again, so you'll not be stuck in an endless loop.