0

I'm facing a memory leak problem using QPainter on a QPixmap. I need to set about 250000 points around earth, on a map (nav points). Each of them share the same icon but have a specific label. I add all these points to the same layer.

Here is my code :

void Gspv::addFixes() // waypoints layer
{
    waypoints = new GeometryLayer("Waypoints", mapadapter);
    mc->addLayer(waypoints);

    //Icon
    QPixmap icone(38,38);
    icone.fill(Qt::transparent);
    QPainter *paint = new QPainter(&icone);
    paint->setRenderHint(QPainter::Antialiasing);
    paint->setBrush(Qt::cyan);
    paint->setPen(Qt::black);
    static const QPoint triangle[3] = {
        QPoint(15,0),
        QPoint(3, 20),
        QPoint(27,20)
    };
    paint->drawPolygon(triangle, 3);
    delete paint;

    //Check file
    QFile file(QCoreApplication::applicationDirPath() + "/data/Waypoints.txt");
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QMessageBox::information(0, "erreur lecture fichier : " + file.fileName(), file.errorString());
        return;
    }

    //Parsing file
    QTextStream in(&file);
    while(!in.atEnd()) {
        QString line = in.readLine();
        QStringList fields = line.split(",");
        QString str = fields.at(1);
        double latitude = str.toDouble();
        str = fields.at(2);
        double longitude = str.toDouble();
        str = fields.at(0);

        addCode(icone,str); // Prob here

        //Add current point to layer
        Point* pointCourant = new Point(longitude, latitude, icone, str);
        pointCourant->setBaselevel(10);
        pointCourant->setMaxsize(QSize(38, 38));
        waypoints->addGeometry(pointCourant);

    }

    file.close();
}


//Add code to QPixmap
void Gspv::addCode(QPixmap &pm, QString &code)
{
    QPainter pmp(&pm);
    pmp.setPen(Qt::black);
    pmp.setFont(QFont("ArialBold",9));
    pmp.eraseRect(0,20,38,15);
    pmp.drawText(0,32,code);
}

Everything works as expected, except that it causes severe memory leaks. Problem is when adding the code within the while loop. Whatever I do (addcode in the addfixes method or in a specific one as it is with addCode), I get a memory leak.

Even if the code is only reduced to :

void Gspv::addCode(QPixmap &pm, QString &code)
{
    QPainter pmp(&pm);
    // here it does nothing !
}

the memory leak is. And no matter whether the statement is static or dynamic, the result is the same.

Without the addition of the code, the memory usage is about 152 Mo, which is low enough. With the addition of this simple code, it bugs out of memory.

I have read many posts on the QPainter and the memory leak, but I can't handle it.

Will you have an help for that ?

Thanks in advance.

kontiki
  • 186
  • 3
  • 16
  • use QImage instead of QPixmap. – eyllanesc Oct 26 '17 at 21:45
  • See this: https://stackoverflow.com/questions/10307860/what-is-the-difference-between-qimage-and-qpixmap – eyllanesc Oct 26 '17 at 21:46
  • Are you sure the painter is the source of the leak? Are you sure creator builds and executes your most recent code? It gets stuck often... – dtech Oct 26 '17 at 23:20
  • 1
    I would try to reply with actual answer but it is covered already and not once: https://stackoverflow.com/questions/707492/how-do-i-paint-with-qpainter Your code supposed to overload `paintEvent` and request `update`. Refactor it that way, separate an object with some task for `paintEvent` to draw. – Alexander V Oct 26 '17 at 23:32
  • About leaks: only unclear `waypoints`. The rest of code is just not doing what is supposed to. – Alexander V Oct 27 '17 at 00:23
  • QPainter on Windows has had memory leaks since Qt3 as i can remember. The problem was painting outside paintEvent causing windows paint engine to produce leaks, So if you need to paint many items, in loop, often, do it in paintEvent like @AlexanderVX suggested. – Xplatforms Oct 27 '17 at 08:10
  • @eyllanesc : Unfortunately, it is not possible for me to use QImage. Constructor of Point allows only QWidget, QPixmap or a file (bmp, jpg...) as icon. – kontiki Oct 28 '17 at 07:17
  • @AlexanderVX : The while loop takes minutes to be achieved. If I put it within a paintevent, this will not be user friendly if for each paintevent the user have to wait too long. Could you please let me know the way to prevent insertion of the while loop in the paintevent. – kontiki Oct 28 '17 at 07:19
  • @kontiki What is Point? – eyllanesc Oct 28 '17 at 12:04
  • @eyllanesc . Point is an object of the [QmapControl library](https://sourceforge.net/projects/qmapcontrol/) which add a GPS point on a layer, over tiles map from google or other. This point is defined by a latitude, longitude, icon (Qpixmap, QWidget or file) and a String. The point is displayed on the map through the icon and respond to click with mouse button. The overall project is sumarized at the begining of my first post. Thanks for your help. PS : The qmapcontrol project includes an html description of all the lib. – kontiki Oct 28 '17 at 15:22
  • @kontiki You could share your project to be able to directly test my possible solution. – eyllanesc Oct 28 '17 at 15:30
  • The least I want is to argue but the way to draw for Qt with widgets is via paint event. It is up to programmer how the data staged before dispatched for actual draw. – Alexander V Oct 29 '17 at 01:03
  • @eyllanesc : no problem. You can find the project here : https://wetransfer.com/downloads/c5be857c0e4beb74658b0dd9a7994c0820171030090311/a70306 – kontiki Oct 30 '17 at 09:30
  • @AlexanderVX : I understand what you mean. The 40000 chip example given by qt is a possible way to achieve what I need. – kontiki Oct 30 '17 at 09:34

1 Answers1

0

@AlexanderVX Based on your comment I changed my code. Here is the new structure.

The addFixes method from this :

void Gspv::addFixes() // waypoints layer
{

...
    addCode(icone,str); // Prob here
...
}

become this :

void Gspv::addFixes() // waypoints layer
{
...
    //Add code within icon
    paint = new QPainter(&icone);
    QGraphicsItem *item = new GenIcone("wayPoint", str, paint);
    delete paint;
...
}

AddCode method has been replaced by a brand new class, GenIcon.

.h

#ifndef GENICONE_H
#define GENICONE_H

//#include <QPixmap>
#include <QGraphicsItem>
#include <QPainter>

class GenIcone : public QGraphicsItem
{
public:
    GenIcone(const QString icone, QString code, QPainter *painter);
    QRectF boundingRect() const Q_DECL_OVERRIDE;
    QPainterPath shape() const Q_DECL_OVERRIDE;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget) Q_DECL_OVERRIDE;

    QPainter m_painter;

private :
    QString m_icone;
    QString m_code;
};

#endif // GENICONE_H

.cpp

#include "genicone.h"
#include <QtWidgets>
#include <QWidget>
#include <QStyleOptionGraphicsItem>

GenIcone::GenIcone(const QString icone, QString code, QPainter *painter)
{
    this->m_icone = icone;
    this->m_code = code;

    setAcceptHoverEvents(true);
    QStyleOptionGraphicsItem opt;
    QWidget w;

    paint(painter,&opt,&w);
}


void GenIcone::paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget)
{
    Q_UNUSED(widget);
    Q_UNUSED(item);

    //Draw code within icon

    if (m_icone== "wayPoint") {
        painter->setFont(QFont("ArialBold",10));
        painter->eraseRect(0,20,50,18);
        painter->drawText(1,32,m_code);
        painter->end();
    }
}

QRectF GenIcone::boundingRect() const 
{
    ...
}

QPainterPath GenIcone::shape() const
{
    ...
}

So, it works, but I still get the memory leak despite being overloaded paint. What can I do to improve my code ?

Thanks for help

kontiki
  • 186
  • 3
  • 16