PDA

View Full Version : QGraphicsItem inheritence



bajarangi
11th August 2009, 17:46
I need to subclass an existing QGraphicsItem and change the painting
and size. I started modifying the elasticnodes example and came up with
these changes:



class Node : public QGraphicsItem
{
public:
Node(GraphWidget *graphWidget);

void addEdge(Edge *edge);
QList<Edge *> edges() const;

enum { Type = UserType + 1 };
int type() const { return Type; }

void calculateForces();
bool advance();

virtual QRectF boundingRect() const;
QPainterPath shape() const;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value);

virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);

QList<Edge *> edgeList;
QPointF newPos;
GraphWidget *graph;

private:

};


So for my derived class, I need to make boundingRect(), paint(), and mousePressEvent() virtual, because I want my class to paint a pixmap
and catch it's own mousePressEvents.
Correct?

So I subclassed Node, loaded a rectangular image in the constructor, implemented boundingRect(), paint(), and mousePressEvent(). Compiles and runs ok.
Just one problem - I can't drag the rectangular image by the mouse!

Some qDebug statements in the relevant methods shows that the derived class
is receiving mousePressEvents, but only in the exact area where a Node (ball) would be (around 0,0 in my pixmap). It looks like I need to make another method in Node virtual to override the default area where a Node accepts mouse events.

I hope this is clear. The attached jpg shows a closeup.
The white circle is some sort of "ghost" node that will accept a mouse press
and allow me to drag the pixmap. I can't drag the pixmap anywhere else.

thanks,
-baj

wysota
11th August 2009, 21:20
So for my derived class, I need to make boundingRect(), paint(), and mousePressEvent() virtual, because I want my class to paint a pixmap
and catch it's own mousePressEvents.
Correct?
They already are virtual. You just need to reimplement the methods.


So I subclassed Node, loaded a rectangular image in the constructor, implemented boundingRect(), paint(), and mousePressEvent(). Compiles and runs ok.
Just one problem - I can't drag the rectangular image by the mouse!
Call the base class implementation of mousePressEvent() and mouseReleaseEvent() in your reimplementations.

bajarangi
11th August 2009, 23:01
Thanks again, Wysotta. Still no joy here.
So I removed the virtual keywords from the Node class, recompiled and ran. No change.

Here's the derived class declaration:


class CloudNode : public Node
{
public:
CloudNode(GraphWidget *graphWidget);

protected:
void paint( QPainter *, const QStyleOptionGraphicsItem *option, QWidget *widget );
QRectF boundingRect() const;
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);

private:
QImage *cloudimage;
QPixmap pixmap;
};

CloudNode::CloudNode(GraphWidget *graphWidget) : Node(graphWidget)
{
qDebug() << "Creating CloudNode";
cloudimage = new QImage(); // = new QImage();
bool loadsuccess = cloudimage->load("./images/background.png");
qDebug() << "CloudNode loaded image = " << loadsuccess;
setFlag(ItemIsMovable);
setCacheMode(DeviceCoordinateCache);
pixmap = QPixmap::fromImage(*cloudimage, Qt::OrderedAlphaDither);
}


void CloudNode::paint( QPainter *p, const QStyleOptionGraphicsItem *option, QWidget * )
{
qDebug() << "CloudNode::paint";
p->drawPixmap(0, 0, pixmap);
}

QRectF CloudNode::boundingRect() const
{
int adjust = 0;
QRectF noderect(-adjust, -adjust, cloudimage->width() +10, cloudimage->height()+10);
//qDebug() << "CloudNode width " << noderect.width() << " height " << noderect.height();
return noderect;
}

void CloudNode::mousePressEvent(QGraphicsSceneMouseEven t *event)
{
update();
QGraphicsItem::mousePressEvent(event);
qDebug() << "CloudNode mouse x " << event->pos().x() << " y " << event->pos().y();
}



Problem persists as before. I can click and drag the pixmap in a small area around
0,0 and qDebug output shows:
CloudNode mouse x 2.64032 y 0.489026
But I don't receive the mouse click anywhere else in the pixmap.

Do I have to re-implement itemChange() ? I wouldn't think so, that only
is called after the mouse event is received.

In Graphwidget constructor I have this for a CloudNode:
CloudNode *cnode8 = new CloudNode(this);
scene->addItem(cnode8);
scene->addItem(new Edge(cnode8, node7));
cnode8->setPos(150, 150);

wysota
11th August 2009, 23:06
I'd guess your boundingRect() or shape() implementation is incorrect. Try reimplementing shape() to return the result of boundingRect() and see if it changes anything.

bajarangi
12th August 2009, 00:45
SUCCESS!

Yea, the runtime was defaulting to the Node implementation of shape(), which
was an elipse around 0,0. Reiplemented shape() in CloudNode like:


QPainterPath CloudNode::shape() const
{
QPainterPath path;
path.addRect(0, 0, cloudimage->width(), cloudimage->height());
return path;
}

and I can now drag the pixmap from any point in the rectangle.

Thanks again.
-baj