Search code examples
c++qtqgraphicsviewqgraphicsitemqlist

How to delete listed "QGraphicsPathItem" object to control process memory usage?


I want to draw some paths in QGraphicsView. I want to manage drown paths. So in path_ploter(double) method, I draw a path and pass the pointer of object to PathItemList.

I redraw the paths in plot_fn() slot. I connect this slot to a push button. when I push the plot button, despite deleting all path item pointers in list before redraw paths, process memory usage increases. If I delete the pointer in list as soon as in created, such as //delete PathItemList.back(); in path_ploter(double) method, the process usage memory doesn't increase. In this case paths are not displayed. why does memory usage increase when I delete the pointer in plot slot ? how can I control it?

in header file:

#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_QtGuiApplication1.h"
#include <QGraphicsView>
#include <QGraphicsPathItem>
#include <QGraphicsLineItem>
#include <QtWidgets/QPushButton>

class QtGuiApplication1 : public QMainWindow
{
    Q_OBJECT

public:
    QtGuiApplication1(QWidget *parent = Q_NULLPTR);

private:
    Ui::QtGuiApplication1Class ui;
    QGraphicsView* qGraph;
    QGraphicsScene* scene;
    QGraphicsPathItem* pathItem = new QGraphicsPathItem();
    QList<QGraphicsPathItem *>PathItemList;
    void path_ploter(double);
private slots:
    void plot_fn();
};

in source file:

#include "QtGuiApplication1.h"

QtGuiApplication1::QtGuiApplication1(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    //////////////
    qGraph = new QGraphicsView(ui.centralWidget);
    qGraph->setGeometry(QRect(0, 0, 300, 300));
    scene = new QGraphicsScene(qGraph);
    scene->setSceneRect(0, 0, 300, 300);
    qGraph->setScene(scene);    
    qGraph->show();
    ////////////
    QPushButton* btn_Ok = new QPushButton(ui.centralWidget);
    btn_Ok->setObjectName(QStringLiteral("btn_Ok"));
    btn_Ok->setGeometry(QRect(300, 300, 75, 23));
    btn_Ok->setText("Plot");
    connect(btn_Ok, SIGNAL(clicked()), this, SLOT(plot_fn()));
    //plot_fn();
    //path_ploter(1);
}

void QtGuiApplication1::path_ploter(double alpha)
{
    QPainterPath* myPath = new QPainterPath();
    QPolygon pol;

    QPen graphPen;
    graphPen.setColor(QColor(255, 0, 0, 255));
    graphPen.setWidth(2);


    QPoint pos;

    for (size_t i = 0; i < 100; i++)
    {

        pos.setX(i);
        pos.setY(i*alpha);
        pol.append(pos);
    }

    myPath->addPolygon(pol);
    pol.clear();


    pathItem = scene->addPath(*myPath, graphPen);
    PathItemList << pathItem;
    //delete PathItemList.back();
    pathItem = new QGraphicsPathItem();

}

void QtGuiApplication1::plot_fn()
{

    for (size_t i = 0; i < PathItemList.size(); i++)
    {
        scene->removeItem(PathItemList.at(i));
    }
    qDeleteAll(PathItemList.begin(), PathItemList.end());
    PathItemList.clear();

    for (size_t i = 0; i < 3; i++)
    {
        path_ploter(i+1);

    }

}

Solution

  • Your code has several errors:

    • Why do you create a QPainterPath pointer? It is not necessary to have that information permanently since addPath() takes a copy of that value.

    • Why do you add 2 items with the same myPath ?, just one is enough and store it in the list.

    • Why do you create 2 pathItem? create a pathItem with addPath() and another with new QGraphicsPathItem, the second is not necessary.

    • Why do you use scene->addItem(PathItemList.back()); in the for-loop ?, it does not make sense.

    Remember that when you create a pointer your task is to make sure that the memory will be eliminated before the application is closed.

    Considering the above, the code should be the following:

    void QtGuiApplication1::path_ploter(double alpha)
    {
        QPainterPath myPath;
        QPolygonF pol;
        QPen graphPen;
        graphPen.setColor(QColor(255, 0, 0, 255));
        graphPen.setWidth(2);
        for (size_t i = 0; i < 100; i++){
            pol.append(QPointF(i, i*alpha));
        }
    
        myPath.addPolygon(pol);
        QGraphicsPathItem *pathItem = scene->addPath(myPath, graphPen);
        PathItemList << pathItem;
    }
    
    void QtGuiApplication1::plot_fn()
    {
        // Remove the item from the scene
        for(QGraphicsPathItem * pathItem: PathItemList){
            scene->removeItem(pathItem);
        }
        // Delete the memory pointed by the pointers
        qDeleteAll(PathItemList.begin(), PathItemList.end());
        // Clean the container
        PathItemList.clear();
        for (size_t i = 0; i < 3; i++)
        {
            path_ploter(i+1);
        }
    }
    

    Finally, it is recommended that you use the new connection syntax:

    connect(btn_Ok, &QAbstractButton::clicked, this, &QtGuiApplication1::plot_fn);