问题
This question is related to: Forcing QGraphicsItem To Stay Put
I'd like to have a QGraphicsItem
on a fixed location when moving around in the scene.
The suggested solution is to override the void paintEvent(QPaintEvent*)
of the sub-classed QGraphicsView
.
void MyGraphicsView::paintEvent(QPaintEvent*) {
QPointF scenePos = mapToScene(0,0); // map viewport's top-left corner to scene
myItem->setPos(scenePos);
}
However, the problem is that I want everything else in the scene to stay intact, i.e. if I zoom or move I want all other QGraphicsItems
to behave as default.
One poor way of solving this is to call void QGraphicsView::paintEvent(QPaintEvent*)
from within void MyGraphicsView::paintEvent(QPaintEvent*)
.
void MyGraphicsView::paintEvent(QPaintEvent* event) {
QGraphicsView::paintEvent(event);
QPointF scenePos = mapToScene(0,0); // map viewport's top-left corner to scene
myItem->setPos(scenePos);
}
However, this adds a flickering behaviour to my_item
since it's positioned first using QGraphicsView::paintEvent(event);
and then using the added code
QPointF scenePos = mapToScene(0,0); // map viewport's top-left corner to scene
myItem->setPos(scenePos);
The question is, do I have to re-implement void MyGraphicsView::paintEvent(QPaintEvent*)
from scratch and write code for both the desired behaviour of myItem
and the default behaviour of all other QGraphicsItems
, or is there an easier way to do this?
Thank you.
回答1:
I think this is what you are looking for:
http://qt-project.org/doc/qt-4.8/qgraphicsitem.html#setFlag
QGraphicsItem::ItemIgnoresTransformations
Description from the docs:
The item ignores inherited transformations (i.e., its position is still anchored to its parent, but the parent or view rotation, zoom or shear transformations are ignored). This flag is useful for keeping text label items horizontal and unscaled, so they will still be readable if the view is transformed. 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. By default, this flag is disabled. This flag was introduced in Qt 4.3. Note: With this flag set you can still scale the item itself, and that scale transformation will influence the item's children.
You may also want to parent everything that does pan around to something else. Then, you move or scale or rotate a single graphics group to affect everything except your "un-transformable" objects.
https://qt-project.org/doc/qt-4.8/graphicsview.html#the-graphics-view-coordinate-system
https://qt-project.org/doc/qt-4.8/painting-transformations.html (a cool example, though it doesn't show this feature really)
http://qt-project.org/doc/qt-4.8/demos-chip.html (great example of using QGraphicsView
)
Hope that helps.
EDIT:
Example showing how you can achieve a static layer using parenting:
main.cpp
#include <QApplication>
#include "mygraphicsview.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyGraphicsView w;
w.show();
return a.exec();
}
mygraphicsview.h
#ifndef MYGRAPHICSVIEW_H
#define MYGRAPHICSVIEW_H
#include <QGraphicsView>
#include <QGraphicsItemGroup>
#include <QMouseEvent>
class MyGraphicsView : public QGraphicsView
{
Q_OBJECT
public:
MyGraphicsView(QWidget *parent = 0);
~MyGraphicsView();
public slots:
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private:
bool down;
QPointF m_last_pos;
QGraphicsItemGroup * m_group;
};
#endif // MYGRAPHICSVIEW_H
mygraphicsview.cpp
#include "mygraphicsview.h"
#include <QGraphicsItem>
#include <QGraphicsEllipseItem>
#include <QGraphicsTextItem>
MyGraphicsView::MyGraphicsView(QWidget *parent)
: QGraphicsView(parent)
{
down = false;
this->setScene(new QGraphicsScene);
// Anything not added to the "group" will stay put
this->scene()->addEllipse(20, 20, 50, 50);
this->scene()->addEllipse(180, 180, 50, 50);
this->scene()->addText("Click and drag with the mouse to move only the tiny dots.");
// This group will receive all transformations
m_group = new QGraphicsItemGroup;
for(int r = 0; r < 20; r ++)
{
for(int c = 0; c < 20; c++)
{
if(c % 5 == 0 && r % 5 == 0)
{
QGraphicsTextItem * txt = new QGraphicsTextItem(QString::number(r) + "," + QString::number(c));
m_group->addToGroup(txt);
txt->setPos(r*100, c*100);
}
m_group->addToGroup(new QGraphicsEllipseItem(r *100, c*100, 5, 5));
}
}
this->scene()->addItem(m_group);
}
MyGraphicsView::~MyGraphicsView()
{
}
void MyGraphicsView::mousePressEvent(QMouseEvent *event)
{
m_last_pos = mapToScene(event->pos());
down = true;
}
void MyGraphicsView::mouseReleaseEvent(QMouseEvent *)
{
down = false;
}
void MyGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
if(down)
{
QPointF temp = mapToScene(event->pos());
QPointF delta = temp - m_last_pos;
m_last_pos = temp;
// Apply transformation to the group, not the scene!
m_group->translate(delta.x(), delta.y());
}
}
来源:https://stackoverflow.com/questions/17373210/fixed-qgraphicsitem-position-without-changing-behaviour-of-other-qgraphicsitems