Нужно добавить проверку существует ли уже один объект класса и в таком случае удалить его из памяти и создать новый

Суть в том что я по нажатию на кнопку вызываю слот "drawChart" который отрисовывает график, для этого я каждый раз когда я нажимаю кнопку я создаю новый объект класса "Chart".

Так вот проблема в том что я могу так до бесконечности создавать такие объекты, а мне нужно удалять старый график и рисовать новый когда пользователь нажал на кнопку второй/третий/и т.д. раз.

void MainWindow::drawChart(){
    chart = new Chart(line_x0->text().toFloat(), line_yx0->text().toFloat(), this);
    layoutChart->addWidget(chart);
    layoutMain->addLayout(layoutChart);
}

Класс Chart:

#include "chart.h"
#include "mainwindow.h"

Chart::Chart(long long x0, long long yx0, QWidget *parent) : QWidget(parent), x0(x0), yx0(yx0)
{
    y = 0;
    C = qExp(2*x0)*(2000-(qExp(2*x0)/4)+yx0);
    scale = 20; // масштаб клеток/отрезков
    scaleXY = 1; //масштаб графика

    setMouseTracking(true);

}

void Chart::paintEvent(QPaintEvent*){
    painter.begin(this);
    if(scaleXY <1) scaleXY = 1; // задаем минимальную границу масштаба
    painter.scale(scaleXY, scaleXY); 

    painter.setRenderHints(QPainter::Antialiasing, true);
    painter.setBackgroundMode(Qt::OpaqueMode);
    painter.setBackground(Qt::white);

    pen.setColor(Qt::gray);
    pen.setWidth(1);
    painter.setPen(pen);

    for(int i = 0; i < width(); i+=scale){
        painter.drawLine(i, 0, i, height()); //клетки
        painter.drawLine(0, i, width(), i);
    }

    pen.setColor(QColor(220, 20, 60));
    pen.setWidth(3);
    painter.setPen(pen);

    painter.drawLine((width()/2), 0,(width()/2), height()); // ось Y

    QPolygon arrowY;
    arrowY << QPoint(width()/2, 0) << QPoint((width()/2)-20, 20); //левая часть стрелки
    arrowY << QPoint(width()/2, 0) << QPoint((width()/2)+20, 20); //правая часть стрелки
    painter.drawPolygon(arrowY);

    painter.drawLine(0, (height()/2), width(), (height()/2)); // ось X

    QPolygon arrowX;
    arrowX << QPoint(width(), height()/2) << QPoint((width())-20, (height()/2)-20); //верхняя часть стрелки
    arrowX << QPoint(width(), height()/2) << QPoint((width())-20,(height()/2)+20); //нижняя часть стрелки
    painter.drawPolygon(arrowX);

    for(int i = 0; i < width(); i+=scale){
        painter.drawLine(i, (height()/2)-5, i, (height()/2)+5); // отрезки слева направо
    }

    for(int i = 0; i < height(); i+=scale){
        painter.drawLine((width()/2)-5, i, (width()/2)+5, i); // отрезки сверху вниз
    }

    pen.setColor(QColor(0, 128, 128));
    pen.setWidth(4);
    painter.setPen(pen);

   for(float x = -100; x <= 100; x+=0.001){
        y = ((qExp(2*x)/4) + (C/qExp(2*x)) - 2000)/1000; 
        painter.drawPoint(QPoint(((width()/2)+x), ((height()/2)-y)));
    }
    painter.end();
}

void Chart::wheelEvent(QWheelEvent* e){
    if(e->angleDelta().y() > 0){
        scale+= 1;
        scaleXY+=0.1;
        update();
    }
    else if(e->angleDelta().y() < 0){
        scale-= 1;
        scaleXY-=0.1;
        update();
    }
}

void Chart::mouseMoveEvent(QMouseEvent *e){
    bool leftClick = e->buttons() & Qt::LeftButton;
    if(leftClick){
        mousePoint = e->pos();
        update();
    }
}

Ответы (1 шт):

Автор решения: Alexander Chernin

В первую очередь рекомендую именовать наследников QWidget с постфиксом Widget, тогда наш виджет, отвечающий за отрисовку графика, станет ChartWidget.

И так, для начала, давайте заведем отдельный базовый класс для всех чартов (графиков):

class Chart {
public:
    virtual ~Chart() {}
    virtual qreal fun(qreal x) =0;
};

Теперь наследуем Chart, чтобы реализовать нашу функцию:

class ExpChart: public Chart {
    explicit ExpChart(): _C(0) {
    }
    // Конструктор для расчета константы
    ExpChart(qreal x0, qreal y0) {
        _C = C(x0, y0);
    }
    virtual ~ExpChart() {
    }

    qreal fun(qreal x) override {
        return ((qExp(2*x)/4) + (_C/qExp(2*x)) - 2000)/1000;
    }
    // Расчет константы производится
    qreal C(qreal x0, qreal y0) {
        return qExp(2*x0)*(2000-(qExp(2*x0)/4)+y0);
    }
private:
    qreal _C;
}

Теперь создадим сам виджет отрисовки графиков:

// Заголовник
class ChartWidget : public QWidget
{
    Q_OBJECT
public:
    explicit ChartWidget(QWidget *parent = nullptr);
    // Здесь мы передаем на отрисовку наш новый график
    // Можно установить один график, но если немного подшаманить,
    // то совершенно несложно сделать отображение множества графиков одновременно
    // на одном виджете (если вам это надо, то пусть это станет вашим домашним заданием)
    void setChart(Chart *chart);

    void paintEvent(QPaintEvent *);
    void wheelEvent(QWheelEvent *e);
    void mouseMoveEvent(QMouseEvent *e);
signals:
private:
    qreal scaleXY;
    int scale;
    QPoint mousePoint;

    // "Умный" указатель на данные для графиков
    QScopedPointer<Chart> chart;
};

cpp

ChartWidget::ChartWidget(QWidget *parent) : QWidget(parent)
{
    scale = 20; // масштаб клеток/отрезков
    scaleXY = 1; //масштаб графика
    setMouseTracking(true);
}

void ChartWidget::setChart(Chart* chart)
{
    // Удаляем старые данные и устанавливаем новые
    this->chart.reset(chart);
    // Вызываем перерисовку виджета
    update();
}

void ChartWidget::paintEvent(QPaintEvent*){

    QPainter painter;

    painter.begin(this);
    if(scaleXY <1) scaleXY = 1; // задаем минимальную границу масштаба
    painter.scale(scaleXY, scaleXY);

    painter.setRenderHints(QPainter::Antialiasing, true);
    painter.setBackgroundMode(Qt::OpaqueMode);
    painter.setBackground(Qt::white);

    QPen pen;
    pen.setColor(Qt::gray);
    pen.setWidth(1);
    painter.setPen(pen);

    for(int i = 0; i < width(); i+= scale){
        painter.drawLine(i, 0, i, height()); //клетки
        painter.drawLine(0, i, width(), i);
    }

    pen.setColor(QColor(220, 20, 60));
    pen.setWidth(3);
    painter.setPen(pen);

    painter.drawLine((width()/2), 0,(width()/2), height()); // ось Y

    QPolygon arrowY;
    arrowY << QPoint(width()/2, 0) << QPoint((width()/2)-20, 20); //левая часть стрелки
    arrowY << QPoint(width()/2, 0) << QPoint((width()/2)+20, 20); //правая часть стрелки
    painter.drawPolygon(arrowY);

    painter.drawLine(0, (height()/2), width(), (height()/2)); // ось X

    QPolygon arrowX;
    arrowX << QPoint(width(), height()/2) << QPoint((width())-20, (height()/2)-20); //верхняя часть стрелки
    arrowX << QPoint(width(), height()/2) << QPoint((width())-20,(height()/2)+20); //нижняя часть стрелки
    painter.drawPolygon(arrowX);

    for(int i = 0; i < width(); i += scale){
        painter.drawLine(i, (height()/2)-5, i, (height()/2)+5); // отрезки слева направо
    }

    for(int i = 0; i < height(); i += scale){
        painter.drawLine((width()/2)-5, i, (width()/2)+5, i); // отрезки сверху вниз
    }

    pen.setColor(QColor(0, 128, 128));
    pen.setWidth(4);
    painter.setPen(pen);

    // Если данных нет, то выходим
    if (chart.isNull()) {
        painter.end();
        return;
    }

    qreal y = 0;
    for(float x = -100; x <= 100; x+=0.001) {
        // Вызываем функцию расчета следующего значения
        y = chart->fun(x);
        painter.drawPoint(QPoint(((width()/2)+x), ((height()/2)-y)));
    }
    painter.end();
}

void ChartWidget::wheelEvent(QWheelEvent* e){
    // --//--
}

void ChartWidget::mouseMoveEvent(QMouseEvent *e){
    // --//--
}

И наконец главное окно приложения.

В заголовке просто объявим указатель на виджет для графиков, кроме того, в режиме редактирования я добавил кнопку, нажав накоторую мы передадим в виджет графика, соответствующие данные (ExpChart) кнопку :

class ChartWidget;
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private:
    Ui::MainWindow *ui;

    ChartWidget* chart;
};

cpp:

#include "MainWindow.h"
#include "ui_MainWindow.h"

#include <QVBoxLayout>
#include "ChartWidget.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow),
      chart(new ChartWidget())
{
    ui->setupUi(this);
    ui->frame->setLayout(new QVBoxLayout());
    // Добавляем виджет в окно (один раз)
    ui->frame->layout()->addWidget(chart = new ChartWidget());

    // При нажатии на кнопку в чарт добавляется соответсвующая 
    // функция для отрисовки
    connect(ui->toolButton, &QToolButton::clicked, [&]() {
        chart->setChart(new ExpChart() /*или ExpChart(с параметрами)*/);
    });
}

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

Мы отделили сам виджет от данных, которые он должен отображать.

Здесь еще многое можно улучшить. Например, задавать интервалы расчета в том же классе Chart, изменять параметры расчета константы, рисовать поле графика (оси) отдельно от виджета (в отдельном классе), добавить возможность добавления (удаления) нескольких графиков одновременно и так далее

→ Ссылка