This is achieved by rewriting QChartView and inheriting the mousePressEvent and mouseMoveEvent functions to control the cursor length;
The environment used is QT5.14.2, and the package used is: MSVC2017 64bit, win10 system;
Above code:
//Chart display close to label
callout.h
#ifndef CALLOUT_H #define CALLOUT_H #include <QtCharts/QChartGlobal> #include <QtWidgets/QGraphicsItem> #include <QtGui/QFont> #include <QDebug> QT_BEGIN_NAMESPACE class QGraphicsSceneMouseEvent; QT_END_NAMESPACE QT_CHARTS_BEGIN_NAMESPACE class QChart; QT_CHARTS_END_NAMESPACE QT_CHARTS_USE_NAMESPACE class Callout: public QGraphicsItem {<!-- --> public: Callout(QChart *parent); void setText(const QString & amp;text); void setAnchor(QPointF point); void updateGeometry(); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget); protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); private: QString m_text; QRectF m_textRect; QRectF m_rect; QPointF m_anchor; QFont m_font; QChart *m_chart; }; #endif // CALLOUT_H
callout.h
#include "callout.h" #include <QtGui/QPainter> #include <QtGui/QFontMetrics> #include <QtWidgets/QGraphicsSceneMouseEvent> #include <QtGui/QMouseEvent> #include <QtCharts/QChart> Callout::Callout(QChart *chart): QGraphicsItem(chart), m_chart(chart) {<!-- --> } QRectF Callout::boundingRect() const {<!-- --> QPointF anchor = mapFromParent(m_chart->mapToPosition(m_anchor)); QRectFrect; rect.setLeft(qMin(m_rect.left(), anchor.x())); rect.setRight(qMax(m_rect.right(), anchor.x())); rect.setTop(qMin(m_rect.top(), anchor.y())); rect.setBottom(qMax(m_rect.bottom(), anchor.y())); return rect; } void Callout::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {<!-- --> Q_UNUSED(option) Q_UNUSED(widget) QPainterPath path; path.addRoundedRect(m_rect, 5, 5); QPointF anchor = mapFromParent(m_chart->mapToPosition(m_anchor)); qDebug()<<"\t\t\t anchor = "<<anchor; if (!m_rect.contains(anchor)) {<!-- --> QPointF point1, point2; // establish the position of the anchor point in relation to m_rect bool above = anchor.y() <= m_rect.top(); bool aboveCenter = anchor.y() > m_rect.top() & amp; & amp; anchor.y() <= m_rect.center().y(); bool belowCenter = anchor.y() > m_rect.center().y() & amp; & amp; anchor.y() <= m_rect.bottom(); bool below = anchor.y() > m_rect.bottom(); bool onLeft = anchor.x() <= m_rect.left(); bool leftOfCenter = anchor.x() > m_rect.left() & amp; & amp; anchor.x() <= m_rect.center().x(); bool rightOfCenter = anchor.x() > m_rect.center().x() & amp; & amp; anchor.x() <= m_rect.right(); bool onRight = anchor.x() > m_rect.right(); // get the nearest m_rect corner. qreal x = (onRight + rightOfCenter) * m_rect.width(); qreal y = (below + belowCenter) * m_rect.height(); bool cornerCase = (above & amp; & amp; onLeft) || (above & amp; & amp; onRight) || (below & amp; & amp; onLeft) || (below & amp; & amp; onRight); bool vertical = qAbs(anchor.x() - x) > qAbs(anchor.y() - y); qreal x1 = x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCase * !vertical * (onLeft * 10 - onRight * 20); qreal y1 = y + aboveCenter * 10 - belowCenter * 20 + cornerCase * vertical * (above * 10 - below * 20);; point1.setX(x1); point1.setY(y1); qreal x2 = x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCase * !vertical * (onLeft * 20 - onRight * 10);; qreal y2 = y + aboveCenter * 20 - belowCenter * 10 + cornerCase * vertical * (above * 20 - below * 10);; point2.setX(x2); point2.setY(y2); path.moveTo(point1); path.lineTo(anchor); path.lineTo(point2); path = path.simplified(); } painter->setBrush(QColor(255, 255, 255)); painter->drawPath(path); painter->drawText(m_textRect, m_text); } void Callout::mousePressEvent(QGraphicsSceneMouseEvent *event) {<!-- --> event->setAccepted(true); } void Callout::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {<!-- --> if (event->buttons() & amp; Qt::LeftButton){<!-- --> setPos(mapToParent(event->pos() - event->buttonDownPos(Qt::LeftButton))); event->setAccepted(true); } else {<!-- --> event->setAccepted(false); } } void Callout::setText(const QString & amp;text) {<!-- --> m_text = text; QFontMetrics metrics(m_font); m_textRect = metrics.boundingRect(QRect(0, 0, 150, 150), Qt::AlignLeft, m_text); m_textRect.translate(5, 5); prepareGeometryChange(); m_rect = m_textRect.adjusted(-5, -5, 5, 5); } void Callout::setAnchor(QPointF point) {<!-- --> m_anchor = point; } void Callout::updateGeometry() {<!-- --> prepareGeometryChange(); setPos(m_chart->mapToPosition(m_anchor) + QPoint(10, -50)); }
//Rewritten QChartView class
mychartview_mp.h
#ifndef MYCHARTVIEW_MP_H #defineMYCHARTVIEW_MP_H #include <QDebug> #include <QtCharts/QChartView> #include <QtCharts/QPieSeries> #include <QtCharts/QPieSlice> #include <QtCharts/QAbstractBarSeries> #include <QtCharts/QPercentBarSeries> #include <QtCharts/QStackedBarSeries> #include <QtCharts/QBarSeries> #include <QtCharts/QBarSet> #include <QtCharts/QLineSeries> #include <QtCharts/QSplineSeries> #include <QtCharts/QScatterSeries> #include <QtCharts/QAreaSeries> #include <QtCharts/QLegend> #include <QtWidgets/QGridLayout> #include <QtWidgets/QFormLayout> #include <QtWidgets/QComboBox> #include <QtWidgets/QSpinBox> #include <QtWidgets/QCheckBox> #include <QtWidgets/QGroupBox> #include <QtWidgets/QLabel> #include <QtCore/QRandomGenerator> #include <QtCharts/QBarCategoryAxis> #include <QtWidgets/QApplication> #include <QtCharts/QValueAxis> #include "callout.h" QT_BEGIN_NAMESPACE namespace Ui {<!-- --> class MainWindow; } QT_END_NAMESPACE QT_BEGIN_NAMESPACE class QComboBox; class QCheckBox; class Ui_ThemeWidgetForm; QT_END_NAMESPACE QT_CHARTS_BEGIN_NAMESPACE class QChartView; class QChart; //class myChartViewPrivate; QT_CHARTS_END_NAMESPACE QT_CHARTS_USE_NAMESPACE class myChartView_mp : public QChartView {<!-- --> Q_OBJECT public: //explicit myChartView(QWidget *parent = nullptr); myChartView_mp(QWidget *parent = nullptr); ~myChartView_mp(); //Text annotation Callout *pcal; protected: //mouse event void mousePressEvent(QMouseEvent *event) override; //void mouseDoubleClickEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; private: Q_DISABLE_COPY(myChartView_mp) QGraphicsLineItem x_line; QGraphicsLineItem y_line; int x_b; int x_e; int y_b; int y_e; QPointF pot; public slots: void tooltip(QPointF point, bool state); }; #endif // MYCHARTVIEW_MP_H
mychartview_mp.cpp
#include "mychartview_mp.h" myChartView_mp::myChartView_mp(QWidget *parent) : QChartView(parent) {<!-- --> QPen redPen(QColor( 159, 252, 253 )); redPen.setWidth(1); x_line.setPen(redPen); x_line.setZValue(2); y_line.setPen(redPen); y_line.setZValue(2); this->scene()->addItem( & amp;x_line); this->scene()->addItem( & y_line); } myChartView_mp::~myChartView_mp() {<!-- --> } //Mouse press event void myChartView_mp::mousePressEvent(QMouseEvent *event) {<!-- --> QChartView::mousePressEvent(event); } void myChartView_mp::mouseMoveEvent(QMouseEvent *event) {<!-- --> pot = event->pos(); x_b = this->chart()->plotArea().x(); x_e = x_b + this->chart()->plotArea().width(); y_b = this->chart()->plotArea().y(); y_e = y_b + this->chart()->plotArea().height(); if ((pot.rx() < x_b) || (pot.rx() > x_e) || (pot.ry() < y_b) || (pot.ry() > y_e)) {<!-- --> x_line.setVisible(false); y_line.setVisible(false); return; } x_line.setVisible(true); y_line.setVisible(true); //Call the overridden method of the parent class. This line of program is different from e->ignore(). Ignore continues to pass the event to the parent control (generally the parent control is the UI interface) instead of passing it to the parent class. QChartView::mouseMoveEvent(event); x_line.setLine(pot.rx(),y_b,pot.rx(),y_e); y_line.setLine(x_b,pot.ry(),x_e,pot.ry()); QPointF pp1 = this->chart()->mapToValue(pot); //qDebug()<<"x = "<<pot.rx()<<"y = "<<pot.ry()<<QDateTime::fromMSecsSinceEpoch(pp1.rx())<< pp1.ry(); //this->chart()->mapToScene(pot); //pcal->setText(QString("X: %1 \\ Y: %2 ").arg(pot.rx()).arg(pot.ry())); //pcal->setAnchor(QPoint(pot.rx(),pot.ry())); //pcal->show(); } void myChartView_mp::tooltip(QPointF point, bool state) {<!-- --> if(state) {<!-- --> pcal = new Callout(this->chart()); pcal->setText(QString("X: %1 \\ Y: %2 ").arg(point.x()).arg(point.y())); pcal->setAnchor(point); pcal->setZValue(11); pcal->updateGeometry(); pcal->show(); //qDebug()<<"\t\t[tooltip]"<<point.x()<<point.y()<<this->chart(); } else {<!-- --> pcal->hide(); } }
//Main window
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtCharts> #include "mychartview_mp.h" QT_BEGIN_NAMESPACE namespace Ui {<!-- --> class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow {<!-- --> Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) {<!-- --> ui->setupUi(this); //Create a series of points for the curve QSplineSeries *plSer = new QSplineSeries(); plSer->setName("curve"); // double xx[100] = {6.91,12.79,20.63,28.47,38.27,44.15,51.99,59.83,67.67,73.55,81.39,89.23,97.07,104.91,112.75,122.55,128.43,134.31,1 42.15,148.03, // 157.83,165.67,171.55,181.35,187.23,193.11,202.91,212.71,218.59,226.43,234.27,240.15,249.95,253.87,263.67,273.47,281.31,287 .19,293.07,300.91, // 306.79,318.55,326.39,334.23,336.19,349.91,355.79,363.63,369.51,373.43,385.19,387.15,400.87,408.71,416.55,422.43,428.31,438 .11,442.03,447.91, // 461.63,469.47,475.35,481.23,492.99,498.87,508.67,516.51,518.47,530.23,538.07,541.99,551.79,559.63,565.51,567.47,579.23,590 .99,596.87,602.75, // 610.59,620.39,624.31,636.07,638.03,651.75,657.63,661.55,673.31,681.15,687.03,690.95,700.75,708.59,718.39,726.23,730.15,739 .95,751.71,755.63}; // double yy[100]; // for (int i = 1;i < 101;i + + ) // {<!-- --> // yy[i - 1] = i * 100.00; // plSer->append(yy[i - 1],xx[i - 1]); // } double xx[9] = {<!-- -->150.03,163.517,197.535,221.18,231.506,285.653,284.863,362.173,481.254}; double yy[9] = {<!-- -->90.0,100.0,120.0,140.0,150.0,180.0,200.0,220.0,300.0}; for (int i = 0;i < 9;i + + ) {<!-- --> plSer->append(yy[i],xx[i]); } //Create chart object QChart *pqchar = new QChart(); pqchar->legend()->hide(); pqchar->addSeries(plSer); // pqchar->setTitle(QString::fromLocal8Bit("curve")); pqchar->setTitle("112343"); pqchar->createDefaultAxes(); pqchar->axisY()->setRange(0,500); //QChartView * pview = new QChartView(pqchar); myChartView_mp * pview = new myChartView_mp(); pview->setChart(pqchar); pview->setRenderHint(QPainter::Antialiasing); ui->horizontalLayout->addWidget(pview); connect(plSer, & amp;QLineSeries::hovered, pview, & amp;myChartView_mp::tooltip); } MainWindow::~MainWindow() {<!-- --> delete ui; }
main.cpp
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) {<!-- --> QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
The above content refers to the content of at least two netizens. It has been too long and I have forgotten which one it is. I would like to express my gratitude!