PDA

View Full Version : How to create a QGraphicsItem compound?



Cruz
22nd April 2015, 15:23
Hello!

I need to create a slightly complex item for a graphics scene. In particular, imagine a circle that is flying across the screen. The circle has a position, of course, and there is an arrow attached to it, which indicates its velocity. I would like to drag the circle with the mouse to change its position, and I would like to be able to drag the tip of the arrow in order to change the velocity. What is the best strategy to create this item?

I could for example just subclass QGraphicsEllipseItem which gives me the circle, and hack the rest into it by drawing the error in the paint() method, and checking in the mouse event methods if the mouse is on the arrow or on the circle. This way seems a bit hack and I'm sure there is a cleaner way.

I could also subclass QGraphicsEllipseItem and QGraphicsLineItem and add the circle and the arrow as separate items to the scene and connect the arrow to the circle using a parent child relationship. I don't now how I would go about keeping things on one object in the end, one object that has a position and a velocity. Do I somehow find the parent of the arrow and write the velocity into the parent?

Then there are also item groups, but I don't see any advantage of using them at the moment.

Can anyone give pointers please?


Thanks
Cruz

Santosh Reddy
22nd April 2015, 15:56
Do I somehow find the parent of the arrow and write the velocity into the parent?
It's seems as a good approach.

Cruz
22nd April 2015, 16:32
It's seems as a good approach.

Except that the child wouldn't know the type of the parent other than that it's a QGraphicsItem, which means I would have to perform an ugly cast to be able to access the necessary fields.

Santosh Reddy
22nd April 2015, 16:38
You could use QGraphicsItem::setData() and QGraphicsItem::data() to store any custom data


void QGraphicsItem::setData(int key, const QVariant & value)
QVariant QGraphicsItem::data(int key) const

That way you can avoid casting

Cruz
22nd April 2015, 17:03
You could use QGraphicsItem::setData() and QGraphicsItem::data() to store any custom data


void QGraphicsItem::setData(int key, const QVariant & value)
QVariant QGraphicsItem::data(int key) const

That way you can avoid casting

True, but then I always have to access the velocity of the object from the data() field and I lose the ability to use the object as a vector with standard mathematical operations. Somehow I feel it would be best if the circle and its arrow were in one object. I just don't know how to route the mouse events from the arrow tip to the circle.

Added after 9 minutes:

Also, I would have to notify the parent somehow that the data have changed. How do I do that?

anda_skoa
22nd April 2015, 18:22
Except that the child wouldn't know the type of the parent other than that it's a QGraphicsItem, which means I would have to perform an ugly cast to be able to access the necessary fields.

Nothing keeps you from using your own constructor on the arrow item that takes a pointer to your master item as its parent.



class ArrowItem : public QGraphicsItem // or whatever you want to use as a base class
{
public:
explicit ArrowItem(CircleItem *parent = 0)
: QGraphicsItem(parent)
, m_circle(parent)
{
}

private;
Circleitem *const m_circle;
};


Cheers,
_

Cruz
22nd April 2015, 18:53
Yes this is a good suggestion. I ended up subclassing them from QObject so that I can connect them with signals and slots, which is very similar to what you suggested really.

anda_skoa
22nd April 2015, 19:05
Well, you have a one-on-one relation ship between the circle item and the arrow, so the arrow could just call an update method on the parent.

Cheers,
_