PDA

View Full Version : have anyone used collidesWithItem?



rajesh
5th March 2007, 07:25
I am displaying multiple QGraphicsTextItem in a scene. all QGraphicsTextItem sets flag
QGraphicsTextItem::ItemIsMovable .
I want QGraphicsTextItem should not overlapped with other QGraphicsTextItem while moving QGraphicsTextItem using mouse.
any idea how to do that?
is there any example how to use QGraphicesItem::collidesWithItem()?

aamer4yu
5th March 2007, 09:37
I think you need to override the drag events for the items.
While drag move, u need to check if its colliding with other items, and if colliding, set its position to previous safe position.

I had implemented a case where I restricted a item within the scene rectangle. Hope it might help u :)

rajesh
5th March 2007, 09:58
can you send that code to restricted a item within the scene rectangle. it may help me.

wysota
5th March 2007, 10:02
Not drag events but mouseMoveEvent.

rajesh
5th March 2007, 10:08
I have written the following but its not working.


void GraphicsTextItem::mouseMoveEvent ( QGraphicsSceneMouseEvent * mouseEvent )
{
QPointF pt = pos();
QGraphicsTextItem::mouseMoveEvent ( mouseEvent );
QList<QGraphicsItem *> list = collidingItems() ;
if(list.count() > 0)
{
setPos(pt);
}
}

niko
25th September 2007, 18:55
hi,

i'm having the same problem.
And came up with the same (not working) solution. It is not working because the collidingItems-functions doesn't work for an item that is currenlty being moved. If I drop the item over another one I cant remove it form there (so the code is actually working)

any other ideas?

niko

spud
25th September 2007, 21:08
You want to override QGraphicsItem::itemChange() and check for ItemPositionChange. Just like the example in the docs.

Bitto
25th September 2007, 21:10
The best and most efficient approach is to use QGraphicsItem::itemChange(). That way you can avoid moving the item forward and backward. Also by reimplementing this function, you can snap up any other attempt to move the item, not just mouseMove() but also setPos(), and you can even intercept transformation changes (which can also affect the item's position). Here's one way to stop an item from being moved if it collides with another (untested code):



QVariant MyItem::itemChange(GraphicsItemChange change, const QVariant &val)
{
if (change == ItemPositionChange) {
QPainterPath sceneShape = mapToParent(shape()).translate(val.toPointF());
if (QGraphicsItem *parent = parentItem())
sceneShape = parent->mapToScene(sceneShape);
if (scene()->items(sceneShape, Qt::IntersectsItemShape).size() > 1) {
// Collision! Don't move.
return pos();
}
}
return QGraphicsItem::itemChange(change, val);
}


This is a bit crude, but I hope you get the picture. Map your shape to your parent coordinates, translate it by your future position (provided through the val-argument), and map that to the scene if necessary. Now ask the scene if any item other than your own collides with that shape. If so, return the old pos instead of the new one to effectively abort the repositioning.

It's crude, because 1) you really want to check if the list of items is empty, or contains only your item (not just that it contains at most 1 item). And 2) because instead of just not moving the item, it's common to neatly position the item at the point of intersection / right next to the other. That's hard to do in general, so I'll leave that up to the app writer to figure out ;-).

niko
26th September 2007, 21:15
much thanks - this is the code that works for me:


QPainterPath path = shape();

QMatrix matrix;
matrix.translate(value.toPointF().x(), value.toPointF().y());
polygon = matrix.map(path);

QList<QGraphicsItem*> items = scene()->items(path, Qt::IntersectsItemShape);
items.removeAll(this);

if (!items.isEmpty()) {
// Collision! Don't move.
return pos();
}


i didn't need the mapToParent and mapToScene calls. furthermore QPainterPath doesn't have a translate-function afaics - so i used qmatrix for that...

niko