ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

QCustomPlot之鼠标悬浮显示值

2020-07-03 10:35:45  阅读:441  来源: 互联网

标签:QCPToolTip const 鼠标 悬浮 graph void QCustomPlot double Qt


参考:https://www.jianshu.com/p/9f2763469030

使用到qcustomplot,想在鼠标停在某个点时,显示该点的值。从网上找到例子,加入到工程中。

qcustomplot源码下载:https://www.qcustomplot.com/index.php/download

工程中,点击按钮调出对话框,在对话框中显示折线。

对话框类

DlgPlot1.h

#ifndef DLGPLOT1_H
#define DLGPLOT1_H

#include <QDialog>
#include "qcustomplot.h"
#include "CustomPlotTooltip.h"

namespace Ui {
class DlgPlot1;
}

class DlgPlot1 : public QDialog
{
    Q_OBJECT

public:
    explicit DlgPlot1(QWidget *parent = nullptr);
    ~DlgPlot1();

public:

private:
    void setupScatterStyleDemo(QCustomPlot *customPlot);
private slots:
    void on_btnRefresh_clicked();
private:
    Ui::DlgPlot1 *ui;
    QCPToolTip* m_pCpTip;
};

#endif // DLGPLOT1_H

DlgPlot1.cpp

 1 #include "DlgPlot1.h"
 2 #include "ui_DlgPlot1.h"
 3 #include "CustomPlotTooltip.h"
 4 
 5 DlgPlot1::DlgPlot1(QWidget *parent) :
 6     QDialog(parent),
 7     ui(new Ui::DlgPlot1)
 8 {
 9     ui->setupUi(this);
10     QString demoName = "Scatter Style Demo";
11     this->setWindowTitle(demoName);
12     setupScatterStyleDemo(ui->customPlot);
13 
14     m_pCpTip = new QCPToolTip(ui->customPlot);
15 }
16 
17 DlgPlot1::~DlgPlot1()
18 {
19     delete ui;
20 }
21 
22 void DlgPlot1::on_btnRefresh_clicked()
23 {
24 
25 }
26 
27 void DlgPlot1::setupScatterStyleDemo(QCustomPlot *customPlot)
28 {
29     customPlot->legend->setVisible(true);
30     customPlot->legend->setFont(QFont("Helvetica", 9));
31     customPlot->legend->setRowSpacing(-3);
32     QVector<QCPScatterStyle::ScatterShape> shapes;
33     QVector<QColor> colors;
34     colors << Qt::blue;
35     colors << Qt::red;
36     colors << Qt::green;
37 //    shapes << QCPScatterStyle::ssCross;
38 //    shapes << QCPScatterStyle::ssPlus;
39 //    shapes << QCPScatterStyle::ssCircle;
40     shapes << QCPScatterStyle::ssDisc;
41     shapes << QCPScatterStyle::ssDisc;
42 //    shapes << QCPScatterStyle::ssSquare;
43 //    shapes << QCPScatterStyle::ssDiamond;
44 //    shapes << QCPScatterStyle::ssStar;
45 //    shapes << QCPScatterStyle::ssTriangle;
46 //    shapes << QCPScatterStyle::ssTriangleInverted;
47 //    shapes << QCPScatterStyle::ssCrossSquare;
48 //    shapes << QCPScatterStyle::ssPlusSquare;
49 //    shapes << QCPScatterStyle::ssCrossCircle;
50 //    shapes << QCPScatterStyle::ssPlusCircle;
51 //    shapes << QCPScatterStyle::ssPeace;
52 //    shapes << QCPScatterStyle::ssCustom;
53 //    shapes << QCPScatterStyle::ssDot;
54 
55     QPen pen;
56     // add graphs with different scatter styles:
57     for (int i=0; i<shapes.size(); ++i)
58     {
59       customPlot->addGraph();
60       pen.setColor(colors.at(i));
61       // generate data:
62       QVector<double> x, y;
63       if(i == 0){
64           x  << 2005 << 2006 << 2007 << 2008  << 2009  << 2010 << 2011;
65           y << 2.17 << 3.42 << 4.94 << 10.38 << 15.86 << 29.33 << 52.1;
66       }
67       else if(i == 1){
68           x  << 2005 << 2006 << 2007 << 2008  << 2009  << 2010 << 2011;
69           y << 2 << 9 << 6 << 15 << 89 << 11 << 20;
70       }
71       customPlot->graph()->setData(x, y);
72       customPlot->graph()->rescaleAxes(true);
73       customPlot->graph()->setPen(pen);
74       customPlot->graph()->setName(QCPScatterStyle::staticMetaObject.enumerator(QCPScatterStyle::staticMetaObject.indexOfEnumerator("ScatterShape")).valueToKey(shapes.at(i)));
75       customPlot->graph()->setLineStyle(QCPGraph::lsLine);
76       // set scatter style:
77       if (shapes.at(i) != QCPScatterStyle::ssCustom)
78       {
79         customPlot->graph()->setScatterStyle(QCPScatterStyle(shapes.at(i), 10));
80       }
81       else
82       {
83         QPainterPath customScatterPath;
84         for (int i=0; i<3; ++i)
85           customScatterPath.cubicTo(qCos(2*M_PI*i/3.0)*9, qSin(2*M_PI*i/3.0)*9, qCos(2*M_PI*(i+0.9)/3.0)*9, qSin(2*M_PI*(i+0.9)/3.0)*9, 0, 0);
86         customPlot->graph()->setScatterStyle(QCPScatterStyle(customScatterPath, QPen(Qt::black, 0), QColor(255, 255, 255, 50), 10));
87       }
88     }
89 
90     // set blank axis lines:
91     customPlot->rescaleAxes();
92     customPlot->xAxis->setTicks(true);
93     customPlot->yAxis->setTicks(true);
94     customPlot->xAxis->setTickLabels(true);
95     customPlot->yAxis->setTickLabels(true);
96     // make top right axes clones of bottom left axes:
97     customPlot->axisRect()->setupFullAxesBox();
98 }

DlgPlot1.ui

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <ui version="4.0">
 3  <class>DlgPlot1</class>
 4  <widget class="QDialog" name="DlgPlot1">
 5   <property name="geometry">
 6    <rect>
 7     <x>0</x>
 8     <y>0</y>
 9     <width>400</width>
10     <height>300</height>
11    </rect>
12   </property>
13   <property name="windowTitle">
14    <string>Dialog</string>
15   </property>
16   <layout class="QGridLayout" name="gridLayout">
17    <item row="0" column="0" colspan="2">
18     <widget class="QCustomPlot" name="customPlot" native="true"/>
19    </item>
20    <item row="1" column="0">
21     <spacer name="horizontalSpacer">
22      <property name="orientation">
23       <enum>Qt::Horizontal</enum>
24      </property>
25      <property name="sizeHint" stdset="0">
26       <size>
27        <width>293</width>
28        <height>20</height>
29       </size>
30      </property>
31     </spacer>
32    </item>
33    <item row="1" column="1">
34     <widget class="QPushButton" name="btnRefresh">
35      <property name="text">
36       <string>刷  新</string>
37      </property>
38     </widget>
39    </item>
40   </layout>
41  </widget>
42  <customwidgets>
43   <customwidget>
44    <class>QCustomPlot</class>
45    <extends>QWidget</extends>
46    <header location="global">qcustomplot.h</header>
47    <container>1</container>
48   </customwidget>
49  </customwidgets>
50  <resources/>
51  <connections/>
52 </ui>

CustomPlotTooltip.h

 1 #ifndef CUSTOMPLOTTOOLTIP_H
 2 #define CUSTOMPLOTTOOLTIP_H
 3 #include "qcustomplot.h"
 4 
 5 class QCPToolTip : public QCPAbstractItem
 6 {
 7     Q_OBJECT
 8 public:
 9     explicit QCPToolTip(QCustomPlot *parentPlot);
10 
11     void setText(const QString &text);
12     void setFont(const QFont &font);
13     void setTextColor(const QColor &color);
14     void setBorderPen(const QPen &pen);
15     void setBrush(const QBrush &brush);
16     void setRadius(double xRadius, double yRadius, Qt::SizeMode mode = Qt::AbsoluteSize);
17     void setOffset(double xOffset, double yOffset);
18     void setPadding(const QMargins &paddings);
19 
20     Q_SLOT void handleTriggerEvent(QMouseEvent *event);
21     void updatePosition(const QPointF &newPos, bool replot = false);
22 
23     void update();
24 
25     virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const Q_DECL_OVERRIDE;
26 
27     QCPItemPosition * const position;
28 protected:
29     bool mPlotReplot;    // 表明是由QCustomPlot刷新的,需要更新位置
30     QString mText;
31     Qt::Alignment mTextAlignment;
32     QFont mFont;
33     QColor mTextColor;
34     QPen mBorderPen;
35     QBrush mBrush;
36 
37     QPointF mRadius;
38     Qt::SizeMode mSizeMode;
39 
40     QPointF mOffset;     // 偏移鼠标的距离
41     QMargins mPadding;
42 
43     QCPGraph *mHighlightGraph;
44     QPointF mGraphDataPos;
45 
46     virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE;
47     virtual void drawGraphScatterPlot(QCPPainter *painter, QCPGraph *graph, const QPointF &pos);
48 
49     int pickClosest(double target, const QVector<double> &vector);
50 };
51 #endif // CUSTOMPLOTTOOLTIP_H

CustomPlotTooltip.cpp

  1 #include "CustomPlotTooltip.h"
  2 #include <QToolTip>
  3 #include <QCursor>
  4 
  5 QCPToolTip::QCPToolTip(QCustomPlot *parentPlot)
  6     : QCPAbstractItem(parentPlot),
  7       position(createPosition(QLatin1String("position"))),
  8       mPlotReplot(true),
  9       mTextAlignment(Qt::AlignLeft | Qt::AlignVCenter),
 10       mRadius(6, 6),
 11       mSizeMode(Qt::AbsoluteSize),
 12       mHighlightGraph(nullptr)
 13 {
 14     position->setType(QCPItemPosition::ptAbsolute);
 15     setSelectable(false);
 16     setLayer("overlay");
 17 
 18     setBorderPen(Qt::NoPen);
 19     setBrush(QColor(87, 98, 93, 180));
 20     setTextColor(Qt::white);
 21     setOffset(10, 0);
 22     setPadding(QMargins(6, 6, 6, 6));
 23     connect(mParentPlot, SIGNAL(mouseMove(QMouseEvent *)), this, SLOT(handleTriggerEvent(QMouseEvent *)));
 24 }
 25 
 26 void QCPToolTip::setText(const QString &text)
 27 {
 28     mText = text;
 29 //    QToolTip::showText(mParentPlot->cursor().pos(), text, mParentPlot);
 30 }
 31 
 32 void QCPToolTip::setFont(const QFont &font)
 33 {
 34     mFont = font;
 35 }
 36 
 37 void QCPToolTip::setTextColor(const QColor &color)
 38 {
 39     mTextColor = color;
 40 }
 41 
 42 void QCPToolTip::setBorderPen(const QPen &pen)
 43 {
 44     mBorderPen = pen;
 45 }
 46 
 47 void QCPToolTip::setBrush(const QBrush &brush)
 48 {
 49     mBrush = brush;
 50 }
 51 
 52 void QCPToolTip::setRadius(double xRadius, double yRadius, Qt::SizeMode mode)
 53 {
 54     mRadius.setX(xRadius);
 55     mRadius.setY(yRadius);
 56     mSizeMode = mode;
 57 }
 58 
 59 void QCPToolTip::setOffset(double xOffset, double yOffset)
 60 {
 61     mOffset.setX(xOffset);
 62     mOffset.setY(yOffset);
 63 }
 64 
 65 void QCPToolTip::setPadding(const QMargins &paddings)
 66 {
 67     mPadding = paddings;
 68 }
 69 
 70 void QCPToolTip::handleTriggerEvent(QMouseEvent *event)
 71 {
 72     updatePosition(event->pos(), true);   // true 表示需要单独刷新,将调用update函数
 73 }
 74 
 75 void QCPToolTip::update()
 76 {
 77     mPlotReplot = false;    // 表明单独刷新
 78     layer()->replot();
 79     mPlotReplot = true;    // 单独刷新完毕
 80 }
 81 
 82 // 不需要鼠标点击测试,因为ToolTip是跟随鼠标的,鼠标点击不到
 83 double QCPToolTip::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
 84 {
 85     Q_UNUSED(pos)
 86     Q_UNUSED(onlySelectable)
 87     Q_UNUSED(details)
 88     return -1;
 89 }
 90 
 91 int QCPToolTip::pickClosest(double target, const QVector<double> &vector)
 92 {
 93     if (vector.size() < 2)
 94         return 0;
 95 
 96     // 查找第一个大于或等于target的位置
 97     auto it = std::lower_bound(vector.constBegin(), vector.constEnd(), target);
 98 
 99     if (it == vector.constEnd()) return vector.size() - 1;
100     else if (it == vector.constBegin()) return 0;
101     else return target - *(it - 1) < *it - target ? (it - vector.constBegin() - 1): (it - vector.constBegin());
102 }
103 
104 void QCPToolTip::updatePosition(const QPointF &newPos, bool replot)
105 {
106     mHighlightGraph = nullptr;
107     double tolerance = mParentPlot->selectionTolerance();
108 
109     for (int i = mParentPlot->graphCount() - 1; i >= 0; --i) {
110         QCPGraph *graph = mParentPlot->graph(i);
111         if (!graph->realVisibility() || graph->scatterStyle().isNone())   // graph不可见或者scatter style 为空的时候,不显示ToolTip
112             continue;
113 
114         double limitDistance = tolerance;   // limitDistance 用于选择的范围
115         double penWidth = graph->pen().widthF();
116         QCPScatterStyle scatterStyle = graph->scatterStyle();
117 
118         limitDistance = qMax(scatterStyle.size(), tolerance);
119         penWidth = scatterStyle.isPenDefined() ? scatterStyle.pen().widthF() : penWidth;
120 
121         QVariant details;
122         double currentDistance = graph->selectTest(newPos, false, &details);   // details会返回最接近的一个数据点,selectTest是不精确的,所以后面还要判断
123 
124         QCPDataSelection selection = details.value<QCPDataSelection>();
125         if (currentDistance >= 0 && currentDistance < limitDistance + penWidth && !selection.isEmpty()) {
126             // 取出当前key和value值,并且转换为像素位置
127             double key = graph->dataMainKey(selection.dataRange().begin());
128             double value = graph->dataMainValue(selection.dataRange().begin());
129             QPointF pos = graph->coordsToPixels(key, value);
130 
131             QRectF rect(pos.x() - limitDistance * 0.5, pos.y() - limitDistance * 0.5, limitDistance, limitDistance);
132             rect = rect.adjusted(-penWidth, -penWidth, penWidth, penWidth);
133 
134             if (rect.contains(newPos)) {    // 通过矩形判断,鼠标位置是否在数据点上
135 //                // 解开以下注释,可以使得我们的文字跟轴标签的文字是一样的(但跟轴标签实际的显示效果可能是不一样的,这里要注意,例如对于科学计数法,轴可能会使用美化),同时要注意当轴标签不显示的时候tickVectorLabels返回的是空的,所以我们要做一下判断
136 //                // 注意这里的方式是不精确的,适用于文字轴这种类型的
137 //                int keyIndex = pickClosest(key, graph->keyAxis()->tickVector());
138 //                setText(QString("%1:%2").arg(graph->keyAxis()->tickVectorLabels().at(keyIndex),
139 //                                         QString::number(value)));
140                 setText(QString("%1:%2").arg(QString::number(key), QString::number(value)));
141                 mHighlightGraph = graph;
142                 mGraphDataPos = pos;
143 
144                 mParentPlot->setCursor(Qt::PointingHandCursor);
145                 position->setPixelPosition(newPos);  // 更新位置
146                 setVisible(true);
147 
148                 if (replot) update();
149                 break;
150             }
151         }
152     }
153 
154     if (!mHighlightGraph && visible()) {
155         mParentPlot->setCursor(Qt::ArrowCursor);
156         setVisible(false);
157         if (replot) update();
158     }
159 }
160 
161 void QCPToolTip::draw(QCPPainter *painter)
162 {
163     if (mPlotReplot) {  // 当前是由QCustomPlot的replot函数刷新的,所以要更新位置
164         updatePosition(position->pixelPosition(), false);  // 传入false表明不刷新
165         if (!visible()) return;   // 由于位置更新之后,ToolTip可能会隐藏掉了,所以此处直接返回
166     }
167 
168     drawGraphScatterPlot(painter, mHighlightGraph, mGraphDataPos);
169 
170     QPointF pos = position->pixelPosition() + mOffset;
171     painter->translate(pos);  // 移动painter的绘制原点位置
172 
173     QFontMetrics fontMetrics(mFont);
174     QRect textRect = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip | mTextAlignment, mText);
175     textRect.moveTopLeft(QPoint(mPadding.left(), mPadding.top()));
176 
177     QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom());
178     textBoxRect.moveTopLeft(QPoint());
179 
180     // 限制ToolTip不超过QCustomPlot的范围
181     if (pos.x() + textBoxRect.width() >= mParentPlot->viewport().right())
182         painter->translate(-mOffset.x() * 2 - textBoxRect.width(), 0);
183     if (pos.y() + textBoxRect.height() * 2 >= mParentPlot->viewport().bottom())
184         painter->translate(0, -mOffset.y() * 2 - textBoxRect.height());
185 
186     // 绘制背景和边框
187     if ((mBrush != Qt::NoBrush && mBrush.color().alpha() != 0) ||
188             (mBorderPen != Qt::NoPen && mBorderPen.color().alpha() != 0)) {
189         double clipPad = mBorderPen.widthF();
190         QRect boundingRect = textBoxRect.adjusted(-clipPad, -clipPad, clipPad, clipPad);
191 
192         painter->setPen(mBorderPen);
193         painter->setBrush(mBrush);
194         painter->drawRoundedRect(boundingRect, mRadius.x(), mRadius.y(), mSizeMode);
195     }
196 
197     // 绘制文字
198     painter->setFont(mFont);
199     painter->setPen(mTextColor);
200     painter->setBrush(Qt::NoBrush);
201     painter->drawText(textRect, Qt::TextDontClip | mTextAlignment, mText);
202 }
203 
204 void QCPToolTip::drawGraphScatterPlot(QCPPainter *painter, QCPGraph *graph, const QPointF &pos)
205 {
206     if (!graph) return;
207 
208     QCPScatterStyle style = graph->scatterStyle();
209     if (style.isNone()) return;
210 
211     if (graph->selectionDecorator())  // 如果有select decorator,则使用修饰器的风格
212         style = graph->selectionDecorator()->getFinalScatterStyle(style);
213 
214     style.applyTo(painter, graph->pen());
215     style.setSize(style.size() * 1.2); // 放大一点
216     style.drawShape(painter, pos);
217 }

 

标签:QCPToolTip,const,鼠标,悬浮,graph,void,QCustomPlot,double,Qt
来源: https://www.cnblogs.com/warmlight/p/13228911.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有