新增超级曲线图表
This commit is contained in:
112
third/qcustomplotdemo/frmexample2/axistag.cpp
Normal file
112
third/qcustomplotdemo/frmexample2/axistag.cpp
Normal 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);
|
||||
}
|
||||
60
third/qcustomplotdemo/frmexample2/axistag.h
Normal file
60
third/qcustomplotdemo/frmexample2/axistag.h
Normal 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
|
||||
67
third/qcustomplotdemo/frmexample2/frmaxistag.cpp
Normal file
67
third/qcustomplotdemo/frmexample2/frmaxistag.cpp
Normal 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();
|
||||
}
|
||||
34
third/qcustomplotdemo/frmexample2/frmaxistag.h
Normal file
34
third/qcustomplotdemo/frmexample2/frmaxistag.h
Normal 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
|
||||
32
third/qcustomplotdemo/frmexample2/frmaxistag.ui
Normal file
32
third/qcustomplotdemo/frmexample2/frmaxistag.ui
Normal 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>
|
||||
16
third/qcustomplotdemo/frmexample2/frmexample2.pri
Normal file
16
third/qcustomplotdemo/frmexample2/frmexample2.pri
Normal 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
|
||||
266
third/qcustomplotdemo/frmexample2/frminteraction.cpp
Normal file
266
third/qcustomplotdemo/frmexample2/frminteraction.cpp
Normal 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);
|
||||
}
|
||||
39
third/qcustomplotdemo/frmexample2/frminteraction.h
Normal file
39
third/qcustomplotdemo/frmexample2/frminteraction.h
Normal 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
|
||||
32
third/qcustomplotdemo/frmexample2/frminteraction.ui
Normal file
32
third/qcustomplotdemo/frmexample2/frminteraction.ui
Normal 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>
|
||||
80
third/qcustomplotdemo/frmexample2/frmscrollbar.cpp
Normal file
80
third/qcustomplotdemo/frmexample2/frmscrollbar.cpp
Normal 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
|
||||
}
|
||||
30
third/qcustomplotdemo/frmexample2/frmscrollbar.h
Normal file
30
third/qcustomplotdemo/frmexample2/frmscrollbar.h
Normal 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
|
||||
53
third/qcustomplotdemo/frmexample2/frmscrollbar.ui
Normal file
53
third/qcustomplotdemo/frmexample2/frmscrollbar.ui
Normal 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>
|
||||
Reference in New Issue
Block a user