# QCustomPlot鼠标跟随显示坐标值

tags: QCustomPlot hover


背景

Qt最大的优势就是各种库非常全,尤其在图表方面,在5.7版本之后虽然引入了原本企业版才有的QCharts,但相对于只有2个文件就可以引入库的QCustomPlot来说还是太臃肿了。
这里解决一个使用图表的都会碰到的问题–跟随鼠标显示值,在QCustomPlot里非常简单,它早就给出了解决方案-QCPItemTracer.可以直接看下面的效果图。

效果

几点重要概念

  1. QCPAbstractItem所有相关的类都是它的子类,可以是图片、文字、曲线等
  2. QCPItemPosition这个类表示的是位置的解析方式,理解很好理解,但实际用的时候很容易乱,具体看参考文献2

代码

跟随鼠标的样式里包含了文字、箭头、指示当前值的圆点,为了方便,构造一个类

class myTracer : public QObject
{
    Q_OBJECT
public:

    enum TracerType
    {
        XAxisTracer,
        YAxisTracer,
        DataTracer
    };

public:

    explicit myTracer(QCustomPlot *_plot, TracerType _type, QObject *parent = nullptr);
    ~myTracer();

    void setPen(const QPen &pen);
    void setBrush(const QBrush &brush);
    void setText(const QString &text);
    void setLabelPen(const QPen &pen);
    void updatePosition(double xValue, double yValue);

protected:
    void setVisible(bool visible);
protected:
    QCustomPlot *plot = nullptr;
    QCPItemTracer *tracer = nullptr;// 跟踪的点
    QCPItemText *label = nullptr;   // 显示的数值
    QCPItemLine *arrow = nullptr;   // 箭头

    TracerType type = DataTracer;
    bool visible = false;
};

myTracer::myTracer(QCustomPlot *_plot, TracerType _type, QObject *parent) : plot(_plot),
    type(_type),
    QObject(parent)
{
    if (plot)
    {
        tracer = new QCPItemTracer(plot);
        tracer->setStyle(QCPItemTracer::tsCircle);
        tracer->setPen(QPen(Qt::red));
        tracer->setBrush(Qt::red);
        tracer->setSize(10);

        label = new QCPItemText(plot);
        label->setLayer("overlay");
        label->setClipToAxisRect(false);
        label->setPadding(QMargins(5, 5, 5, 5));
        label->setBrush(QBrush(QColor(244, 244, 244, 100)));
        label->setPen(QPen(Qt::blue));
        label->position->setParentAnchor(tracer->position);
        label->setFont(QFont("宋体", 10));

        arrow = new QCPItemLine(plot);
        arrow->setLayer("overlay");
        arrow->setClipToAxisRect(false);
        arrow->setHead(QCPLineEnding::esSpikeArrow);

        switch (type) {
        case XAxisTracer:
        {
            tracer->position->setTypeX(QCPItemPosition::ptPlotCoords);
            tracer->position->setTypeY(QCPItemPosition::ptAxisRectRatio);

            label->setPositionAlignment(Qt::AlignTop|Qt::AlignHCenter);

            arrow->end->setParentAnchor(tracer->position);
            arrow->start->setParentAnchor(arrow->end);
            arrow->start->setCoords(20, 0);//偏移量
            break;
        }
        case YAxisTracer:
        {
            tracer->position->setTypeX(QCPItemPosition::ptAxisRectRatio);
            tracer->position->setTypeY(QCPItemPosition::ptPlotCoords);

            label->setPositionAlignment(Qt::AlignRight|Qt::AlignHCenter);

            arrow->end->setParentAnchor(tracer->position);
            arrow->start->setParentAnchor(label->position);
            arrow->start->setCoords(-20, 0);//偏移量
            break;
        }
        case DataTracer:
        {
            tracer->position->setTypeX(QCPItemPosition::ptPlotCoords);
            tracer->position->setTypeY(QCPItemPosition::ptPlotCoords);

            label->setPositionAlignment(Qt::AlignLeft|Qt::AlignVCenter);

            arrow->end->setParentAnchor(tracer->position);
            arrow->start->setParentAnchor(arrow->end);
            arrow->start->setCoords(25, 0);
            break;
        }

        default:
            break;
        }

        setVisible(false);
    }
}

myTracer::~myTracer()
{
    if (tracer)
        plot->removeItem(tracer);
    if (label)
        plot->removeItem(label);
}

void myTracer::setPen(const QPen &pen)
{
    tracer->setPen(pen);
    arrow->setPen(pen);
}

void myTracer::setBrush(const QBrush &brush)
{
    tracer->setBrush(brush);
}

void myTracer::setLabelPen(const QPen &pen)
{
    label->setPen(pen);
}

void myTracer::setText(const QString &text)
{
    label->setText(text);
}

void myTracer::setVisible(bool visible)
{
    tracer->setVisible(visible);
    label->setVisible(visible);
    arrow->setVisible(visible);
}

void myTracer::updatePosition(double xValue, double yValue)
{
    if (!visible)
    {
        setVisible(true);
        visible = true;
    }
    if (yValue > plot->yAxis->range().upper)
        yValue = plot->yAxis->range().upper;
    switch (type) {
    case XAxisTracer:
    {
        tracer->position->setCoords(xValue, 1);
        label->position->setCoords(0, 15);
        arrow->start->setCoords(0, 15);
        arrow->end->setCoords(0, 0);

        break;
    }
    case YAxisTracer:
    {
        tracer->position->setCoords(1, yValue);
        label->position->setCoords(-20, 0);
        break;
    }
    case DataTracer:
    {
        tracer->position->setCoords(xValue, yValue);
        label->position->setCoords(25, 0);
        break;
    }
    default:
        break;
    }
}

参考

  1. Creating dynamic axis tags using items
  2. QCustomplot使用分享(四) QCPAbstractItem

给个赏吧

如果我的文字解决了你的问题,请打个赏的,让我更有动力:)

你可能感兴趣的:(qt)