【问题标题】:Fixed QGraphicsItem position, without changing behaviour of other QGraphicsItems in scene固定 QGraphicsItem 位置,而不改变场景中其他 QGraphicsItems 的行为
【发布时间】:2013-06-26 17:29:39
【问题描述】:

此问题与:Forcing QGraphicsItem To Stay Put

我希望在场景中移动时将QGraphicsItem 放在固定位置。

建议的解决方案是覆盖子类QGraphicsViewvoid paintEvent(QPaintEvent*)

void MyGraphicsView::paintEvent(QPaintEvent*) {
  QPointF scenePos = mapToScene(0,0); // map viewport's top-left corner to scene
  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); // map viewport's top-left corner to scene
  myItem->setPos(scenePos);
}

但是,这会为 my_item 添加闪烁行为,因为它首先使用 QGraphicsView::paintEvent(event); 定位,然后使用添加的代码

QPointF scenePos = mapToScene(0,0); // map viewport's top-left corner to scene
myItem->setPos(scenePos);

问题是,我是否必须从头开始重新实现void MyGraphicsView::paintEvent(QPaintEvent*) 并为myItem 的所需行为和所有其他QGraphicsItems 的默认行为编写代码,或者有更简单的方法吗?这个?

谢谢。

【问题讨论】:

  • 打电话给setPos()之后为什么不打电话给paintEvent()
  • @Chris 效果会更差。在整个屏幕上显示该项目的痕迹。
  • 您可以使用QGraphicsItem::itemChange 功能,看看您是否收到一些通知吗?也许QGraphicsItem::ItemScenePositionHasChanged 是您需要的。您必须启用 QGraphicsItem::ItemSendsScenePositionChanges 标志才能使其工作。

标签: c++ qt qgraphicsview qgraphicsitem qgraphicsscene


【解决方案1】:

我想这就是你要找的东西:

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

【讨论】:

  • 抱歉,ItemIgnoresTransformations 已设置。这无助于在场景中四处走动。
  • 您是否尝试过将其他所有内容都交给另一个 QGraphicsItemGroup,然后将翻译应用到那个而不是场景?
  • 那还是得让我从头开始实现void MyGraphicsView::paintEvent(QPaintEvent*),对吧?
  • 我将在接下来的几分钟内整理出一个示例。如果你做正确的育儿,你不应该这样做。
猜你喜欢
  • 2014-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 2021-03-21
  • 1970-01-01
  • 2019-05-14
相关资源
最近更新 更多