Constant size QGraphicsPixmapItem position problem
-
Hi,
First, sorry for my English, i'm french.
I'm facing a problem with the position of a constant size QGraphicsPixmapItem when the view is scaled.
Like on http://www.flightradar24.com/, I would like to display planes (constant size QGraphicsPixmapItems) on a "aeroport map" that can be rescaled.
To do this, I've a basic QGraphicsScene that contains a QGraphicsPixmapItem (picture) that represents the "aeroport map". On this map, I've planes, instances of QGraphicsPixmapItem class, with the flag QGraphicsItem::ItemIgnoresTransformations set. I've extended the QGraphicsView class and overrided the wheelEvent method to implement a zooming function with the mouse wheel.
The problem appears when I'm zooming --> The planes move. The position of the center of the plane change when I zoom in or out.
Plane on the track :
https://www.dropbox.com/s/6r6utd5o75d0evl/plane1.png?dl=0Plane move when zooming out (or in)
https://www.dropbox.com/s/xgb97o8b1n1zczo/plane2.png?dl=0What I have to do for the center of the plane stay at the same position when I'm zooming ?
In the documentation, i read this about the flag QGraphicsItem::ItemIgnoresTransformations : "When set, the item's view geometry and scene geometry will be maintained separately. You must call deviceTransform() to map coordinates and detect collisions in the view." --> but I don't understand when/where to invoke it and how to use it.
Here is my simple code:
@
class PlaneGraphicsItem : public QGraphicsPixmapItem
{
public:explicit PlaneGraphicsItem(QGraphicsItem* parent = NULL); virtual ~PlaneGraphicsItem(void);
};
PlaneGraphicsItem::PlaneGraphicsItem(QGraphicsItem* parent) :
QGraphicsPixmapItem(QPixmap(":/images/plane"), parent)
{
this->setFlag(QGraphicsItem::ItemIsMovable);
this->setFlag(QGraphicsItem::ItemIgnoresTransformations);this->setTransformOriginPoint(this->boundingRect().center());
}
PlaneGraphicsItem::~PlaneGraphicsItem(void){}
@@
class MapGraphicsView : public QGraphicsView
{
Q_OBJECTpublic: explicit MapGraphicsView(QWidget* parent = NULL); virtual ~MapGraphicsView(void); protected: virtual void wheelEvent(QWheelEvent* event); private: void scaleXY(double factor); protected: double _factor;
};
MapGraphicsView::MapGraphicsView(QWidget* parent) :
QGraphicsView(parent), _factor(1.2)
{
[...]this->setTransformationAnchor(QGraphicsView::AnchorUnderMouse); this->setDragMode(ScrollHandDrag);
}
MapGraphicsView::~MapGraphicsView(void) {}
void MapGraphicsView::wheelEvent(QWheelEvent* event)
{
// Zoom in
if (event->delta() > 0)
this->scaleXY(this->_factor);
// Zoom out
else
this->scaleXY(1.0/this->_factor);
}void MapGraphicsView::scaleXY(double factor)
{
this->scale(factor, factor);
}
@@
MainWidget::MainWidget(QWidget* parent) :
QWidget(parent), ui(new Ui::MainWidget),
_scene(NULL), _mapTrack(NULL), _planeItem(NULL)
{
this->ui->setupUi(this);// Create items this->_mapTrack = new QGraphicsPixmapItem(QPixmap(":/images/map")); this->_planeItem = new PlaneGraphicsItem(this->_mapTrack); // Create scene this->_scene = new QGraphicsScene(this); // Populate scene this->_scene->addItem(this->_mapTrack); this->ui->mapGraphicsView->setScene(this->_scene);
}
@Thanks for your help.
Best regards,
Xavier Mawet -
Up...
-
Up ...
-
I suspect the problem is related to changing the size of the image (the plane in this case) relative to the graphics scene. Your goal is to keep the graphics item the same size so therefore you must adjust the position of the graphics item on the graphics scene.
I had a similar problem but from a different cause (I wanted to adjust the size of the graphics images without having them move on the graphics scene). My solution was to use the center of the graphics image and adjust the position as the size changed. The item data 'ITEM_POS_FIELD' from the example represents the center coordinates of the image.
@
for(item_iter = d_item_images.begin();item_iter != d_item_images.end();++item_iter)
{
center_target = (*item_iter)->data(ITEM_POS_FIELD).toPointF();
center_offset = QPointF(d_item_size.width()/2,d_item_size.height()/2);center_target.setX(center_target.x() - center_offset.x());
center_target.setY(center_target.y() - center_offset.y());(*item_iter)->setPos(center_target);
}
@ -
Thanks for your help but it it didn't solve my problem.
-
This option could be contributing to your problem:
@
this->setFlag(QGraphicsItem::ItemIgnoresTransformations);
@I had a look at what I did for this. It is not too different from what you have in some regards but I didn't use 'QGraphicsItem::ItemIgnoresTransformations'.
If you do set this flag (QGraphicsItem::ItemIgnoresTransformations) for the graphicsitem I believe you need to manually do the transformations or position adjustments yourself. I don't see any of this in your example code.
-
This is the flag I used (class PlaneGraphicsItem, line 13). And when I zoom in/out the center of the plane doesn't stay at the same position. This is my problem.
But in the documentation, i read this about the flag QGraphicsItem::ItemIgnoresTransformations : “When set, the item’s view geometry and scene geometry will be maintained separately.You must call deviceTransform() to map coordinates and detect collisions in the view.” —> but I don’t understand when/where to invoke it and how to use it.
I see : " this thread on stackoverflow":http://stackoverflow.com/questions/1719694/getting-the-bounding-box-of-a-constant-size-item-in-qt-graphics-views but I don't know how to incorporate it in my code (and where ???)
-
You would need to perform the manual calculations after anything that changes the viewport or viewport scale. Probably in here:
@
void MapGraphicsView::scaleXY(double factor)
{
this->scale(factor, factor);// code here. See stackoverflow }
@
The link on stackoverflow seemed to have a solution and a mention of using an 'inverted vp_trans' matrix. The idea is to simply rearrange the data something like this:
@
| a | b | c |
| d | e | f |
| g | h | i |
@to
@
| a | d | g |
| b | e | h |
| c | f | i |
@The QTransform.transposed() function does this I believe.