项目中需要实现实时曲线的多Y轴实现,对比了qwt和 qcustomplot,觉得后者用起来更简单些,简单记录下:
效果如下
核心代码如下:
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;
};
cpp
#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(true);
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);
mDummyTracer->setStyle(QCPItemTracer::tsCircle);
mDummyTracer->setSize(10);
// 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)
{
mDummyTracer->setPen(pen);
mArrow->setPen(pen);
mLabel->setPen(pen);
}
void AxisTag::setBrush(const QBrush &brush)
{
mDummyTracer->setBrush(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