2

I have a QGraphicsPixmap item in a QGraphicsScene. The item has flags set to ItemIsMovable, and ItemIsSelectable. How do I ensure that when the item is moved out of a certain boundary - it can be a QGraphicsScene or just a fixed frame size at fixed coordinates - the part becomes hidden?

Eg. enter image description here

The left part of the basketball becomes hidden.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
ALH
  • 85
  • 4
  • 14

1 Answers1

2

You have to use setClipPath().

In the following code I have created a class that inherits from QGraphicsPixmapItem (the same could do with other classes that inherit from QGraphicsItem) and I created the method setBoundaryPath() that receives a QPainterPath that indicates the visible area, for example in the code use:

QPainterPath path;
path.addRect(QRectF(100, 100, 400, 200));

That QPainterPath is a rectangle whose topleft is the point (100, 100) of the QGraphicsScene with size of 400 in width and 200 in height.

#include <QApplication>
#include <QGraphicsRectItem>
#include <QGraphicsView>

class GraphicsPixmapItem: public QGraphicsPixmapItem{

public:
    GraphicsPixmapItem(const QPixmap & pixmap,  QGraphicsItem *parent = 0):
        QGraphicsPixmapItem(pixmap, parent)
    {
        setFlag(QGraphicsItem::ItemIsMovable, true);
        setFlag(QGraphicsItem::ItemIsSelectable, true);
    }
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
        if(!m_boundaryPath.isEmpty()){
            QPainterPath path = mapFromScene(m_boundaryPath);
            if(!path.isEmpty())
                painter->setClipPath(path);
        }
        QGraphicsPixmapItem::paint(painter, option, widget);
    }

    QPainterPath boundaryPath() const{
        return m_boundaryPath;
    }
    void setBoundaryPath(const QPainterPath &boundaryPath){
        m_boundaryPath = boundaryPath;
        update();
    }

private:
    QPainterPath m_boundaryPath;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsView view;
    QGraphicsScene scene(0, 0, 600, 400);
    view.setScene(&scene);
    view.setBackgroundBrush(QBrush(Qt::gray));

    GraphicsPixmapItem *p_item = new GraphicsPixmapItem(QPixmap(":/ball.png"));
    p_item->setPos(100, 100);

    // Define the area that will be visible
    QPainterPath path;
    path.addRect(QRectF(100, 100, 400, 200));

    p_item->setBoundaryPath(path);
    scene.addItem(p_item);

    // the item is added to visualize the intersection
    QGraphicsPathItem *path_item = scene.addPath(path, QPen(Qt::black), QBrush(Qt::white));
    path_item->setZValue(-1);
    view.show();
    return a.exec();
}

enter image description here

enter image description here

You can find the example code in this link.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • I wonder what's the `certain boundary` which the OP means. Why not just use a layer contains transparent stack on the basketball... – JustWe May 24 '18 at 01:40
  • I've edited the question to clarify `certain boundary`. There is no fixed approach at the moment. – ALH May 24 '18 at 03:36
  • @ALH a QGraphicSscene is everyone in QGraphicsView, that has no limits, explain how you determine that area, do not confuse sceneRect () with QGraphicsScene. in my example I add an item so that the area is visible but you can delete the path_item, in my example it is determined by the QPainterPath. – eyllanesc May 24 '18 at 03:41
  • @ALH I have added a clearer explanation to my answer, please review it. – eyllanesc May 24 '18 at 04:14
  • Hmm, with your code, it still seems like the image is visible on the grey background. – ALH May 24 '18 at 04:56
  • @ALH have you tried my code ?, the images that I have published prove it, you could show me what you get. – eyllanesc May 24 '18 at 08:06
  • @Jiu If my code works, you could give it an upvote. :D – eyllanesc May 24 '18 at 09:54
  • The answer gives correct result as I understand the question...But _it still seems like the image is visible on the grey background_ How could this possible? – JustWe May 24 '18 at 09:58
  • @Jiu What I think is that the askers do not know how to correctly implement the solution in their own project, that happens a lot with the beginners. ;-D – eyllanesc May 24 '18 at 10:00
  • Thanks all. The given answer works. I had a line: `painter->drawPixmap(offset(), pixmap());` in the `paint` function before `setClipPath`, which seemed to override the clipPath. I got it to work by switching the order. – ALH May 24 '18 at 16:52