Нужно добавить проверку существует ли уже один объект класса и в таком случае удалить его из памяти и создать новый
Суть в том что я по нажатию на кнопку вызываю слот "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 шт):
В первую очередь рекомендую именовать наследников 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, изменять параметры расчета константы, рисовать поле графика (оси) отдельно от виджета (в отдельном классе), добавить возможность добавления (удаления) нескольких графиков одновременно и так далее