Overriding QCustomPlot library method with your own method
-
wrote on 4 Apr 2024, 05:42 last edited by
I am working with QCustomPlot on the QT to write my application. This question is related to QCustomPlot but more related to C++ in general hence I have decided to ask here.
QCustomPlot source files can be found here:
https://www.qcustomplot.com/index.php/downloadI want to slightly change the funcionality of the QCustomPlot by overriding some methods (
mousePressEvent
andmouseMoveEvent
) to achieve simillar funcionality as described here: https://www.qcustomplot.com/index.php/support/forum/1887So I have tried to create a custom class named
QMyPlot
and made it a subclass ofQCPAxisRect
.See my
QMyPlot.h
:#ifndef QMYPLOT_H #define QMYPLOT_H #include "qcustomplot.h" class QMyPlot : public QCPAxisRect { public: QMyPlot(); }; #endif // QMYPLOT_H
and
QMyPlot.cpp
:#include "qmyplot.h" QMyPlot::QMyPlot() { }
I am getting an error:
C:\Users\my_user\Desktop\WORK\QT\uCurrent\uCurrent\qmyplot.cpp:3: error: Constructor for 'QMyPlot' must explicitly initialize the base class 'QCPAxisRect' which does not have a default constructor
Which is not fully clear to me. I am hoping to get some clarifications on how to prevent this error and how to properly override the methods that are defined in QCustomPlot.cpp
-
I am working with QCustomPlot on the QT to write my application. This question is related to QCustomPlot but more related to C++ in general hence I have decided to ask here.
QCustomPlot source files can be found here:
https://www.qcustomplot.com/index.php/downloadI want to slightly change the funcionality of the QCustomPlot by overriding some methods (
mousePressEvent
andmouseMoveEvent
) to achieve simillar funcionality as described here: https://www.qcustomplot.com/index.php/support/forum/1887So I have tried to create a custom class named
QMyPlot
and made it a subclass ofQCPAxisRect
.See my
QMyPlot.h
:#ifndef QMYPLOT_H #define QMYPLOT_H #include "qcustomplot.h" class QMyPlot : public QCPAxisRect { public: QMyPlot(); }; #endif // QMYPLOT_H
and
QMyPlot.cpp
:#include "qmyplot.h" QMyPlot::QMyPlot() { }
I am getting an error:
C:\Users\my_user\Desktop\WORK\QT\uCurrent\uCurrent\qmyplot.cpp:3: error: Constructor for 'QMyPlot' must explicitly initialize the base class 'QCPAxisRect' which does not have a default constructor
Which is not fully clear to me. I am hoping to get some clarifications on how to prevent this error and how to properly override the methods that are defined in QCustomPlot.cpp
@lukutis222 Your constructor must call a constructor of the base class:
QMyPlot::QMyPlot() : QCPAxisRect(...) { }
Since there is no QCPAxisRect default constructor (as the error says) you have to call one of the others.
-
@lukutis222 Your constructor must call a constructor of the base class:
QMyPlot::QMyPlot() : QCPAxisRect(...) { }
Since there is no QCPAxisRect default constructor (as the error says) you have to call one of the others.
wrote on 4 Apr 2024, 06:33 last edited by lukutis222 4 Apr 2024, 06:33@jsulm
Thanks. I have managed to get it to work using the following code:QMyPlot.h
:#ifndef QMYPLOT_H #define QMYPLOT_H #include "qcustomplot.h" class QMyPlot : public QCPAxisRect { public: QMyPlot(QCustomPlot *parentPlot); private slots: void mousePressEvent(QMouseEvent *event, const QVariant &details); }; #endif // QMYPLOT_H
and my
QMyPlot.cpp
:#include "qmyplot.h" QMyPlot::QMyPlot(QCustomPlot *parentPlot):QCPAxisRect(parentPlot,true) { } void QMyPlot::mousePressEvent(QMouseEvent *event, const QVariant &details) { qDebug("Mouse press custom event"); }
In my MainWindow.cpp I can now create a constructor of my custom
QMyPlot
class:QMyPlot test(ui->customPlot);
I am now trying to figure out how to get this mousePressEvent to actually work and override the existing QCPAxisRect mousePressEvent. The original method in the
QCustomPlot.cpp
is declared as following:void QCPAxisRect::mousePressEvent(QMouseEvent *event, const QVariant &details) { Q_UNUSED(details) if (event->buttons() & Qt::LeftButton) { mDragging = true; // initialize antialiasing backup in case we start dragging: if (mParentPlot->noAntialiasingOnDrag()) { mAADragBackup = mParentPlot->antialiasedElements(); mNotAADragBackup = mParentPlot->notAntialiasedElements(); } // Mouse range dragging interaction: if (mParentPlot->interactions().testFlag(QCP::iRangeDrag)) { mDragStartHorzRange.clear(); foreach (QPointer<QCPAxis> axis, mRangeDragHorzAxis) mDragStartHorzRange.append(axis.isNull() ? QCPRange() : axis->range()); mDragStartVertRange.clear(); foreach (QPointer<QCPAxis> axis, mRangeDragVertAxis) mDragStartVertRange.append(axis.isNull() ? QCPRange() : axis->range()); } } }
-
@jsulm
Thanks. I have managed to get it to work using the following code:QMyPlot.h
:#ifndef QMYPLOT_H #define QMYPLOT_H #include "qcustomplot.h" class QMyPlot : public QCPAxisRect { public: QMyPlot(QCustomPlot *parentPlot); private slots: void mousePressEvent(QMouseEvent *event, const QVariant &details); }; #endif // QMYPLOT_H
and my
QMyPlot.cpp
:#include "qmyplot.h" QMyPlot::QMyPlot(QCustomPlot *parentPlot):QCPAxisRect(parentPlot,true) { } void QMyPlot::mousePressEvent(QMouseEvent *event, const QVariant &details) { qDebug("Mouse press custom event"); }
In my MainWindow.cpp I can now create a constructor of my custom
QMyPlot
class:QMyPlot test(ui->customPlot);
I am now trying to figure out how to get this mousePressEvent to actually work and override the existing QCPAxisRect mousePressEvent. The original method in the
QCustomPlot.cpp
is declared as following:void QCPAxisRect::mousePressEvent(QMouseEvent *event, const QVariant &details) { Q_UNUSED(details) if (event->buttons() & Qt::LeftButton) { mDragging = true; // initialize antialiasing backup in case we start dragging: if (mParentPlot->noAntialiasingOnDrag()) { mAADragBackup = mParentPlot->antialiasedElements(); mNotAADragBackup = mParentPlot->notAntialiasedElements(); } // Mouse range dragging interaction: if (mParentPlot->interactions().testFlag(QCP::iRangeDrag)) { mDragStartHorzRange.clear(); foreach (QPointer<QCPAxis> axis, mRangeDragHorzAxis) mDragStartHorzRange.append(axis.isNull() ? QCPRange() : axis->range()); mDragStartVertRange.clear(); foreach (QPointer<QCPAxis> axis, mRangeDragVertAxis) mDragStartVertRange.append(axis.isNull() ? QCPRange() : axis->range()); } } }
@lukutis222 said in Overriding QCustomPlot library method with your own method:
I am now trying to figure out how to get this mousePressEvent to actually work and override the existing QCPAxisRect mousePressEvent
You need to override mousePressEvent in your class. See https://doc.qt.io/qt-6/eventsandfilters.html
-
@lukutis222 said in Overriding QCustomPlot library method with your own method:
I am now trying to figure out how to get this mousePressEvent to actually work and override the existing QCPAxisRect mousePressEvent
You need to override mousePressEvent in your class. See https://doc.qt.io/qt-6/eventsandfilters.html
wrote on 4 Apr 2024, 08:03 last edited by lukutis222 4 Apr 2024, 08:05@jsulm
Thanks for suggesting that. I have read it and I have an idea how to implement this.For example, the original mousePressEvent for the
QCPAxisRect
only handles the logic when the left mouse button is pressed. I have extended the funcionality of that by adding a debug print message when the right mouse button is pressed. When the left mouse button is pressed, I call the origin method.void QMyPlot::mousePressEvent(QMouseEvent *event, const QVariant &details) { if (event->button() == Qt::RightButton) { qDebug("Right mouse Press Event\n"); } else { qDebug("Left mouse Press Event\n"); QCPAxisRect::mousePressEvent(event,details); } }
But I still do not get how to actually get this method to work? What do I need to do in my
MainWindow.cpp
after creating a class object to ensure that when I press right button it actually triggers this -
@jsulm
Thanks for suggesting that. I have read it and I have an idea how to implement this.For example, the original mousePressEvent for the
QCPAxisRect
only handles the logic when the left mouse button is pressed. I have extended the funcionality of that by adding a debug print message when the right mouse button is pressed. When the left mouse button is pressed, I call the origin method.void QMyPlot::mousePressEvent(QMouseEvent *event, const QVariant &details) { if (event->button() == Qt::RightButton) { qDebug("Right mouse Press Event\n"); } else { qDebug("Left mouse Press Event\n"); QCPAxisRect::mousePressEvent(event,details); } }
But I still do not get how to actually get this method to work? What do I need to do in my
MainWindow.cpp
after creating a class object to ensure that when I press right button it actually triggers this@lukutis222 said in Overriding QCustomPlot library method with your own method:
What do I need to do in my MainWindow.cpp after creating a class object to ensure that when I press right button it actually triggers this
Now you're talking about MainWindow - but you're overriding the event in QMyPlot. So where do you want to handle mouse press event?
-
@lukutis222 said in Overriding QCustomPlot library method with your own method:
What do I need to do in my MainWindow.cpp after creating a class object to ensure that when I press right button it actually triggers this
Now you're talking about MainWindow - but you're overriding the event in QMyPlot. So where do you want to handle mouse press event?
wrote on 4 Apr 2024, 08:20 last edited by lukutis222 4 Apr 2024, 08:22I do not fully understand what do you mean. I simply want to override the existing library method:
void QCPAxisRect::mousePressEvent(QMouseEvent *event, const QVariant &details)
For that I have created a new class which is a subclass of
QCPAxisRect
and overridden the mousePressEvent method. Whats next? As you can see from my overridden method:void QMyPlot::mousePressEvent(QMouseEvent *event, const QVariant &details) { if (event->button() == Qt::RightButton) { qDebug("Right mouse Press Event\n"); } else { qDebug("Left mouse Press Event\n"); QCPAxisRect::mousePressEvent(event,details); } }
When the right mouse button is pressed, it is supposed to print debug message "Right mouse Press Event". I can launch the application and click the right mouse button but it will not print the debug message it so I assume I am missing something to actually trigger this.
In my MainWindow.cpp I create signals:
connect(ui->customPlot, &QCustomPlot::mouseMove, this, &MainWindow::showPointToolTip); connect(ui->customPlot, &QCustomPlot::mouseDoubleClick, this, &MainWindow::SavePoint); connect(ui->customPlot, &QCustomPlot::selectionChangedByUser, this, &MainWindow::Calculate_average_selected); connect(ui->customPlot, &QCustomPlot::mousePress, this, &MainWindow::ChangeScrollMode);
Perhaps I need to replace this with my new class ?
-
I do not fully understand what do you mean. I simply want to override the existing library method:
void QCPAxisRect::mousePressEvent(QMouseEvent *event, const QVariant &details)
For that I have created a new class which is a subclass of
QCPAxisRect
and overridden the mousePressEvent method. Whats next? As you can see from my overridden method:void QMyPlot::mousePressEvent(QMouseEvent *event, const QVariant &details) { if (event->button() == Qt::RightButton) { qDebug("Right mouse Press Event\n"); } else { qDebug("Left mouse Press Event\n"); QCPAxisRect::mousePressEvent(event,details); } }
When the right mouse button is pressed, it is supposed to print debug message "Right mouse Press Event". I can launch the application and click the right mouse button but it will not print the debug message it so I assume I am missing something to actually trigger this.
In my MainWindow.cpp I create signals:
connect(ui->customPlot, &QCustomPlot::mouseMove, this, &MainWindow::showPointToolTip); connect(ui->customPlot, &QCustomPlot::mouseDoubleClick, this, &MainWindow::SavePoint); connect(ui->customPlot, &QCustomPlot::selectionChangedByUser, this, &MainWindow::Calculate_average_selected); connect(ui->customPlot, &QCustomPlot::mousePress, this, &MainWindow::ChangeScrollMode);
Perhaps I need to replace this with my new class ?
@lukutis222 said in Overriding QCustomPlot library method with your own method:
I can launch the application and click the right mouse button but it will not print the debug message it so I assume I am missing something to actually trigger this
Where in the application do you press the mouse? Since you're overriding mousePressEvent in QMyPlot you need to press mouse when the cursor is over QMyPlot.
Also this is completely wrong (please read again the link I gave you):
private slots: void mousePressEvent(QMouseEvent *event, const QVariant &details);
mousePressEvent is NOT a slot!
And as a tip: add override keyword if you're overriding an inherited method:void mousePressEvent(QMouseEvent *event, const QVariant &details) override;
In this case compiler will tell you that you're not overriding properly if you do something wrong.
-
@lukutis222 said in Overriding QCustomPlot library method with your own method:
I can launch the application and click the right mouse button but it will not print the debug message it so I assume I am missing something to actually trigger this
Where in the application do you press the mouse? Since you're overriding mousePressEvent in QMyPlot you need to press mouse when the cursor is over QMyPlot.
Also this is completely wrong (please read again the link I gave you):
private slots: void mousePressEvent(QMouseEvent *event, const QVariant &details);
mousePressEvent is NOT a slot!
And as a tip: add override keyword if you're overriding an inherited method:void mousePressEvent(QMouseEvent *event, const QVariant &details) override;
In this case compiler will tell you that you're not overriding properly if you do something wrong.
wrote on 4 Apr 2024, 08:51 last edited by lukutis222 4 Apr 2024, 08:52@jsulm
Thanks for the tip. I have fixed my declaration as you have suggested and added override keyword.I am slowly starting to grasp how my QMyPlot supposed to work. See my MainWindow.cpp:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { sample_counter = 0; sample_counter_1_sec = 0; ui->setupUi(this); setup_graph(ui->customPlot); connect(ui->customPlot, &QCustomPlot::mouseMove, this, &MainWindow::showPointToolTip); connect(ui->customPlot, &QCustomPlot::mouseDoubleClick, this, &MainWindow::SavePoint); connect(ui->customPlot, &QCustomPlot::selectionChangedByUser, this, &MainWindow::Calculate_average_selected); connect(ui->customPlot, &QCustomPlot::mousePress, this, &MainWindow::ChangeScrollMode); } void MainWindow::setup_graph(QCustomPlot *customPlot) { current_upper_limit = 10; current_lower_limit = 0; voltage_upper_limit = 5; voltage_lower_limit = 0; QColor accentColor = QColor(Qt::red); QColor themeColor = QColor(Qt::white); QColor themeBackgroundColor = QColor(53, 57, 53); QColor traceColor = accentColor; QMyPlot test(customPlot); foreach (QCPAxisRect *rect, customPlot->axisRects()) { foreach (QCPAxis *axis, rect->axes()) { axis->setLabelColor(themeColor); axis->setBasePen(QPen(themeColor, 1)); axis->setTickPen(QPen(themeColor, 1)); axis->setSubTickPen(QPen(themeColor, 1)); axis->setTickLabelColor(themeColor); axis->grid()->setPen(QPen(themeColor, 0.5, Qt::DotLine)); axis->grid()->setSubGridVisible(false); axis->setSelectedTickLabelColor(accentColor); axis->setSelectedLabelColor(accentColor); axis->setSelectedBasePen(QPen(accentColor, 1)); axis->setSelectedSubTickPen(QPen(accentColor, 1)); axis->setSelectedTickPen(QPen(accentColor, 1)); } } ui->customPlot->setBackground(QBrush(themeBackgroundColor)); // SETUP GRAPH 0 for Current customPlot->addGraph(); customPlot->graph(0)->setScatterStyle(QCPScatterStyle::ssCircle); customPlot->graph(0)->setLineStyle(QCPGraph::lsLine); QPen pen_current; pen_current.setWidth(2); pen_current.setColor(QColor(80, 200, 120)); customPlot->graph(0)->setPen(pen_current); // SETUP GRAPH 1 for Voltage // customPlot->addGraph(); customPlot->addGraph(customPlot->xAxis, customPlot->yAxis2); customPlot->graph(1)->setScatterStyle(QCPScatterStyle::ssCross); customPlot->graph(1)->setLineStyle(QCPGraph::lsLine); QPen pen_voltage; pen_voltage.setWidth(2); pen_voltage.setColor(QColor(225,225,50)); customPlot->graph(1)->setPen(pen_voltage); // SETUP GRAPH 2 for cursors customPlot->addGraph(customPlot->xAxis, customPlot->yAxis); customPlot->graph(2)->setLineStyle((QCPGraph::LineStyle)QCPGraph::lsNone); customPlot->graph(2)->setScatterStyle(QCPScatterStyle::ssTriangle); QPen pen_cursor; pen_cursor.setWidth(20); pen_cursor.setColor(QColor(244, 200, 0)); customPlot->graph(2)->setPen(pen_cursor); customPlot->xAxis->setLabel("Time(h:m:s)"); customPlot->yAxis->setLabel("Current (mA)"); customPlot->yAxis->setRange(current_lower_limit, current_upper_limit); customPlot->yAxis2->setVisible(true); customPlot->yAxis2->setLabel("Voltage (V)"); customPlot->yAxis2->setRange(voltage_lower_limit, voltage_upper_limit); connect(ui->customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(xAxisChanged(QCPRange))); customPlot->legend->setVisible(true); customPlot->graph(0)->setName("Current"); customPlot->graph(1)->setName("Voltage"); customPlot->graph(2)->setName("Cursor"); customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables | QCP::iMultiSelect); customPlot->setSelectionRectMode(QCP::srmSelect); customPlot->graph(0)->setSelectable(QCP::stDataRange); customPlot->graph(1)->setSelectable(QCP::stDataRange); customPlot->graph(2)->setSelectable(QCP::stSingleData); foreach (QCPAxisRect *rect, customPlot->axisRects()) { rect->setRangeDrag(Qt::Horizontal); rect->setRangeZoom(Qt::Horizontal); } }
My main QCustomPlot widget is as shown here:
My
setup_graph
method contains all configuration and initialization of my QCustomPlot. I think somewhere inside here I must utilize my new classQMyPlot
instead of usingcustomPlot
.I am currently reading more about QAxisRect to fully figure out how and where should I use my new class
QMyPlot
object. -
@jsulm
Thanks for the tip. I have fixed my declaration as you have suggested and added override keyword.I am slowly starting to grasp how my QMyPlot supposed to work. See my MainWindow.cpp:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { sample_counter = 0; sample_counter_1_sec = 0; ui->setupUi(this); setup_graph(ui->customPlot); connect(ui->customPlot, &QCustomPlot::mouseMove, this, &MainWindow::showPointToolTip); connect(ui->customPlot, &QCustomPlot::mouseDoubleClick, this, &MainWindow::SavePoint); connect(ui->customPlot, &QCustomPlot::selectionChangedByUser, this, &MainWindow::Calculate_average_selected); connect(ui->customPlot, &QCustomPlot::mousePress, this, &MainWindow::ChangeScrollMode); } void MainWindow::setup_graph(QCustomPlot *customPlot) { current_upper_limit = 10; current_lower_limit = 0; voltage_upper_limit = 5; voltage_lower_limit = 0; QColor accentColor = QColor(Qt::red); QColor themeColor = QColor(Qt::white); QColor themeBackgroundColor = QColor(53, 57, 53); QColor traceColor = accentColor; QMyPlot test(customPlot); foreach (QCPAxisRect *rect, customPlot->axisRects()) { foreach (QCPAxis *axis, rect->axes()) { axis->setLabelColor(themeColor); axis->setBasePen(QPen(themeColor, 1)); axis->setTickPen(QPen(themeColor, 1)); axis->setSubTickPen(QPen(themeColor, 1)); axis->setTickLabelColor(themeColor); axis->grid()->setPen(QPen(themeColor, 0.5, Qt::DotLine)); axis->grid()->setSubGridVisible(false); axis->setSelectedTickLabelColor(accentColor); axis->setSelectedLabelColor(accentColor); axis->setSelectedBasePen(QPen(accentColor, 1)); axis->setSelectedSubTickPen(QPen(accentColor, 1)); axis->setSelectedTickPen(QPen(accentColor, 1)); } } ui->customPlot->setBackground(QBrush(themeBackgroundColor)); // SETUP GRAPH 0 for Current customPlot->addGraph(); customPlot->graph(0)->setScatterStyle(QCPScatterStyle::ssCircle); customPlot->graph(0)->setLineStyle(QCPGraph::lsLine); QPen pen_current; pen_current.setWidth(2); pen_current.setColor(QColor(80, 200, 120)); customPlot->graph(0)->setPen(pen_current); // SETUP GRAPH 1 for Voltage // customPlot->addGraph(); customPlot->addGraph(customPlot->xAxis, customPlot->yAxis2); customPlot->graph(1)->setScatterStyle(QCPScatterStyle::ssCross); customPlot->graph(1)->setLineStyle(QCPGraph::lsLine); QPen pen_voltage; pen_voltage.setWidth(2); pen_voltage.setColor(QColor(225,225,50)); customPlot->graph(1)->setPen(pen_voltage); // SETUP GRAPH 2 for cursors customPlot->addGraph(customPlot->xAxis, customPlot->yAxis); customPlot->graph(2)->setLineStyle((QCPGraph::LineStyle)QCPGraph::lsNone); customPlot->graph(2)->setScatterStyle(QCPScatterStyle::ssTriangle); QPen pen_cursor; pen_cursor.setWidth(20); pen_cursor.setColor(QColor(244, 200, 0)); customPlot->graph(2)->setPen(pen_cursor); customPlot->xAxis->setLabel("Time(h:m:s)"); customPlot->yAxis->setLabel("Current (mA)"); customPlot->yAxis->setRange(current_lower_limit, current_upper_limit); customPlot->yAxis2->setVisible(true); customPlot->yAxis2->setLabel("Voltage (V)"); customPlot->yAxis2->setRange(voltage_lower_limit, voltage_upper_limit); connect(ui->customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(xAxisChanged(QCPRange))); customPlot->legend->setVisible(true); customPlot->graph(0)->setName("Current"); customPlot->graph(1)->setName("Voltage"); customPlot->graph(2)->setName("Cursor"); customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables | QCP::iMultiSelect); customPlot->setSelectionRectMode(QCP::srmSelect); customPlot->graph(0)->setSelectable(QCP::stDataRange); customPlot->graph(1)->setSelectable(QCP::stDataRange); customPlot->graph(2)->setSelectable(QCP::stSingleData); foreach (QCPAxisRect *rect, customPlot->axisRects()) { rect->setRangeDrag(Qt::Horizontal); rect->setRangeZoom(Qt::Horizontal); } }
My main QCustomPlot widget is as shown here:
My
setup_graph
method contains all configuration and initialization of my QCustomPlot. I think somewhere inside here I must utilize my new classQMyPlot
instead of usingcustomPlot
.I am currently reading more about QAxisRect to fully figure out how and where should I use my new class
QMyPlot
object.@lukutis222 said in Overriding QCustomPlot library method with your own method:
I am currently reading more about QAxisRect to fully figure out how and where should I use my new class QMyPlot object.
You can add QMyPlot instance manually in code instead of in designer.
But you also can do that in designer: https://doc.qt.io/qt-6/designer-using-custom-widgets.html -
@lukutis222 said in Overriding QCustomPlot library method with your own method:
I am currently reading more about QAxisRect to fully figure out how and where should I use my new class QMyPlot object.
You can add QMyPlot instance manually in code instead of in designer.
But you also can do that in designer: https://doc.qt.io/qt-6/designer-using-custom-widgets.htmlwrote on 4 Apr 2024, 09:06 last edited by@jsulm
But that is not going to do anything on its own. QAxisRect is nothing on its own without the QCustomPlot -
@jsulm
But that is not going to do anything on its own. QAxisRect is nothing on its own without the QCustomPlot@lukutis222 Then add them in code
1/12