【问题标题】:QGraphicsItemGroup::boundingRect() not updatingQGraphicsItemGroup::boundingRect() 未更新
【发布时间】:2018-08-16 06:05:38
【问题描述】:

我一直在尝试使用 QGraphicsItemGroup 来获取一组 QGraphicsItem*s 的边界矩形。在我看来,当我将所有项目插入组时,边界矩形是正确确定的;但是如果我随后移动组中的项目,则边界矩形不会像我预期的那样更新以包含移动的项目。我在文档中找不到关于我所看到的行为是否正确的指示;我的猜测是我要么误解了 QGraphicsItemGroup 的工作原理,要么滥用了它

我用来测试的一个例子:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QTransform>
#include <QGraphicsEllipseItem>
#include <QDebug>
#include <QTimer>

#include <cmath>

const double pi = 3.14;

QTransform rotation(double degrees)
{

    double a    = pi/180 * degrees;
    double sina = sin(a);
    double cosa = cos(a);

    return QTransform(cosa, sina, -sina, cosa, 0, 0);
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    scene = new QGraphicsScene(this);
    ui->graphicsView->setScene(scene);
    ui->graphicsView->show();

    //Shouldn't execute until after window.show() and application.exec()
    //are called
    QTimer::singleShot(1, this, &MainWindow::build);
}

void MainWindow::build()
{
    QGraphicsEllipseItem* el1 = scene->addEllipse(-5, -5, 10, 10);
    scene->addLine(0, 0, 0, 10)->setParentItem(el1);

    QGraphicsEllipseItem* el2 = scene->addEllipse(-5, -5, 10, 10);
    scene->addLine(0, 0, 0, 10)->setParentItem(el2);

    QGraphicsEllipseItem* el3 = scene->addEllipse(-5, -5, 10, 10);
    scene->addLine(0, 0, 0, 10)->setParentItem(el3);

    QGraphicsEllipseItem* el4 = scene->addEllipse(-5, -5, 10, 10);
    scene->addLine(0, 0, 0, 10)->setParentItem(el4);

    QGraphicsItemGroup* group = new QGraphicsItemGroup;
    group->addToGroup(el1);
    group->addToGroup(el2);
    group->addToGroup(el3);
    group->addToGroup(el4);

    scene->addItem(group);

    scene->addRect(group->boundingRect());

    QTransform translate2(1, 0, 0, 1, 10, 10);
    QTransform t2 = /*rotation(45) **/ translate2;
    el2->setTransform(t2);

    QTransform translate3(1, 0, 0, 1, 20, 20);
    QTransform t3 = /*rotation(-45) **/ translate3 * t2;
    el3->setTransform(t3);

    QTransform translate4(1, 0, 0, 1, 20, -20);
    QTransform t4 = translate4 * t3;
    el4->setTransform(t4);

    qDebug() << t4.dx() << t4.dy() << atan2(t4.m12(), t4.m22())*180/pi;
    QTransform t4i = t4.inverted();
    qDebug() << t4i.dx() << t4i.dy() << atan2(t4i.m12(), t4i.m22())*180/pi;

    scene->addRect(group->boundingRect());
}

MainWindow::~MainWindow()
{
    delete ui;
}

显示的最终场景是这样的

实际结果

但是,我期待这样的东西,第一个 boundingRect 有一个小框,第二个有一个更大的框

预期结果

我是否误解了 QGraphicsItemGroup 的工作原理,还是我使用不当?

Qt 版本:5.10

操作系统:Ubuntu 16.04

编译器 GCC 5.4

【问题讨论】:

    标签: c++ qt qgraphicsview qgraphicsscene qgraphicsitem


    【解决方案1】:

    boundingrect 仅在 additem 处更新。因此必须使用方法childrenBoundingRect() 而不是boundingRect()。 在 QGraphicsItemGroup 的单独子类中说 MyQGraphicsItemGroup 我们可以重载方法 virtual QRectF boundingRect() const override 以便调用 childrenBoundingRect()

    QRectF MyQGraphicsItemGroup::boundingRect() const
    {
       // must be overloaded, otherwise the boundingrect will only be actualized on
       // additem is actualized. This leads to the fact that the boundingrect 
       // will not close around the word items after e.g., moving them. 
       return childrenBoundingRect();
    }
    

    【讨论】:

      【解决方案2】:

      QGraphicsItemGroup 文档似乎没有提到这一点,但它只会在视图和 QGraphicsScene 显示后重新计算 boundingRectQGraphicsItemGroup

      事后添加项目

      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
          QGraphicsScene scene;
          QGraphicsView mainView(&scene);
          scene.setSceneRect(0, 0, 800, 800);
      
          QGraphicsEllipseItem* el1 = scene.addEllipse(-5, -5, 10, 10);
          scene.addLine(0, 0, 0, 10)->setParentItem(el1);
      
          QGraphicsEllipseItem* el2 = scene.addEllipse(-5, -5, 10, 10);
          scene.addLine(0, 0, 0, 10)->setParentItem(el2);
      
          QGraphicsEllipseItem* el3 = scene.addEllipse(-5, -5, 10, 10);
          scene.addLine(0, 0, 0, 10)->setParentItem(el3);
      
          QGraphicsEllipseItem* el4 = scene.addEllipse(-5, -5, 10, 10);
          scene.addLine(0, 0, 0, 10)->setParentItem(el4);
      
          QGraphicsItemGroup* group = new QGraphicsItemGroup;
          scene.addItem(group);
      
      
          QTransform translate2(1, 0, 0, 1, 10, 10);
          QTransform t2 = /*rotation(45) **/ translate2;
          el2->setTransform(t2);
      
          QTransform translate3(1, 0, 0, 1, 20, 20);
          QTransform t3 = /*rotation(-45) **/ translate3 * t2;
          el3->setTransform(t3);
      
          QTransform translate4(1, 0, 0, 1, 20, -20);
          QTransform t4 = translate4 * t3;
          el4->setTransform(t4);
      
          mainView.show();
      
          group->addToGroup(el1);
          group->addToGroup(el2);
          group->addToGroup(el3);
          group->addToGroup(el4);
          scene.addRect(group->boundingRect());
          qDebug() << group->sceneBoundingRect() << endl << group->boundingRect();
          scene.addRect(group->sceneBoundingRect());
      
          return a.exec();
      }
      

      导致组中所有成员的边界矩形

      【讨论】:

      • 有意思,这里MainView的上下文是什么?我有我的 QGraphicsViewWidget 作为 MainWindow 的孩子;使用 Qt Form .ui 文件创建。即使在调整之后,所有内容都在 MainWindow.show() 之后添加,这不是我所看到的。当 QGraphicsView 有父小部件时,行为会有所不同吗?
      • 好的,那我得做一些实验;我的猜测是当 ViewWidget 不是顶级对象时 show() 不会被调用;所以也许有些东西会以不同的方式初始化?我发现 childrenBoundingRect() 可以满足我的要求;那个遍历 GraphicsItem 的所有后代并结合它们的界限。不幸的是,当矩形改变时,它并没有被存储;所以这是每次对后代数量的线性运算。好消息是我的所有物品的后代都没有超过 10 个左右
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多