新增超级曲线图表

This commit is contained in:
feiyangqingyun
2021-12-10 20:34:18 +08:00
parent 1a2302c05d
commit e215d3989b
143 changed files with 120241 additions and 5 deletions

View File

@@ -0,0 +1,112 @@
/***************************************************************************
** **
** QCustomPlot, an easy to use, modern plotting widget for Qt **
** Copyright (C) 2011-2021 Emanuel Eichhammer **
** **
** This program is free software: you can redistribute it and/or modify **
** it under the terms of the GNU General Public License as published by **
** the Free Software Foundation, either version 3 of the License, or **
** (at your option) any later version. **
** **
** This program is distributed in the hope that it will be useful, **
** but WITHOUT ANY WARRANTY; without even the implied warranty of **
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **
** GNU General Public License for more details. **
** **
** You should have received a copy of the GNU General Public License **
** along with this program. If not, see http://www.gnu.org/licenses/. **
** **
****************************************************************************
** Author: Emanuel Eichhammer **
** Website/Contact: http://www.qcustomplot.com/ **
** Date: 29.03.21 **
** Version: 2.1.0 **
****************************************************************************/
#include "axistag.h"
AxisTag::AxisTag(QCPAxis *parentAxis) :
QObject(parentAxis),
mAxis(parentAxis)
{
// The dummy tracer serves here as an invisible anchor which always sticks to the right side of
// the axis rect
mDummyTracer = new QCPItemTracer(mAxis->parentPlot());
mDummyTracer->setVisible(false);
mDummyTracer->position->setTypeX(QCPItemPosition::ptAxisRectRatio);
mDummyTracer->position->setTypeY(QCPItemPosition::ptPlotCoords);
mDummyTracer->position->setAxisRect(mAxis->axisRect());
mDummyTracer->position->setAxes(0, mAxis);
mDummyTracer->position->setCoords(1, 0);
// the arrow end (head) is set to move along with the dummy tracer by setting it as its parent
// anchor. Its coordinate system (setCoords) is thus pixels, and this is how the needed horizontal
// offset for the tag of the second y axis is achieved. This horizontal offset gets dynamically
// updated in AxisTag::updatePosition. the arrow "start" is simply set to have the "end" as parent
// anchor. It is given a horizontal offset to the right, which results in a 15 pixel long arrow.
mArrow = new QCPItemLine(mAxis->parentPlot());
mArrow->setLayer("overlay");
mArrow->setClipToAxisRect(false);
mArrow->setHead(QCPLineEnding::esSpikeArrow);
mArrow->end->setParentAnchor(mDummyTracer->position);
mArrow->start->setParentAnchor(mArrow->end);
mArrow->start->setCoords(15, 0);
// The text label is anchored at the arrow start (tail) and has its "position" aligned at the
// left, and vertically centered to the text label box.
mLabel = new QCPItemText(mAxis->parentPlot());
mLabel->setLayer("overlay");
mLabel->setClipToAxisRect(false);
mLabel->setPadding(QMargins(3, 0, 3, 0));
mLabel->setBrush(QBrush(Qt::white));
mLabel->setPen(QPen(Qt::blue));
mLabel->setPositionAlignment(Qt::AlignLeft | Qt::AlignVCenter);
mLabel->position->setParentAnchor(mArrow->start);
}
AxisTag::~AxisTag()
{
if (mDummyTracer) {
mDummyTracer->parentPlot()->removeItem(mDummyTracer);
}
if (mArrow) {
mArrow->parentPlot()->removeItem(mArrow);
}
if (mLabel) {
mLabel->parentPlot()->removeItem(mLabel);
}
}
void AxisTag::setPen(const QPen &pen)
{
mArrow->setPen(pen);
mLabel->setPen(pen);
}
void AxisTag::setBrush(const QBrush &brush)
{
mLabel->setBrush(brush);
}
void AxisTag::setText(const QString &text)
{
mLabel->setText(text);
}
void AxisTag::updatePosition(double value)
{
// since both the arrow and the text label are chained to the dummy tracer (via anchor
// parent-child relationships) it is sufficient to update the dummy tracer coordinates. The
// Horizontal coordinate type was set to ptAxisRectRatio so to keep it aligned at the right side
// of the axis rect, it is always kept at 1. The vertical coordinate type was set to
// ptPlotCoordinates of the passed parent axis, so the vertical coordinate is set to the new
// value.
mDummyTracer->position->setCoords(1, value);
// We want the arrow head to be at the same horizontal position as the axis backbone, even if
// the axis has a certain offset from the axis rect border (like the added second y axis). Thus we
// set the horizontal pixel position of the arrow end (head) to the axis offset (the pixel
// distance to the axis rect border). This works because the parent anchor of the arrow end is
// the dummy tracer, which, as described earlier, is tied to the right axis rect border.
mArrow->end->setCoords(mAxis->offset(), 0);
}

View File

@@ -0,0 +1,60 @@
/***************************************************************************
** **
** QCustomPlot, an easy to use, modern plotting widget for Qt **
** Copyright (C) 2011-2021 Emanuel Eichhammer **
** **
** This program is free software: you can redistribute it and/or modify **
** it under the terms of the GNU General Public License as published by **
** the Free Software Foundation, either version 3 of the License, or **
** (at your option) any later version. **
** **
** This program is distributed in the hope that it will be useful, **
** but WITHOUT ANY WARRANTY; without even the implied warranty of **
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **
** GNU General Public License for more details. **
** **
** You should have received a copy of the GNU General Public License **
** along with this program. If not, see http://www.gnu.org/licenses/. **
** **
****************************************************************************
** Author: Emanuel Eichhammer **
** Website/Contact: http://www.qcustomplot.com/ **
** Date: 29.03.21 **
** Version: 2.1.0 **
****************************************************************************/
#ifndef AXISTAG_H
#define AXISTAG_H
#include <QObject>
#include "qcustomplot.h"
class AxisTag : public QObject
{
Q_OBJECT
public:
explicit AxisTag(QCPAxis *parentAxis);
virtual ~AxisTag();
// setters:
void setPen(const QPen &pen);
void setBrush(const QBrush &brush);
void setText(const QString &text);
// getters:
QPen pen() const { return mLabel->pen(); }
QBrush brush() const { return mLabel->brush(); }
QString text() const { return mLabel->text(); }
// other methods:
void updatePosition(double value);
protected:
QCPAxis *mAxis;
QPointer<QCPItemTracer> mDummyTracer;
QPointer<QCPItemLine> mArrow;
QPointer<QCPItemText> mLabel;
};
#endif // AXISTAG_H

View File

@@ -0,0 +1,67 @@
#include "frmaxistag.h"
#include "ui_frmaxistag.h"
#include "qdebug.h"
frmAxisTag::frmAxisTag(QWidget *parent) : QWidget(parent), ui(new Ui::frmAxisTag)
{
ui->setupUi(this);
this->initForm();
}
frmAxisTag::~frmAxisTag()
{
delete ui;
}
void frmAxisTag::initForm()
{
mPlot = ui->customPlot;
// configure plot to have two right axes:
mPlot->yAxis->setTickLabels(false);
connect(mPlot->yAxis2, SIGNAL(rangeChanged(QCPRange)), mPlot->yAxis, SLOT(setRange(QCPRange))); // left axis only mirrors inner right axis
mPlot->yAxis2->setVisible(true);
mPlot->axisRect()->addAxis(QCPAxis::atRight);
mPlot->axisRect()->axis(QCPAxis::atRight, 0)->setPadding(30); // add some padding to have space for tags
mPlot->axisRect()->axis(QCPAxis::atRight, 1)->setPadding(30); // add some padding to have space for tags
// create graphs:
mGraph1 = mPlot->addGraph(mPlot->xAxis, mPlot->axisRect()->axis(QCPAxis::atRight, 0));
mGraph2 = mPlot->addGraph(mPlot->xAxis, mPlot->axisRect()->axis(QCPAxis::atRight, 1));
mGraph1->setPen(QPen(QColor(250, 120, 0)));
mGraph2->setPen(QPen(QColor(0, 180, 60)));
// create tags with newly introduced AxisTag class (see axistag.h/.cpp):
mTag1 = new AxisTag(mGraph1->valueAxis());
mTag1->setPen(mGraph1->pen());
mTag2 = new AxisTag(mGraph2->valueAxis());
mTag2->setPen(mGraph2->pen());
connect(&mDataTimer, SIGNAL(timeout()), this, SLOT(timerSlot()));
mDataTimer.start(40);
}
void frmAxisTag::timerSlot()
{
// calculate and add a new data point to each graph:
int count1 = mGraph1->dataCount();
mGraph1->addData(count1, qSin(count1 / 50.0) + qSin(count1 / 50.0 / 0.3843) * 0.25);
int count2 = mGraph2->dataCount();
mGraph2->addData(count2, qCos(count2 / 50.0) + qSin(count2 / 50.0 / 0.4364) * 0.15);
// make key axis range scroll with the data:
mPlot->xAxis->rescale();
mGraph1->rescaleValueAxis(false, true);
mGraph2->rescaleValueAxis(false, true);
mPlot->xAxis->setRange(mPlot->xAxis->range().upper, 100, Qt::AlignRight);
// update the vertical axis tag positions and texts to match the rightmost data point of the graphs:
double graph1Value = mGraph1->dataMainValue(mGraph1->dataCount() - 1);
double graph2Value = mGraph2->dataMainValue(mGraph2->dataCount() - 1);
mTag1->updatePosition(graph1Value);
mTag2->updatePosition(graph2Value);
mTag1->setText(QString::number(graph1Value, 'f', 2));
mTag2->setText(QString::number(graph2Value, 'f', 2));
mPlot->replot();
}

View File

@@ -0,0 +1,34 @@
#ifndef FRMAXISTAG_H
#define FRMAXISTAG_H
#include <QWidget>
#include "qcustomplot.h"
#include "axistag.h"
namespace Ui {
class frmAxisTag;
}
class frmAxisTag : public QWidget
{
Q_OBJECT
public:
explicit frmAxisTag(QWidget *parent = 0);
~frmAxisTag();
private:
Ui::frmAxisTag *ui;
QCustomPlot *mPlot;
QPointer<QCPGraph> mGraph1;
QPointer<QCPGraph> mGraph2;
AxisTag *mTag1;
AxisTag *mTag2;
QTimer mDataTimer;
private slots:
void initForm();
void timerSlot();
};
#endif // FRMAXISTAG_H

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmAxisTag</class>
<widget class="QWidget" name="frmAxisTag">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCustomPlot" name="customPlot" native="true"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,16 @@
FORMS += \
$$PWD/frmaxistag.ui \
$$PWD/frminteraction.ui \
$$PWD/frmscrollbar.ui
HEADERS += \
$$PWD/axistag.h \
$$PWD/frmaxistag.h \
$$PWD/frminteraction.h \
$$PWD/frmscrollbar.h
SOURCES += \
$$PWD/axistag.cpp \
$$PWD/frmaxistag.cpp \
$$PWD/frminteraction.cpp \
$$PWD/frmscrollbar.cpp

View File

@@ -0,0 +1,266 @@
#include "frminteraction.h"
#include "ui_frminteraction.h"
#include "qmenu.h"
#include "qdebug.h"
frmInterAction::frmInterAction(QWidget *parent) : QWidget(parent), ui(new Ui::frmInterAction)
{
ui->setupUi(this);
this->initForm();
}
frmInterAction::~frmInterAction()
{
delete ui;
}
void frmInterAction::initForm()
{
std::srand(QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000.0);
ui->customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectAxes | QCP::iSelectLegend | QCP::iSelectPlottables);
ui->customPlot->xAxis->setRange(-8, 8);
ui->customPlot->yAxis->setRange(-5, 5);
ui->customPlot->axisRect()->setupFullAxesBox();
ui->customPlot->plotLayout()->insertRow(0);
QCPTextElement *title = new QCPTextElement(ui->customPlot, "Interaction Example", QFont("sans", 17, QFont::Bold));
ui->customPlot->plotLayout()->addElement(0, 0, title);
ui->customPlot->xAxis->setLabel("x Axis");
ui->customPlot->yAxis->setLabel("y Axis");
ui->customPlot->legend->setVisible(true);
QFont legendFont = font();
legendFont.setPointSize(10);
ui->customPlot->legend->setFont(legendFont);
ui->customPlot->legend->setSelectedFont(legendFont);
//ui->customPlot->legend->setSelectableParts(QCPLegend::spItems); // legend box shall not be selectable, only legend items
addRandomGraph();
addRandomGraph();
addRandomGraph();
addRandomGraph();
ui->customPlot->rescaleAxes();
// // connect slot that ties some axis selections together (especially opposite axes):
connect(ui->customPlot, SIGNAL(selectionChangedByUser()), this, SLOT(selectionChanged()));
// // connect slots that takes care that when an axis is selected, only that direction can be dragged and zoomed:
connect(ui->customPlot, SIGNAL(mousePress(QMouseEvent *)), this, SLOT(mousePress()));
connect(ui->customPlot, SIGNAL(mouseWheel(QWheelEvent *)), this, SLOT(mouseWheel()));
// make bottom and left axes transfer their ranges to top and right axes:
connect(ui->customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->xAxis2, SLOT(setRange(QCPRange)));
connect(ui->customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->yAxis2, SLOT(setRange(QCPRange)));
// connect some interaction slots:
connect(ui->customPlot, SIGNAL(axisDoubleClick(QCPAxis *, QCPAxis::SelectablePart, QMouseEvent *)), this, SLOT(axisLabelDoubleClick(QCPAxis *, QCPAxis::SelectablePart)));
connect(ui->customPlot, SIGNAL(legendDoubleClick(QCPLegend *, QCPAbstractLegendItem *, QMouseEvent *)), this, SLOT(legendDoubleClick(QCPLegend *, QCPAbstractLegendItem *)));
connect(title, SIGNAL(doubleClicked(QMouseEvent *)), this, SLOT(titleDoubleClick(QMouseEvent *)));
// connect slot that shows a message in the status bar when a graph is clicked:
connect(ui->customPlot, SIGNAL(plottableClick(QCPAbstractPlottable *, int, QMouseEvent *)), this, SLOT(graphClicked(QCPAbstractPlottable *, int)));
// setup policy and connect slot for context menu popup:
ui->customPlot->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->customPlot, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequest(QPoint)));
}
void frmInterAction::titleDoubleClick(QMouseEvent *event)
{
Q_UNUSED(event)
if (QCPTextElement *title = qobject_cast<QCPTextElement *>(sender())) {
// Set the plot title by double clicking on it
bool ok;
QString newTitle = QInputDialog::getText(this, "QCustomPlot example", "New plot title:", QLineEdit::Normal, title->text(), &ok);
if (ok) {
title->setText(newTitle);
ui->customPlot->replot();
}
}
}
void frmInterAction::axisLabelDoubleClick(QCPAxis *axis, QCPAxis::SelectablePart part)
{
// Set an axis label by double clicking on it
if (part == QCPAxis::spAxisLabel) { // only react when the actual axis label is clicked, not tick label or axis backbone
bool ok;
QString newLabel = QInputDialog::getText(this, "QCustomPlot example", "New axis label:", QLineEdit::Normal, axis->label(), &ok);
if (ok) {
axis->setLabel(newLabel);
ui->customPlot->replot();
}
}
}
void frmInterAction::legendDoubleClick(QCPLegend *legend, QCPAbstractLegendItem *item)
{
// Rename a graph by double clicking on its legend item
Q_UNUSED(legend)
if (item) { // only react if item was clicked (user could have clicked on border padding of legend where there is no item, then item is 0)
QCPPlottableLegendItem *plItem = qobject_cast<QCPPlottableLegendItem *>(item);
bool ok;
QString newName = QInputDialog::getText(this, "QCustomPlot example", "New graph name:", QLineEdit::Normal, plItem->plottable()->name(), &ok);
if (ok) {
plItem->plottable()->setName(newName);
ui->customPlot->replot();
}
}
}
void frmInterAction::selectionChanged()
{
/*
normally, axis base line, axis tick labels and axis labels are selectable separately, but we want
the user only to be able to select the axis as a whole, so we tie the selected states of the tick labels
and the axis base line together. However, the axis label shall be selectable individually.
The selection state of the left and right axes shall be synchronized as well as the state of the
bottom and top axes.
Further, we want to synchronize the selection of the graphs with the selection state of the respective
legend item belonging to that graph. So the user can select a graph by either clicking on the graph itself
or on its legend item.
*/
// make top and bottom axes be selected synchronously, and handle axis and tick labels as one selectable object:
if (ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis) || ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spTickLabels) ||
ui->customPlot->xAxis2->selectedParts().testFlag(QCPAxis::spAxis) || ui->customPlot->xAxis2->selectedParts().testFlag(QCPAxis::spTickLabels)) {
ui->customPlot->xAxis2->setSelectedParts(QCPAxis::spAxis | QCPAxis::spTickLabels);
ui->customPlot->xAxis->setSelectedParts(QCPAxis::spAxis | QCPAxis::spTickLabels);
}
// make left and right axes be selected synchronously, and handle axis and tick labels as one selectable object:
if (ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis) || ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spTickLabels) ||
ui->customPlot->yAxis2->selectedParts().testFlag(QCPAxis::spAxis) || ui->customPlot->yAxis2->selectedParts().testFlag(QCPAxis::spTickLabels)) {
ui->customPlot->yAxis2->setSelectedParts(QCPAxis::spAxis | QCPAxis::spTickLabels);
ui->customPlot->yAxis->setSelectedParts(QCPAxis::spAxis | QCPAxis::spTickLabels);
}
// synchronize selection of graphs with selection of corresponding legend items:
for (int i = 0; i < ui->customPlot->graphCount(); ++i) {
QCPGraph *graph = ui->customPlot->graph(i);
QCPPlottableLegendItem *item = ui->customPlot->legend->itemWithPlottable(graph);
if (item->selected() || graph->selected()) {
item->setSelected(true);
graph->setSelection(QCPDataSelection(graph->data()->dataRange()));
}
}
}
void frmInterAction::mousePress()
{
// if an axis is selected, only allow the direction of that axis to be dragged
// if no axis is selected, both directions may be dragged
if (ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis)) {
ui->customPlot->axisRect()->setRangeDrag(ui->customPlot->xAxis->orientation());
} else if (ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis)) {
ui->customPlot->axisRect()->setRangeDrag(ui->customPlot->yAxis->orientation());
} else {
ui->customPlot->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
}
}
void frmInterAction::mouseWheel()
{
// if an axis is selected, only allow the direction of that axis to be zoomed
// if no axis is selected, both directions may be zoomed
if (ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis)) {
ui->customPlot->axisRect()->setRangeZoom(ui->customPlot->xAxis->orientation());
} else if (ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis)) {
ui->customPlot->axisRect()->setRangeZoom(ui->customPlot->yAxis->orientation());
} else {
ui->customPlot->axisRect()->setRangeZoom(Qt::Horizontal | Qt::Vertical);
}
}
void frmInterAction::addRandomGraph()
{
int n = 50; // number of points in graph
double xScale = (std::rand() / (double)RAND_MAX + 0.5) * 2;
double yScale = (std::rand() / (double)RAND_MAX + 0.5) * 2;
double xOffset = (std::rand() / (double)RAND_MAX - 0.5) * 4;
double yOffset = (std::rand() / (double)RAND_MAX - 0.5) * 10;
double r1 = (std::rand() / (double)RAND_MAX - 0.5) * 2;
double r2 = (std::rand() / (double)RAND_MAX - 0.5) * 2;
double r3 = (std::rand() / (double)RAND_MAX - 0.5) * 2;
double r4 = (std::rand() / (double)RAND_MAX - 0.5) * 2;
QVector<double> x(n), y(n);
for (int i = 0; i < n; i++) {
x[i] = (i / (double)n - 0.5) * 10.0 * xScale + xOffset;
y[i] = (qSin(x[i] * r1 * 5) * qSin(qCos(x[i] * r2) * r4 * 3) + r3 * qCos(qSin(x[i]) * r4 * 2)) * yScale + yOffset;
}
ui->customPlot->addGraph();
ui->customPlot->graph()->setName(QString("New graph %1").arg(ui->customPlot->graphCount() - 1));
ui->customPlot->graph()->setData(x, y);
ui->customPlot->graph()->setLineStyle((QCPGraph::LineStyle)(std::rand() % 5 + 1));
if (std::rand() % 100 > 50) {
ui->customPlot->graph()->setScatterStyle(QCPScatterStyle((QCPScatterStyle::ScatterShape)(std::rand() % 14 + 1)));
}
QPen graphPen;
graphPen.setColor(QColor(std::rand() % 245 + 10, std::rand() % 245 + 10, std::rand() % 245 + 10));
graphPen.setWidthF(std::rand() / (double)RAND_MAX * 2 + 1);
ui->customPlot->graph()->setPen(graphPen);
ui->customPlot->replot();
}
void frmInterAction::removeSelectedGraph()
{
if (ui->customPlot->selectedGraphs().size() > 0) {
ui->customPlot->removeGraph(ui->customPlot->selectedGraphs().first());
ui->customPlot->replot();
}
}
void frmInterAction::removeAllGraphs()
{
ui->customPlot->clearGraphs();
ui->customPlot->replot();
}
void frmInterAction::contextMenuRequest(QPoint pos)
{
QMenu *menu = new QMenu(this);
menu->setAttribute(Qt::WA_DeleteOnClose);
if (ui->customPlot->legend->selectTest(pos, false) >= 0) { // context menu on legend requested
menu->addAction("Move to top left", this, SLOT(moveLegend()))->setData((int)(Qt::AlignTop | Qt::AlignLeft));
menu->addAction("Move to top center", this, SLOT(moveLegend()))->setData((int)(Qt::AlignTop | Qt::AlignHCenter));
menu->addAction("Move to top right", this, SLOT(moveLegend()))->setData((int)(Qt::AlignTop | Qt::AlignRight));
menu->addAction("Move to bottom right", this, SLOT(moveLegend()))->setData((int)(Qt::AlignBottom | Qt::AlignRight));
menu->addAction("Move to bottom left", this, SLOT(moveLegend()))->setData((int)(Qt::AlignBottom | Qt::AlignLeft));
} else { // general context menu on graphs requested
menu->addAction("Add random graph", this, SLOT(addRandomGraph()));
if (ui->customPlot->selectedGraphs().size() > 0) {
menu->addAction("Remove selected graph", this, SLOT(removeSelectedGraph()));
}
if (ui->customPlot->graphCount() > 0) {
menu->addAction("Remove all graphs", this, SLOT(removeAllGraphs()));
}
}
menu->popup(ui->customPlot->mapToGlobal(pos));
}
void frmInterAction::moveLegend()
{
if (QAction *contextAction = qobject_cast<QAction *>(sender())) { // make sure this slot is really called by a context menu action, so it carries the data we need
bool ok;
int dataInt = contextAction->data().toInt(&ok);
if (ok) {
ui->customPlot->axisRect()->insetLayout()->setInsetAlignment(0, (Qt::Alignment)dataInt);
ui->customPlot->replot();
}
}
}
void frmInterAction::graphClicked(QCPAbstractPlottable *plottable, int dataIndex)
{
// since we know we only have QCPGraphs in the plot, we can immediately access interface1D()
// usually it's better to first check whether interface1D() returns non-zero, and only then use it.
double dataValue = plottable->interface1D()->dataMainValue(dataIndex);
QString message = QString("Clicked on graph '%1' at data point #%2 with value %3.").arg(plottable->name()).arg(dataIndex).arg(dataValue);
//ui->statusBar->showMessage(message, 2500);
}

View File

@@ -0,0 +1,39 @@
#ifndef FRMINTERACTION_H
#define FRMINTERACTION_H
#include <QWidget>
#include <QInputDialog>
#include "qcustomplot.h"
namespace Ui {
class frmInterAction;
}
class frmInterAction : public QWidget
{
Q_OBJECT
public:
explicit frmInterAction(QWidget *parent = 0);
~frmInterAction();
private:
Ui::frmInterAction *ui;
private slots:
void initForm();
void titleDoubleClick(QMouseEvent *event);
void axisLabelDoubleClick(QCPAxis* axis, QCPAxis::SelectablePart part);
void legendDoubleClick(QCPLegend* legend, QCPAbstractLegendItem* item);
void selectionChanged();
void mousePress();
void mouseWheel();
void addRandomGraph();
void removeSelectedGraph();
void removeAllGraphs();
void contextMenuRequest(QPoint pos);
void moveLegend();
void graphClicked(QCPAbstractPlottable *plottable, int dataIndex);
};
#endif // FRMINTERACTION_H

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmInterAction</class>
<widget class="QWidget" name="frmInterAction">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCustomPlot" name="customPlot" native="true"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,80 @@
#include "frmscrollbar.h"
#include "ui_frmscrollbar.h"
#include "qdebug.h"
frmScrollBar::frmScrollBar(QWidget *parent) : QWidget(parent), ui(new Ui::frmScrollBar)
{
ui->setupUi(this);
this->initForm();
}
frmScrollBar::~frmScrollBar()
{
delete ui;
}
void frmScrollBar::initForm()
{
// The following plot setup is mostly taken from the plot demos:
ui->plot->addGraph();
ui->plot->graph()->setPen(QPen(Qt::blue));
ui->plot->graph()->setBrush(QBrush(QColor(0, 0, 255, 20)));
ui->plot->addGraph();
ui->plot->graph()->setPen(QPen(Qt::red));
QVector<double> x(500), y0(500), y1(500);
for (int i = 0; i < 500; ++i) {
x[i] = (i / 499.0 - 0.5) * 10;
y0[i] = qExp(-x[i] * x[i] * 0.25) * qSin(x[i] * 5) * 5;
y1[i] = qExp(-x[i] * x[i] * 0.25) * 5;
}
ui->plot->graph(0)->setData(x, y0);
ui->plot->graph(1)->setData(x, y1);
ui->plot->axisRect()->setupFullAxesBox(true);
ui->plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
// configure scroll bars:
// Since scroll bars only support integer values, we'll set a high default range of -500..500 and
// divide scroll bar position values by 100 to provide a scroll range -5..5 in floating point
// axis coordinates. if you want to dynamically grow the range accessible with the scroll bar,
// just increase the minimum/maximum values of the scroll bars as needed.
ui->horizontalScrollBar->setRange(-500, 500);
ui->verticalScrollBar->setRange(-500, 500);
// create connection between axes and scroll bars:
connect(ui->horizontalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(horzScrollBarChanged(int)));
connect(ui->verticalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(vertScrollBarChanged(int)));
connect(ui->plot->xAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(xAxisChanged(QCPRange)));
connect(ui->plot->yAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(yAxisChanged(QCPRange)));
// initialize axis range (and scroll bar positions via signals we just connected):
ui->plot->xAxis->setRange(0, 6, Qt::AlignCenter);
ui->plot->yAxis->setRange(0, 10, Qt::AlignCenter);
}
void frmScrollBar::horzScrollBarChanged(int value)
{
if (qAbs(ui->plot->xAxis->range().center() - value / 100.0) > 0.01) { // if user is dragging plot, we don't want to replot twice
ui->plot->xAxis->setRange(value / 100.0, ui->plot->xAxis->range().size(), Qt::AlignCenter);
ui->plot->replot();
}
}
void frmScrollBar::vertScrollBarChanged(int value)
{
if (qAbs(ui->plot->yAxis->range().center() + value / 100.0) > 0.01) { // if user is dragging plot, we don't want to replot twice
ui->plot->yAxis->setRange(-value / 100.0, ui->plot->yAxis->range().size(), Qt::AlignCenter);
ui->plot->replot();
}
}
void frmScrollBar::xAxisChanged(QCPRange range)
{
ui->horizontalScrollBar->setValue(qRound(range.center() * 100.0)); // adjust position of scroll bar slider
ui->horizontalScrollBar->setPageStep(qRound(range.size() * 100.0)); // adjust size of scroll bar slider
}
void frmScrollBar::yAxisChanged(QCPRange range)
{
ui->verticalScrollBar->setValue(qRound(-range.center() * 100.0)); // adjust position of scroll bar slider
ui->verticalScrollBar->setPageStep(qRound(range.size() * 100.0)); // adjust size of scroll bar slider
}

View File

@@ -0,0 +1,30 @@
#ifndef FRMSCROLLBAR_H
#define FRMSCROLLBAR_H
#include <QWidget>
#include "qcustomplot.h"
namespace Ui {
class frmScrollBar;
}
class frmScrollBar : public QWidget
{
Q_OBJECT
public:
explicit frmScrollBar(QWidget *parent = 0);
~frmScrollBar();
private:
Ui::frmScrollBar *ui;
private slots:
void initForm();
void horzScrollBarChanged(int value);
void vertScrollBarChanged(int value);
void xAxisChanged(QCPRange range);
void yAxisChanged(QCPRange range);
};
#endif // FRMSCROLLBAR_H

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmScrollBar</class>
<widget class="QWidget" name="frmScrollBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QCustomPlot" name="plot" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QScrollBar" name="verticalScrollBar">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QScrollBar" name="horizontalScrollBar">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>