add qcustomplot

This commit is contained in:
朱子楚\zhuzi
2024-06-17 16:42:54 +08:00
parent a3fa54a02b
commit b11fccd758
24 changed files with 45313 additions and 29 deletions

View File

@ -30,8 +30,8 @@ endif ()
option(FLUENTUI_BUILD_STATIC_LIB "Build static library." OFF)
#导入Qt相关依赖包
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Quick Qml)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Quick)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Quick Qml Widgets PrintSupport)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Quick Widgets PrintSupport)
set(QT_SDK_DIR "${Qt${QT_VERSION_MAJOR}_DIR}/../../..")
cmake_path(SET QT_SDK_DIR NORMALIZE ${QT_SDK_DIR})
@ -196,6 +196,8 @@ target_link_libraries(${PROJECT_NAME} PUBLIC
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Quick
Qt${QT_VERSION_MAJOR}::Qml
Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::PrintSupport
)
if(APPLE)
find_library(CARBON_LIBRARY Carbon)
@ -216,6 +218,10 @@ elseif(UNIX)
target_link_libraries(${PROJECT_NAME} PRIVATE X11)
endif()
target_include_directories(${PROJECT_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/qmlcustomplot
)
if ((${QT_VERSION_MAJOR} LESS_EQUAL 6) AND (CMAKE_BUILD_TYPE MATCHES "Release"))
find_program(QML_PLUGIN_DUMP NAMES qmlplugindump)
add_custom_target(Script-Generate-QmlTypes

View File

@ -17,6 +17,11 @@
#include "FluFrameless.h"
#include "FluTableModel.h"
#include "FluHotkey.h"
#include "qmlcustomplot/TimePlot.h"
#include "qmlcustomplot/baseplot.h"
#include "qmlcustomplot/axis.h"
#include "qmlcustomplot/ticker.h"
#include "qmlcustomplot/grid.h"
void FluentUI::registerTypes(QQmlEngine *engine) {
initializeEngine(engine, _uri);
@ -40,6 +45,13 @@ void FluentUI::registerTypes(const char *uri) const {
qmlRegisterType<FluHotkey>(uri, major, minor, "FluHotkey");
qmlRegisterType<FluTableSortProxyModel>(uri, major, minor, "FluTableSortProxyModel");
qmlRegisterType<QmlQCustomPlot::TimePlot>(uri, major, minor, "TimePlot");
qmlRegisterType<QmlQCustomPlot::BasePlot>(uri, major, minor, "BasePlot");
qmlRegisterUncreatableType<QmlQCustomPlot::Axis>(uri, major, minor, "Axis", "");
qmlRegisterUncreatableType<QmlQCustomPlot::Ticker>(uri, major, minor, "Ticker", "");
qmlRegisterUncreatableType<QmlQCustomPlot::Grid>(uri, major, minor, "Grid", "");
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluAcrylic.qml"), uri, major, minor, "FluAcrylic");
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluAppBar.qml"), uri, major, minor, "FluAppBar");
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluFrame.qml"), uri, major, minor, "FluFrame");

View File

@ -0,0 +1,88 @@
#include "TimePlot.h"
#include "graph.h"
#include "axis.h"
#include "qcustomplot.h"
#include <QTimer>
namespace QmlQCustomPlot
{
TimePlot::TimePlot(QQuickItem *parent)
: BasePlot(parent)
, m_timer(new QTimer(this))
{
xAxis()->setTickerType(Axis::Time);
connect(m_timer, &QTimer::timeout, this, &TimePlot::onTimeOut);
m_timer->start(5);
startTimer(25);
m_plotTimeRangeInMilliseconds = 60;
}
TimePlot::~TimePlot()
{
}
void TimePlot::set_plotTimeRangeInMilliseconds(int value) noexcept
{
if(m_plotTimeRangeInMilliseconds != value) {
m_plotTimeRangeInMilliseconds = value;
emit plotTimeRangeInMillisecondsChanged(value);
}
}
Q_INVOKABLE void TimePlot::setTimeFormat(const QString &format) noexcept
{
if(xAxis()) {
QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime);
timeTicker->setTimeFormat(format);
xAxis()->setTicker(timeTicker);
}
}
Q_INVOKABLE void TimePlot::addCurrentTimeValue(const QString &name, double value) noexcept
{
auto graph = getGraph(name);
if(graph) {
graph->addData(m_currentTimeKey, value);
}
}
Q_INVOKABLE void TimePlot::addCurrentTimeValues(QVariantMap values) noexcept
{
for(auto it = values.begin(); it != values.end(); ++it) {
addCurrentTimeValue(it.key(), it.value().toDouble());
}
}
void TimePlot::onTimeOut() noexcept
{
auto todayString = QDateTime::currentDateTime().toString("yyyy-MM-dd") + " 00:00:00";
auto todayTime = QDateTime::fromString(todayString, "yyyy-MM-dd hh:mm:ss");
m_currentTimeKey = todayTime.msecsTo(QDateTime::currentDateTime()) / 1000.0;
if(m_currentTimeKey - m_lastClearTime > m_plotTimeRangeInMilliseconds || m_currentTimeKey < m_lastClearTime) {
auto map = graphsMap();
std::for_each(map.begin(), map.end(), [this](auto graph) {
if(graph) graph->removeDataBefore(m_currentTimeKey - m_plotTimeRangeInMilliseconds);
});
m_lastClearTime = m_currentTimeKey;
}
// if(m_currentTimeKey - m_lastAddedTime > 0.002 || m_currentTimeKey < m_lastAddedTime) {
// auto map = graphsMap();
// std::for_each(map.begin(), map.end(), [this](auto graph) {
// if(graph) graph->addData(m_currentTimeKey, 4.0);
// });
// m_lastAddedTime = m_currentTimeKey;
// }
if(xAxis())
xAxis()->setRange(m_currentTimeKey - m_plotTimeRangeInMilliseconds, m_currentTimeKey);
// QCP::MarginSide s = &static_cast<QCP::MarginSide*>((customPlot()->axisRect()->autoMargins()));
// qDebug() << s;
}
void TimePlot::timerEvent(QTimerEvent *event)
{
customPlot()->replot();
}
} // namespace QmlQCustomPlot

View File

@ -0,0 +1,113 @@
#pragma once
#include "baseplot.h"
#include <QElapsedTimer>
class QTimer;
namespace QmlQCustomPlot
{
/*
* @class TimePlot
* @brief A class for dynamically updating the x-axis and curves with the current time in milliseconds.
*
* This class extends the BasePlot and provides functionalities to dynamically update
* a plot with time values. It allows adding time values either individually or in bulk.
* The x-axis is based on the current time of the day, displaying values within a specified time range.
*/
class TimePlot : public BasePlot
{
Q_OBJECT
QML_ELEMENT
QML_READ_WRITE_NOTIFY_PROPERTY(int, plotTimeRangeInMilliseconds) // Property to hold the time range for the plot display in milliseconds.
public:
/*
* @brief Constructor for the TimePlot class.
*
* This constructor initializes the TimePlot object, setting the parent QQuickItem and
* initializing the internal timer and elapsed time tracker.
*
* @param parent The parent QQuickItem, default is nullptr.
*/
TimePlot(QQuickItem *parent = nullptr);
~TimePlot();
/*
* @brief Sets the time range for the plot display in milliseconds.
*
* This function allows the user to specify the range of time (in milliseconds) that the
* plot should display on the x-axis. For example, setting this to 60000 will display the
* last 60 seconds of data on the plot.
* Default is 60 seconds
*
* @param value The time range in milliseconds.
*/
void set_plotTimeRangeInMilliseconds(int value) noexcept;
/*
* @brief Sets the time format for the x-axis labels.
*
* This function allows the user to specify the format of the time labels on the x-axis.
* The format should be a valid QDateTime format string, such as "hh:mm:ss" or "hh:mm:ss.zzz".
* Default is "hh:mm:ss".
*
* @param format The format string for the time labels.
*/
Q_INVOKABLE void setTimeFormat(const QString &format) noexcept;
/*
* @brief Adds a current time value to the plot.
*
* This function adds a single data point to the plot. The x-axis value is the current
* elapsed time in milliseconds since the timer started, and the y-axis value is provided
* by the user. The data point is associated with a specific series name (curve name).
*
* @param name The name of the data series (curve name).
* @param value The value to be added to the plot.
*/
Q_INVOKABLE void addCurrentTimeValue(const QString& name, double value) noexcept;
/*
* @brief Adds multiple current time values to the plot.
*
* This function allows adding multiple data points to the plot at once. The values are
* provided as a QVariantMap, where each key is the name of a data series (curve name)
* and the corresponding value is the data point to be added. The x-axis value for all
* data points is the current elapsed time in milliseconds.
*
* @param values A map of series names (curve names) and their corresponding values to be added to the plot.
*/
Q_INVOKABLE void addCurrentTimeValues(QVariantMap values) noexcept;
protected:
/*
* @brief Function called when the timer times out.
*
* This function is intended to be overridden by subclasses to define custom behavior
* when the timer expires. By default, it does nothing, but it can be used to update
* the plot or perform other actions at regular intervals.
*/
virtual void onTimeOut() noexcept;
/*
* @brief Handles timer events.
*
* This function is called automatically by the Qt framework when a timer event occurs.
* It updates the plot by adding a new time value if necessary and handles any other
* timer-related functionality.
*
* @param event The timer event containing information about the timer that triggered the event.
*/
void timerEvent(QTimerEvent *event) override;
private:
QTimer *m_timer = nullptr; ///< Pointer to the QTimer object used to trigger regular updates.
double m_currentTimeKey = 0; ///< Current time key (x-axis value) in seconds.
// double m_lastAddedTime = 0; ///< Time (in milliseconds) of the last added data point.
double m_lastClearTime = 0; ///< Time (in milliseconds) of the last clear operation.
};
} // namespace QmlQCustomPlot

132
src/qmlcustomplot/axis.cpp Normal file
View File

@ -0,0 +1,132 @@
#include "axis.h"
#include "grid.h"
#include "ticker.h"
#include "qcustomplot.h"
#include <stdexcept>
namespace QmlQCustomPlot
{
Axis::Axis(QObject *parent) : QObject(parent)
{
}
Axis::Axis(QCPAxis* axis, QCustomPlot *parentPlot, QObject *parent)
: m_parentPlot(parentPlot), m_axis(axis), QObject(parent)
{
if(parentPlot == nullptr || axis == nullptr)
throw std::invalid_argument(nullptr);
connect(parentPlot, &QCustomPlot::beforeReplot, this, &Axis::updateProperty);
connect(axis, &QCPAxis::destroyed, this, &Axis::deleteLater);
m_ticker = new Ticker(axis, m_parentPlot, this);
m_grid = new Grid(axis->grid(), m_parentPlot, this);
updateProperty();
}
Axis::~Axis()
{
}
void Axis::setTickerType(TickerType type)
{
QSharedPointer<QCPAxisTicker> ticker;
switch (type)
{
default:
case Fixed:
ticker = QSharedPointer<QCPAxisTicker>(new QCPAxisTickerFixed);
break;
case Log:
ticker = QSharedPointer<QCPAxisTicker>(new QCPAxisTickerLog);
break;
case Pi:
ticker = QSharedPointer<QCPAxisTicker>(new QCPAxisTickerPi);
break;
case Text:
ticker = QSharedPointer<QCPAxisTicker>(new QCPAxisTickerText);
break;
case DateTime:
ticker = QSharedPointer<QCPAxisTicker>(new QCPAxisTickerDateTime);
break;
case Time:
ticker = QSharedPointer<QCPAxisTicker>(new QCPAxisTickerTime);
break;
}
m_axis->setTicker(ticker);
m_parentPlot->replot();
}
void Axis::setRange(float position, float size, Qt::AlignmentFlag align) noexcept
{
m_axis->setRange(position, size, align);
m_parentPlot->replot();
}
Q_INVOKABLE void Axis::setRange(float lower, float upper) noexcept
{
m_axis->setRange(lower, upper);
}
void Axis::setTicker(QSharedPointer<QCPAxisTicker> ticker) noexcept
{
m_axis->setTicker(ticker);
m_parentPlot->replot();
}
void Axis::set_visible(bool value) noexcept
{
m_visible = m_axis->visible();
if(m_visible == value) return;
m_visible = value;
m_axis->setVisible(value);
Q_EMIT visibleChanged(m_visible);
m_parentPlot->replot();
}
void Axis::set_label(const QString &value) noexcept
{
m_label = m_axis->label();
if(m_label == value) return;
m_label = value;
m_axis->setLabel(value);
Q_EMIT labelChanged(m_label);
m_parentPlot->replot();
}
void Axis::set_upper(float value) noexcept
{
m_upper = m_axis->range().upper;
if(m_upper == value) return;
m_upper = value;
m_axis->setRangeLower(value);
Q_EMIT upperChanged(m_upper);
m_parentPlot->replot();
}
void Axis::set_lower(float value) noexcept
{
m_lower = m_axis->range().lower;
if(m_lower == value) return;
m_lower = value;
m_axis->setRangeUpper(value);
Q_EMIT lowerChanged(m_lower);
m_parentPlot->replot();
}
void Axis::updateProperty() noexcept
{
m_visible = m_axis->visible();
m_label = m_axis->label();
m_upper = m_axis->range().upper;
m_lower = m_axis->range().lower;
Q_EMIT visibleChanged(m_visible);
Q_EMIT labelChanged(m_label);
Q_EMIT upperChanged(m_upper);
Q_EMIT lowerChanged(m_lower);
}
} // namespace QmlQCustomPlot

56
src/qmlcustomplot/axis.h Normal file
View File

@ -0,0 +1,56 @@
#pragma once
#include "macros.h"
#include <QtCore/QObject>
#include <QtQml/qqml.h>
#include "grid.h"
#include "ticker.h"
class QCPAxis;
class QCPAxisTicker;
class QCustomPlot;
namespace QmlQCustomPlot
{
class Grid;
class Ticker;
class Axis : public QObject
{
Q_OBJECT
QML_READ_WRITE_NOTIFY_PROPERTY(bool , visible)
QML_READ_WRITE_NOTIFY_PROPERTY(QString , label)
QML_READ_WRITE_NOTIFY_PROPERTY(float , upper)
QML_READ_WRITE_NOTIFY_PROPERTY(float , lower)
QML_READ_CONSTANT(QmlQCustomPlot::Grid*, grid)
QML_READ_CONSTANT(QmlQCustomPlot::Ticker*, ticker)
QML_ELEMENT
QML_UNCREATABLE("")
public:
explicit Axis(QObject *parent = nullptr);
Axis(QCPAxis* axis, QCustomPlot *parentPlot, QObject *parent = nullptr);
~Axis();
Q_ENUMS(TickerType)
enum TickerType { Fixed, Log, Pi, Text, DateTime, Time };
Q_INVOKABLE void setTickerType(TickerType type);
Q_INVOKABLE void setRange(float position, float size, Qt::AlignmentFlag align) noexcept;
Q_INVOKABLE void setRange(float lower, float upper) noexcept;
void setTicker(QSharedPointer<QCPAxisTicker> ticker) noexcept;
void set_visible(bool value) noexcept;
void set_label(const QString &value) noexcept;
void set_upper(float value) noexcept;
void set_lower(float value) noexcept;
private:
void updateProperty() noexcept;
private:
QCustomPlot *m_parentPlot = nullptr;
QCPAxis* m_axis = nullptr;
};
} // namespace QmlQCustomPlot

View File

@ -0,0 +1,138 @@
#include "baseplot.h"
#include "axis.h"
#include "graph.h"
#include "qcustomplot.h"
#include <stdexcept>
namespace QmlQCustomPlot
{
BasePlot::BasePlot(QQuickItem *parent)
: QQuickPaintedItem(parent)
, m_customPlot(new QCustomPlot())
{
setFlag(QQuickItem::ItemHasContents, true);
setAcceptedMouseButtons(Qt::AllButtons);
setAcceptHoverEvents(true);
connect(this, &QQuickPaintedItem::widthChanged, this, &BasePlot::onChartViewSizeChanged);
connect(this, &QQuickPaintedItem::heightChanged, this, &BasePlot::onChartViewSizeChanged);
connect(m_customPlot, &QCustomPlot::afterReplot, this, &BasePlot::onChartViewReplot, Qt::UniqueConnection);
try {
m_xAxis = new Axis(m_customPlot->xAxis, m_customPlot, this);
m_x1Axis = new Axis(m_customPlot->xAxis2, m_customPlot, this);
m_yAxis = new Axis(m_customPlot->yAxis, m_customPlot, this);
m_y1Axis = new Axis(m_customPlot->yAxis2, m_customPlot, this);
connect(m_xAxis, &Axis::destroyed, this, [this]{ m_xAxis = nullptr; Q_EMIT xAxisChanged(nullptr); });
connect(m_x1Axis, &Axis::destroyed, this, [this]{ m_x1Axis = nullptr; Q_EMIT x1AxisChanged(nullptr);});
connect(m_yAxis, &Axis::destroyed, this, [this]{ m_yAxis = nullptr; Q_EMIT yAxisChanged(nullptr); });
connect(m_y1Axis, &Axis::destroyed, this, [this]{ m_y1Axis = nullptr; Q_EMIT y1AxisChanged(nullptr);});
connect(m_customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), m_customPlot->xAxis2, SLOT(setRange(QCPRange)));
connect(m_customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), m_customPlot->yAxis2, SLOT(setRange(QCPRange)));
}
catch(const std::exception &e) {
qCritical() << e.what();
m_xAxis = nullptr;
m_x1Axis = nullptr;
m_yAxis = nullptr;
m_y1Axis = nullptr;
}
update();
}
BasePlot::~BasePlot()
{
delete m_customPlot;
}
void BasePlot::set_backgroundColor(const QColor &value)
{
// m_backgroundColor = m_customPlot->background().toImage().pixelColor(0, 0);
if(m_backgroundColor == value) return;
m_backgroundColor = value;
m_customPlot->setBackground(QBrush(m_backgroundColor));
// m_customPlot->axisRect()->setBackground(QBrush(m_backgroundColor));
emit backgroundColorChanged(m_backgroundColor);
m_customPlot->replot();
}
QVariantMap BasePlot::graphs() const
{
QVariantMap map;
for(auto it = m_graphs.begin(); it != m_graphs.end(); ++it) {
map.insert(it.key(), QVariant::fromValue(it.value()));
}
return map;
}
Q_INVOKABLE void BasePlot::addGraph(const QString &key)
{
if(m_graphs.contains(key)) return;
auto g = m_customPlot->addGraph();
if(g == nullptr) return;
g->setName(key);
auto graph = new Graph(g, m_customPlot, this);
m_graphs.insert(key, graph);
emit graphsChanged();
}
Q_INVOKABLE void BasePlot::removeGraph(const QString &key)
{
if(m_graphs.contains(key)) {
auto graph = m_graphs.take(key);
delete graph;
emit graphsChanged();
}
}
Q_INVOKABLE void BasePlot::rescaleAxes(bool onlyVisiblePlottables)
{
m_customPlot->rescaleAxes(onlyVisiblePlottables);
}
Graph *BasePlot::getGraph(const QString &key) const
{
if(m_graphs.contains(key)) {
return m_graphs.value(key);
}
return nullptr;
}
void BasePlot::paint(QPainter *painter)
{
if (!painter->isActive())
return;
QPixmap picture( boundingRect().size().toSize() );
QCPPainter qcpPainter( &picture );
m_customPlot->toPainter(&qcpPainter);
painter->drawPixmap(QPoint(), picture);
}
void BasePlot::onChartViewSizeChanged()
{
m_customPlot->setGeometry(0, 0, (int)width(), (int)height());
m_customPlot->setViewport(QRect(0, 0, (int)width(), (int)height()));
m_customPlot->axisRect()->setOuterRect(QRect(0, 0, (int)width(), (int)height()));
m_customPlot->axisRect()->setMinimumMargins (QMargins(0, 0, 0, 0));
m_customPlot->axisRect()->setMargins(QMargins(0, 0, 0, 0));
}
void BasePlot::routeMouseEvents(QMouseEvent *event)
{
QMouseEvent* newEvent = new QMouseEvent(event->type(), event->localPos(), event->button(), event->buttons(), event->modifiers());
QCoreApplication::postEvent(m_customPlot, newEvent);
}
void BasePlot::routeWheelEvents(QWheelEvent *event)
{
QWheelEvent* newEvent = new QWheelEvent(event->position(), event->globalPosition(),
event->pixelDelta(), event->angleDelta(),
event->buttons(), event->modifiers(),
event->phase(), event->inverted());
QCoreApplication::postEvent(m_customPlot, newEvent);
}
} // namespace QmlQCustomPlot

View File

@ -0,0 +1,60 @@
#pragma once
#include "macros.h"
#include <QtGui/QColor>
#include <QtCore/QVariantMap>
#include <QtCore/QString>
#include <QtQuick/QQuickPaintedItem>
class QCustomPlot;
namespace QmlQCustomPlot
{
class Axis;
class Graph;
class BasePlot : public QQuickPaintedItem
{
Q_OBJECT
QML_READ_WRITE_NOTIFY_PROPERTY(QColor, backgroundColor)
QML_READ_NOTIFY_PROPERTY(QmlQCustomPlot::Axis *, xAxis)
QML_READ_NOTIFY_PROPERTY(QmlQCustomPlot::Axis *, x1Axis)
QML_READ_NOTIFY_PROPERTY(QmlQCustomPlot::Axis *, yAxis)
QML_READ_NOTIFY_PROPERTY(QmlQCustomPlot::Axis *, y1Axis)
QML_ELEMENT
Q_PROPERTY(QVariantMap graphs READ graphs NOTIFY graphsChanged)
public:
BasePlot(QQuickItem *parent = nullptr);
~BasePlot();
void set_backgroundColor(const QColor &value);
QVariantMap graphs() const;
Q_SIGNAL void graphsChanged();
Q_INVOKABLE void addGraph(const QString &key);
Q_INVOKABLE void removeGraph(const QString &key);
Q_INVOKABLE void rescaleAxes(bool onlyVisiblePlottables=false);
void paint(QPainter *painter);
QCustomPlot *customPlot() const { return m_customPlot; }
const QMap<QString, Graph *> &graphsMap() const { return m_graphs; }
Graph* getGraph(const QString &key) const;
protected:
virtual void onChartViewReplot() { update(); }
virtual void onChartViewSizeChanged();
virtual void hoverMoveEvent(QHoverEvent *event) override { Q_UNUSED(event) }
virtual void mousePressEvent(QMouseEvent *event) override { routeMouseEvents(event); }
virtual void mouseReleaseEvent(QMouseEvent *event) override { routeMouseEvents(event); }
virtual void mouseMoveEvent(QMouseEvent *event) override { routeMouseEvents(event); }
virtual void mouseDoubleClickEvent(QMouseEvent *event) override { routeMouseEvents(event); }
virtual void wheelEvent(QWheelEvent *event) override { routeWheelEvents(event); }
void routeMouseEvents(QMouseEvent *event);
void routeWheelEvents(QWheelEvent *event);
private:
QCustomPlot *m_customPlot = nullptr;
QMap<QString, Graph *> m_graphs;
};
} // namespace QmlQCustomPlot

128
src/qmlcustomplot/graph.cpp Normal file
View File

@ -0,0 +1,128 @@
#include "graph.h"
#include "qcustomplot.h"
#include <QPen>
#include <stdexcept>
namespace QmlQCustomPlot
{
Graph::Graph(QCPGraph* graph, QCustomPlot *parentPlot, QObject *parent)
: m_graph(graph), m_parentPlot(parentPlot), QObject(parent)
{
if(parentPlot == nullptr || graph == nullptr)
throw std::invalid_argument(nullptr);
connect(parentPlot, &QCustomPlot::beforeReplot, this, &Graph::updateProperty);
updateProperty();
}
Graph::~Graph()
{
}
void Graph::setData(const QVector<double> &keys, const QVector<double> &values) noexcept
{
m_graph->setData(keys, values);
m_parentPlot->replot();
}
void Graph::addData(double key, double value) noexcept
{
m_graph->addData(key, value);
m_parentPlot->replot();
}
void Graph::removeDataBefore(double key) noexcept
{
m_graph->data()->removeBefore(key);
m_parentPlot->replot();
}
void Graph::clearData() noexcept
{
m_graph->data()->clear();
m_parentPlot->replot();
}
void Graph::set_visible(bool value) noexcept
{
m_visible = m_graph->visible();
if(m_visible == value) return;
m_visible = value;
m_graph->setVisible(value);
Q_EMIT visibleChanged(m_visible);
m_parentPlot->replot();
}
void Graph::set_antialiased(bool value) noexcept
{
m_antialiased = m_graph->antialiased();
if(m_antialiased == value) return;
m_antialiased = value;
m_graph->setAntialiased(value);
Q_EMIT antialiasedChanged(m_antialiased);
m_parentPlot->replot();
}
void Graph::set_name(const QString &value) noexcept
{
m_name = m_graph->name();
if(m_name == value) return;
m_name = value;
m_graph->setName(value);
Q_EMIT nameChanged(m_name);
m_parentPlot->replot();
}
void Graph::set_lineStyle(LineStyle value) noexcept
{
m_lineStyle = static_cast<Graph::LineStyle>(m_graph->lineStyle());
if(m_lineStyle == value) return;
m_lineStyle = value;
m_graph->setLineStyle(static_cast<QCPGraph::LineStyle>(value));
Q_EMIT lineStyleChanged(m_lineStyle);
m_parentPlot->replot();
}
void Graph::set_graphWidth(int value) noexcept
{
m_graphWidth = m_graph->pen().width();
if(m_graphWidth == value) return;
m_graphWidth = value;
QPen pen = m_graph->pen();
pen.setWidth(value);
m_graph->setPen(pen);
Q_EMIT graphWidthChanged(m_graphWidth);
m_parentPlot->replot();
}
void Graph::set_graphColor(const QColor &value) noexcept
{
m_graphColor = m_graph->pen().color();
if(m_graphColor == value) return;
m_graphColor = value;
QPen pen = m_graph->pen();
pen.setColor(value);
m_graph->setPen(pen);
Q_EMIT graphColorChanged(m_graphColor);
m_parentPlot->replot();
}
void Graph::updateProperty() noexcept
{
m_visible = m_graph->visible();
m_antialiased = m_graph->antialiased();
m_name = m_graph->name();
m_lineStyle = static_cast<Graph::LineStyle>(m_graph->lineStyle());
m_graphWidth = m_graph->pen().width();
m_graphColor = m_graph->pen().color();
Q_EMIT visibleChanged(m_visible);
Q_EMIT antialiasedChanged(m_antialiased);
Q_EMIT nameChanged(m_name);
Q_EMIT lineStyleChanged(m_lineStyle);
Q_EMIT graphWidthChanged(m_graphWidth);
Q_EMIT graphColorChanged(m_graphColor);
}
}

58
src/qmlcustomplot/graph.h Normal file
View File

@ -0,0 +1,58 @@
#pragma once
#include "macros.h"
#include <QtCore/QObject>
#include <QtGui/QColor>
class QCPGraph;
class QCustomPlot;
namespace QmlQCustomPlot
{
class Graph : public QObject
{
Q_OBJECT
Q_ENUMS(LineType)
public:
enum LineStyle
{
lsNone,
lsLine,
lsStepLeft,
lsStepRight,
lsStepCenter,
lsImpulse
};
private:
QML_READ_WRITE_NOTIFY_PROPERTY(bool, visible)
QML_READ_WRITE_NOTIFY_PROPERTY(bool, antialiased)
QML_READ_WRITE_NOTIFY_PROPERTY(QString, name)
QML_READ_WRITE_NOTIFY_PROPERTY(LineStyle, lineStyle)
QML_READ_WRITE_NOTIFY_PROPERTY(int, graphWidth)
QML_READ_WRITE_NOTIFY_PROPERTY(QColor, graphColor)
public:
Graph(QCPGraph *graph, QCustomPlot *parentPlot, QObject *parent = nullptr);
~Graph();
Q_INVOKABLE void setData(const QVector<double> &keys, const QVector<double> &values) noexcept;
Q_INVOKABLE void addData(double key, double value) noexcept;
Q_INVOKABLE void removeDataBefore(double key) noexcept;
Q_INVOKABLE void clearData() noexcept;
void set_visible(bool value) noexcept;
void set_antialiased(bool value) noexcept;
void set_name(const QString &value) noexcept;
void set_lineStyle(LineStyle value) noexcept;
void set_graphWidth(int value) noexcept;
void set_graphColor(const QColor &value) noexcept;
private:
void updateProperty() noexcept;
private:
QCustomPlot *m_parentPlot = nullptr;
QCPGraph *m_graph = nullptr;
};
} // namespace QmlQCustomPlot

136
src/qmlcustomplot/grid.cpp Normal file
View File

@ -0,0 +1,136 @@
#include "grid.h"
#include "qcustomplot.h"
#include <QPen>
#include <stdexcept>
namespace QmlQCustomPlot
{
Grid::Grid(QCPGrid* grid, QCustomPlot *parentPlot, QObject *parent)
: m_qcpgrid(grid), m_parentPlot(parentPlot), QObject(parent)
{
if(parentPlot == nullptr || grid == nullptr)
throw std::invalid_argument(nullptr);
connect(parentPlot, &QCustomPlot::beforeReplot, this, &Grid::updateProperty);
updateProperty();
}
Grid::~Grid()
{
}
void Grid::set_visible(bool value) noexcept
{
m_visible = m_qcpgrid->visible();
if(m_visible == value) return;
m_visible = value;
m_qcpgrid->setVisible(value);
Q_EMIT visibleChanged(m_visible);
m_parentPlot->replot();
}
void Grid::set_subVisible(bool value) noexcept
{
m_subVisible = m_qcpgrid->subGridVisible();
if(m_subVisible == value) return;
m_subVisible = value;
m_qcpgrid->setSubGridVisible(value);
Q_EMIT subVisibleChanged(m_subVisible);
m_parentPlot->replot();
}
void Grid::set_lineWidth(int value) noexcept
{
m_lineWidth = m_qcpgrid->pen().width();
if(m_lineWidth == value) return;
m_lineWidth = value;
QPen pen = m_qcpgrid->pen();
pen.setWidth(value);
m_qcpgrid->setPen(pen);
Q_EMIT lineWidthChanged(m_lineWidth);
m_parentPlot->replot();
}
void Grid::set_lineColor(const QColor &value) noexcept
{
m_lineColor = m_qcpgrid->pen().color();
if(m_lineColor == value) return;
m_lineColor = value;
QPen pen = m_qcpgrid->pen();
pen.setColor(value);
m_qcpgrid->setPen(pen);
Q_EMIT lineColorChanged(m_lineColor);
m_parentPlot->replot();
}
void Grid::set_lineType(LineType value) noexcept
{
m_lineType = static_cast<LineType>(m_qcpgrid->pen().style());
if(m_lineType == value) return;
m_lineType = value;
QPen pen = m_qcpgrid->pen();
pen.setStyle(static_cast<Qt::PenStyle>(value));
m_qcpgrid->setPen(pen);
Q_EMIT lineTypeChanged(m_lineType);
m_parentPlot->replot();
}
void Grid::set_subLineWidth(int value) noexcept
{
m_subLineWidth = m_qcpgrid->subGridPen().width();
if(m_subLineWidth == value) return;
m_subLineWidth = value;
QPen pen = m_qcpgrid->subGridPen();
pen.setWidth(value);
m_qcpgrid->setSubGridPen(pen);
Q_EMIT subLineWidthChanged(m_subLineWidth);
m_parentPlot->replot();
}
void Grid::set_subLineColor(const QColor &value) noexcept
{
m_subLineColor = m_qcpgrid->subGridPen().color();
if(m_subLineColor == value) return;
m_subLineColor = value;
QPen pen = m_qcpgrid->subGridPen();
pen.setColor(value);
m_qcpgrid->setSubGridPen(pen);
Q_EMIT subLineColorChanged(m_subLineColor);
m_parentPlot->replot();
}
void Grid::set_subLineType(LineType value) noexcept
{
m_subLineType = static_cast<LineType>(m_qcpgrid->subGridPen().style());
if(m_subLineType == value) return;
m_subLineType = value;
QPen pen = m_qcpgrid->subGridPen();
pen.setStyle(static_cast<Qt::PenStyle>(value));
m_qcpgrid->setSubGridPen(pen);
Q_EMIT subLineTypeChanged(m_subLineType);
m_parentPlot->replot();
}
void Grid::updateProperty() noexcept
{
m_visible = m_qcpgrid->visible();
m_subVisible = m_qcpgrid->subGridVisible();
m_lineWidth = m_qcpgrid->pen().width();
m_lineColor = m_qcpgrid->pen().color();
m_lineType = static_cast<LineType>(m_qcpgrid->pen().style());
m_subLineWidth = m_qcpgrid->subGridPen().width();
m_subLineColor = m_qcpgrid->subGridPen().color();
m_subLineType = static_cast<LineType>(m_qcpgrid->subGridPen().style());
Q_EMIT visibleChanged(m_visible);
Q_EMIT subVisibleChanged(m_subVisible);
Q_EMIT lineWidthChanged(m_lineWidth);
Q_EMIT lineColorChanged(m_lineColor);
Q_EMIT lineTypeChanged(m_lineType);
Q_EMIT subLineWidthChanged(m_subLineWidth);
Q_EMIT subLineColorChanged(m_subLineColor);
Q_EMIT subLineTypeChanged(m_subLineType);
}
}

61
src/qmlcustomplot/grid.h Normal file
View File

@ -0,0 +1,61 @@
#pragma once
#include "macros.h"
#include <QtCore/QObject>
#include <QtGui/QColor>
#include <QtQml/qqml.h>
class QCPGrid;
class QCustomPlot;
namespace QmlQCustomPlot
{
class Grid : public QObject
{
Q_OBJECT
Q_ENUMS(LineType)
QML_ELEMENT
QML_UNCREATABLE("")
public:
enum LineType
{
NoPen,
SolidLine,
DashLine,
DotLine,
DashDotLine,
DashDotDotLine
};
private:
QML_READ_WRITE_NOTIFY_PROPERTY(bool, visible)
QML_READ_WRITE_NOTIFY_PROPERTY(bool, subVisible)
QML_READ_WRITE_NOTIFY_PROPERTY(int, lineWidth)
QML_READ_WRITE_NOTIFY_PROPERTY(QColor, lineColor)
QML_READ_WRITE_NOTIFY_PROPERTY(LineType, lineType)
QML_READ_WRITE_NOTIFY_PROPERTY(int, subLineWidth)
QML_READ_WRITE_NOTIFY_PROPERTY(QColor, subLineColor)
QML_READ_WRITE_NOTIFY_PROPERTY(LineType, subLineType)
public:
Grid(QCPGrid* grid, QCustomPlot *parentPlot, QObject *parent = nullptr);
~Grid();
void set_visible(bool value) noexcept;
void set_subVisible(bool value) noexcept;
void set_lineWidth(int value) noexcept;
void set_lineColor(const QColor &value) noexcept;
void set_lineType(LineType value) noexcept;
void set_subLineWidth(int value) noexcept;
void set_subLineColor(const QColor &value) noexcept;
void set_subLineType(LineType value) noexcept;
private:
void updateProperty() noexcept;
private:
QCustomPlot *m_parentPlot = nullptr;
QCPGrid *m_qcpgrid = nullptr;
};
} // namespace QmlQCustomPlot

View File

@ -0,0 +1,33 @@
#pragma once
namespace QmlQCustomPlot
{
#define QML_READ_WRITE_NOTIFY_PROPERTY(TYPE, NAME) \
Q_PROPERTY(TYPE NAME READ NAME WRITE set_##NAME NOTIFY NAME##Changed) \
public: \
TYPE NAME() const { return m_##NAME; } \
Q_SIGNAL void NAME##Changed(TYPE); \
private: \
TYPE m_##NAME {};
#define QML_READ_NOTIFY_PROPERTY(TYPE, NAME) \
Q_PROPERTY(TYPE NAME READ NAME NOTIFY NAME##Changed) \
public: \
TYPE NAME() const { return m_##NAME; } \
Q_SIGNAL void NAME##Changed(TYPE); \
private: \
TYPE m_##NAME {};
#define QML_READ_CONSTANT(TYPE, NAME) \
Q_PROPERTY(TYPE NAME READ NAME CONSTANT) \
public: \
TYPE NAME() const { return m_##NAME; } \
Q_SIGNAL void NAME##Changed(TYPE); \
private: \
TYPE m_##NAME {};
} // namespace QmlQCustomPlot

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,120 @@
#include "ticker.h"
#include "qcustomplot.h"
#include <QPen>
#include <stdexcept>
namespace QmlQCustomPlot
{
Ticker::Ticker(QCPAxis* parentAxis, QCustomPlot *parentPlot, QObject *parent)
: m_parentAxis(parentAxis), m_parentPlot(parentPlot), QObject(parent)
{
if(parentPlot == nullptr || parentAxis == nullptr)
throw std::invalid_argument(nullptr);
connect(parentPlot, &QCustomPlot::beforeReplot, this, &Ticker::updateProperty);
updateProperty();
}
Ticker::~Ticker()
{
}
void Ticker::set_ticks(bool value) noexcept
{
m_ticks = m_parentAxis->ticks();
if(m_ticks == value) return;
m_ticks = value;
m_parentAxis->setTicks(value);
Q_EMIT ticksChanged(m_ticks);
m_parentPlot->replot();
}
void Ticker::set_subTicks(bool value) noexcept
{
m_subTicks = m_parentAxis->subTicks();
if(m_subTicks == value) return;
m_subTicks = value;
m_parentAxis->setSubTicks(value);
Q_EMIT subTicksChanged(m_subTicks);
m_parentPlot->replot();
}
void Ticker::set_tickCount(int value) noexcept
{
m_tickCount = m_parentAxis->ticker()->tickCount();
if(m_tickCount == value) return;
m_tickCount = value;
m_parentAxis->ticker()->setTickCount(value);
Q_EMIT tickCountChanged(m_tickCount);
m_parentPlot->replot();
}
void Ticker::set_baseWidth(int value) noexcept
{
m_baseWidth = m_parentAxis->basePen().width();
if(m_baseWidth == value) return;
m_baseWidth = value;
QPen pen = m_parentAxis->basePen();
pen.setWidth(value);
m_parentAxis->setBasePen(pen);
Q_EMIT baseWidthChanged(m_baseWidth);
m_parentPlot->replot();
}
void Ticker::set_baseColor(const QColor &value) noexcept
{
m_baseColor = m_parentAxis->basePen().color();
if(m_baseColor == value) return;
m_baseColor = value;
QPen pen = m_parentAxis->basePen();
pen.setColor(value);
m_parentAxis->setBasePen(pen);
Q_EMIT baseColorChanged(m_baseColor);
m_parentPlot->replot();
}
void Ticker::set_tickColor(const QColor &value) noexcept
{
m_tickColor = m_parentAxis->tickPen().color();
if(m_tickColor == value) return;
m_tickColor = value;
QPen pen = m_parentAxis->tickPen();
pen.setColor(value);
m_parentAxis->setTickPen(pen);
Q_EMIT tickColorChanged(m_tickColor);
m_parentPlot->replot();
}
void Ticker::set_subTickColor(const QColor &value) noexcept
{
m_subTickColor = m_parentAxis->subTickPen().color();
if(m_subTickColor == value) return;
m_subTickColor = value;
QPen pen = m_parentAxis->subTickPen();
pen.setColor(value);
m_parentAxis->setSubTickPen(pen);
Q_EMIT subTickColorChanged(m_subTickColor);
m_parentPlot->replot();
}
void Ticker::updateProperty() noexcept
{
m_ticks = m_parentAxis->ticks();
m_subTicks = m_parentAxis->subTicks();
m_tickCount = m_parentAxis->ticker()->tickCount();
m_baseWidth = m_parentAxis->basePen().width();
m_baseColor = m_parentAxis->basePen().color();
m_tickColor = m_parentAxis->tickPen().color();
m_subTickColor = m_parentAxis->subTickPen().color();
Q_EMIT ticksChanged(m_ticks);
Q_EMIT subTicksChanged(m_subTicks);
Q_EMIT tickCountChanged(m_tickCount);
Q_EMIT baseWidthChanged(m_baseWidth);
Q_EMIT baseColorChanged(m_baseColor);
Q_EMIT tickColorChanged(m_tickColor);
Q_EMIT subTickColorChanged(m_subTickColor);
}
}

View File

@ -0,0 +1,47 @@
#pragma once
#include "macros.h"
#include <QtCore/QObject>
#include <QtGui/QColor>
#include <QtQml/qqml.h>
class QCPAxis;
class QCustomPlot;
namespace QmlQCustomPlot
{
class Ticker : public QObject
{
Q_OBJECT
QML_READ_WRITE_NOTIFY_PROPERTY(bool, ticks)
QML_READ_WRITE_NOTIFY_PROPERTY(bool, subTicks)
QML_READ_WRITE_NOTIFY_PROPERTY(int, tickCount)
QML_READ_WRITE_NOTIFY_PROPERTY(int, baseWidth)
QML_READ_WRITE_NOTIFY_PROPERTY(QColor, baseColor)
QML_READ_WRITE_NOTIFY_PROPERTY(QColor, tickColor)
QML_READ_WRITE_NOTIFY_PROPERTY(QColor, subTickColor)
QML_ELEMENT
QML_UNCREATABLE("")
public:
Ticker(QCPAxis* parentAxis, QCustomPlot *parentPlot, QObject *parent = nullptr);
~Ticker();
void set_ticks(bool value) noexcept;
void set_subTicks(bool value) noexcept;
void set_tickCount(int value) noexcept;
void set_baseWidth(int value) noexcept;
void set_baseColor(const QColor &value) noexcept;
void set_tickColor(const QColor &value) noexcept;
void set_subTickColor(const QColor &value) noexcept;
private:
void updateProperty() noexcept;
private:
QCustomPlot *m_parentPlot = nullptr;
QCPAxis* m_parentAxis = nullptr;
};
} // namespace QmlQCustomPlot