固定QGraphicsItem位置,而不改变其他QGraphicsItems在场景中的行为 [英] Fixed QGraphicsItem position, without changing behaviour of other QGraphicsItems in scene

查看:814
本文介绍了固定QGraphicsItem位置,而不改变其他QGraphicsItems在场景中的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题与以下相关:强制QGraphicsItem保持搁置



我想在场景中移动时在固定位置上有 QGraphicsItem



建议的解决方案是覆盖子类别<$ c $的 void paintEvent(QPaintEvent *) c> QGraphicsView 。

  void MyGraphicsView :: paintEvent(QPaintEvent *){
QPointF scenePos = mapToScene(0,0); //将viewport的左上角映射到场景
myItem-> setPos(scenePos);
}

但是,问题是我想让场景中的其他东西保持原样,即如果我缩放或移动我想要所有其他 QGraphicsItems 作为默认行为。



一个很差的解决方法这是调用 void MyGraphicsView :: paintEvent(QPaintEvent *) void QGraphicsView :: paintEvent(QPaintEvent *)

  void MyGraphicsView :: paintEvent(QPaintEvent * event){
QGraphicsView :: paintEvent(event);

QPointF scenePos = mapToScene(0,0); //将viewport的左上角映射到场景
myItem-> setPos(scenePos);但是,这会给 my_item 添加一个闪烁的行为,因为<$ c $ b> / code>,因为它首先使用 QGraphicsView :: paintEvent(event); 定位,然后使用添加的代码

  QPointF scenePos = mapToScene(0,0); //将viewport的左上角映射到场景
myItem-> setPos(scenePos);问题是,我是否必须重新实现 void MyGraphicsView :: a:


$ b paint< code> myItem
的所有行为以及所有其他的默认行为,从头开始绘制paintEvent(QPaintEvent *) QGraphicsItems
,还是有更简单的方法来做到这一点?



谢谢。

解决方案

我认为这是您要寻找的:



http://qt-project.org/doc/qt-4.8/qgraphicsitem .html#setFlag



QGraphicsItem :: ItemIgnoresTransformations



从文档中的描述:


项目忽略继承的转换(即,它的位置仍然锚定到其父,父或视图旋转,缩放或剪切变换被忽略)。此标志对于将文本标签项保持水平和不缩放非常有用,因此如果视图被转换,它们仍然可以被读取。设置时,项目的视图几何和场景几何将单独维护。您必须调用deviceTransform()来映射坐标并检测视图中的冲突。默认情况下,禁用此标志。这个标志是在Qt 4.3中引入的。注意:设置此标志后,您仍然可以对项目本身进行缩放,而且缩放转换将影响项目的子项。


想要父母一切都做到其他东西。然后,您移动或缩放或旋转单个图形组以影响除了不可变换对象之外的所有内容。



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 (一个很酷的例子,虽然它没有显示这个功能真的)



http ://qt-project.org/doc/qt-4.8/demos-chip.html (使用 QGraphicsView 的大例子)



希望有帮助。



编辑:



使用父级实现静态图层:



main.cpp

  include< QApplication> 
#includemygraphicsview.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>

类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

  #includemygraphicsview.h

#include< QGraphicsItem>
#include< QGraphicsEllipseItem>
#include< QGraphicsTextItem>

MyGraphicsView :: MyGraphicsView(QWidget * parent)
:QGraphicsView(parent)
{
down = false;
this-> setScene(new QGraphicsScene);

//没有添加到组中的任何东西将保持为
this-> scene() - > addEllipse(20,20,50,50);
this-> scene() - > addEllipse(180,180,50,50);
this-> scene() - > addText(用鼠标点击并拖动,只移动小点。

//这个组将接收所有的转换
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;

//将转换应用到组,而不是场景!
m_group-> translate(delta.x(),delta.y());
}
}


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.

解决方案

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());
    }
}

这篇关于固定QGraphicsItem位置,而不改变其他QGraphicsItems在场景中的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆