正确删除QGraphicsScene

时间:2018-03-13 09:37:14

标签: qt

我创建了一个小型原型,其中包含QGraphicsView我绑定到GraphicsScene的{​​{1}}我可以添加或删除QGraphicsTextItem。这是执行作业的cpp文件

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

#include <QGraphicsScene>
#include <QGraphicsTextItem>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QGraphicsScene* scene = new QGraphicsScene();
    ui->graphicsView->setScene(scene);
    connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(addGraphicsItem()));
    connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(removeGraphicsItem()));
}

MainWindow::~MainWindow()
{
    auto scene = ui->graphicsView->scene();
    ui->graphicsView->setScene(nullptr);
    delete scene;
    delete ui;
}

void MainWindow::addGraphicsItem()
{
    QGraphicsTextItem* item = new QGraphicsTextItem("jgfkdljkdj");
    _items.push_back(item);
    ui->graphicsView->scene()->addItem(_items.back());
}

void MainWindow::removeGraphicsItem()
{
    auto item = _items.back();
    ui->graphicsView->scene()->removeItem(item);
    _items.erase(_items.end()-1);
    delete item;
}

我无法理解在创建/删除场景和/或其基础项目时如何安全地管理我的记忆。阅读很多关于此问题的帖子,例如this one,我找到了一个代码,但我觉得它过于苛刻,而Qt可能会在没有它的情况下完成工作。当删除和删除场景中的一个项目时,这是否真的是在MainWindow::removeGraphicsItem槽中实现的方式?删除场景时是MainWindow::~MainWindow析构函数?

1 个答案:

答案 0 :(得分:3)

最简单的方法是让语言和框架为你管理内存。

按值存储QGraphicsScene,并利用场景是资源管理器的事实,与项目紧密耦合。它管理物品的使用寿命,并保证任何物品都不会超过现场,即它会处理在破坏者运行之前没有处理过的任何物品。

要从场景或父项中删除项目,只需将其删除即可。该项目将通知场景和任何父母即将消失,并且场景将从其项目列表中删除它。那就是QObject内存管理的工作方式。

您可能还希望使用QGraphicsScene::itemsQGraphicsItemGroup::childItems,而不是手动管理对象列表。使用手动列表需要注意将列表的内容与对象生存期同步。场景或项目组会自动执行此操作。

如果要写它,我会按如下方式进行。我还展示了如何在场景中混合不同的项目生命周期,以及如何按值保存项目。

// mainwindow.h
#pragma once
#include "ui_mainwindow.h"
#include <QGraphicsScene>

class MainWindow : public QMainWindow {
  Q_OBJECT
  Ui::MainWindow ui;
  QGraphicsScene m_scene;
  QGraphicsTextItem m_text{tr("foo")};
  QGraphicsItemGroup m_dynamicItems;
  template <typename T, typename ...Ar> T* newItem(Ar&&... args);
public:
  MainWindow(QWidget *parent = {});
  Q_SLOT void addItem();
  Q_SLOT void removeItem();
  Q_SLOT void removeAllItems();
};

// mainwindow.cpp
#include "mainwindow.h"
#include <utility>

template <typename T, typename ...Ar> 
T* MainWindow::newItem(Ar&&... args) {
  return new T{&this->m_dynamicItems, std::forward<Ar>(args)...};
}

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent) 
{
  ui.setupUi(this);
  ui.graphicsView->setScene(&m_scene);
  m_scene.addItem(&m_text);
  m_scene.addItem(&m_dynamicItems);
  auto const clicked = &QPushButton::clicked;
  connect(ui.pushButton, clicked, this, &MainWindow::addItem);
  connect(ui.pushButton2, clicked, this, &MainWindow::removeItem);
}

void MainWindow::addItem() {
  newItem<QGraphicsTextItem>(tr("jfslkdfjd"));
}

void MainWindow::removeItem() {
  auto const &items = std::as_const(m_dynamicItems.childItems());
  if (!items.isEmpty())
    delete items.back();
}

void MainWindow::removeAllItems() {
  for (auto *item : std::as_const(m_dynamicItems.childItems()))
    delete item;
  // or (deprecated but you may run into such code)
  qDeleteAll(std::as_const(m_dynamicItems.childItems()));
}