PDA

View Full Version : QGraphicsItem Tracer



dimixan
23rd January 2010, 23:40
I have a QGraphicsItem (A) and I would like to implement a path tracing functionality for it. (ie as A changes position, a graphical trace is drawn on QGraphicsView).

I was thinking to create a custom QGraphicsItem (B) with a QPolygonF data member which will hold N points. Then in the paintEvent, use those points to draw N circles, one next the other thus creating the trace I want. My problem is a part of QGraphicsItem documentation which states the following:

"QGraphicsScene expects all items boundingRect() and shape() to remain unchanged unless it is notified. If you want to change an item's geometry in any way, you must first call prepareGeometryChange() to allow QGraphicsScene to update its bookkeeping.".

So calling prepareGeometryChange() in every paintEvent is not a solution.

Any suggestions on what should I do?

NOTE: I would prefer a solution where the tracer is a child of A.

wysota
24th January 2010, 00:03
Here is a hint: items don't move as a result of paint events. You get notified upon position changes of items through QGraphicsItem::itemChange().

dimixan
24th January 2010, 00:38
ok to put it in another way.... How bad is the following?



void
TracerGraphicsItem::paint(QPainter* pPainter, const QStyleOptionGraphicsItem* pOption, QWidget* pWidget)
{
m_points.append(scenePos());
if(m_points.count() > 50)
m_points.remove(0);

pPainter->setBrush(Qt::blue);
pPainter->setPen(Qt::NoPen);

foreach(QPointF p, m_points)
pPainter->drawEllipse(m_rect.translated(p-scenePos()));
}

wysota
24th January 2010, 00:54
Very bad as you don't know how many times your item will be repainted. Especially when things like caching or dragging windows over other windows are involved. Why don't you use itemChange()?

dimixan
24th January 2010, 01:17
I'm not using itemChange() because I really can't see how that would help me to implement the tracer I want!
To make sure we're on the same track, i'm attaching a screenshot which show the results of the previous code I posted (which I know is bad).

(btw the code above does what I want if and only if the parent of the tracer (ie the box in the picture) is not rotated at all)

Edit: The only thing I can see doing in itemChange() is to update the points of the path (instead of doing it in paint())

ecanela
24th January 2010, 02:34
i read the problem and i think you need use the itemChange() funtion.

instead of have a QList<Point> to keep track of the tracing point. you need to have a QList<QGraphicsEllipseItem> to keep track. this way each point has you own paint() and no need to call prepareGeometryChange () every time you insert a point in the scene.

the correct way, or at least the most easy way to catch the item position when tracing the item is in the itemChange() function using the QGraphicsItem::ItemPositionChange. when the position change creata a ellipseItem. make each ellipse item parent to A.


if you draw the tracing points in the paint() of item A, you need recalculate the boundingRect () of A every time you insert a point in the scene

wysota
24th January 2010, 09:13
I'm not using itemChange() because I really can't see how that would help me to implement the tracer I want!
It would help you keep track of position changes of your item.


(btw the code above does what I want if and only if the parent of the tracer (ie the box in the picture) is not rotated at all)
I can break your code in 15 seconds.


Edit: The only thing I can see doing in itemChange() is to update the points of the path (instead of doing it in paint())
That's exactly what you should do. The whole "bad" thing with your code is that you update the list from painting routine.

Edit: Of course you shouldn't draw the points in the paint() routine as well. Either implement it as an effect for your item or as a child or associated item to your item.

aamer4yu
25th January 2010, 04:46
You can also consider the following design -
Have a list of points associated with each graphics item. And use these points to in QGraphicsScene::drawBackground to draw the trails.
You can also have a pixmap for background, and you need to update the pixmap on itemChange signal . This approach might save you from using item for the trails.

Wazman
14th February 2010, 04:59
I have a similar implementation problem.

I'm developing a 2D earth plot using the Graphics View Framework to represent the flight path of a aircraft (Position in Latitude and Longitude). The background is a image of a Mercator projection of the earth added via (QGraphicView). I already have the means of converting from geographical coordinates to the scene coordinates.

The user needs to have the ability to add or delete aircraft (0 to 10) hence each aircraft is a reimplementation of QGraphicsItem. Each aircraft stores its initial position (Lat & Lon) and adds its current position to storage "QList" during its flight. I want to show the flight path from take off (New York ) to landing (Paris). The user must have the ability of selecting a aircraft and seeing where it had taken off from even after it has already started its journey.

I plan on updating the Earth Plot via a QTimer connected to the scene's advance() slot (similar to the Colliding Mice Example) during the aircraft flight.

In the AircraftItem every time it geographical position has been updated and the QTimer timeout() signal is triggered then in my AircraftItem::advance(int step) function I was planning on calling AircraftItem::itemChange() to change its position translated into the scene's coordinates.

Ideally the whole flight path is represented by a QPainter::drawPolyline

When I update the aircraft's position on my plot do I need to change its boundingRect() "Not really sure how to do this, btw" and should I do my drawing in its paint function.

Wazman
15th February 2010, 00:26
NOTE In my AircraftItem Object when my advance(int step) function is activated by the QTimer::timeout() signal I want to update the aircraft's current position (converted into the scene's coordinates) Now as I draw the flight path from the initial starting point. Does the entire flight path trace need to be within the AIrcraftItem::boundingRect()?