Qt篇——QChartView实现鼠标滚轮缩放、鼠标拖拽平移、鼠标双击重置缩放平移、曲线点击显示坐标
话不多说。
第一步:自定义QChartView,直接搬
FirtCurveChartView.h
#ifndef FITCURVECHARTVIEW_H
#define FITCURVECHARTVIEW_H
#include <QtCharts>
class FitCurveChartView : public QChartView {
Q_OBJECT
public:
FitCurveChartView(QWidget *parent = Q_NULLPTR);
~FitCurveChartView();
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event);
signals:
void signalMouseEvent(int eventId, QMouseEvent *event);
void signalWheelEvent(QWheelEvent *event);
};
#endif // FITCURVECHARTVIEW_H
FirtCurveChartView.cpp
#include "FitCurveChartView.h"
FitCurveChartView::FitCurveChartView(QWidget *parent) {
}
FitCurveChartView::~FitCurveChartView() {
}
void FitCurveChartView::mousePressEvent(QMouseEvent *event) {
emit signalMouseEvent(0, event);
QChartView::mousePressEvent(event);
}
void FitCurveChartView::mouseMoveEvent(QMouseEvent *event) {
emit signalMouseEvent(1, event);
QChartView::mouseMoveEvent(event);
}
void FitCurveChartView::mouseReleaseEvent(QMouseEvent *event) {
emit signalMouseEvent(2, event);
QChartView::mouseReleaseEvent(event);
}
void FitCurveChartView::mouseDoubleClickEvent(QMouseEvent *event) {
emit signalMouseEvent(3, event);
QChartView::mouseDoubleClickEvent(event);
}
void FitCurveChartView::wheelEvent(QWheelEvent *event) {
emit signalWheelEvent(event);
QChartView::wheelEvent(event);
}
第二步:在主界面代码中使用,我的是在自定义对话框里面,你们可以直接在窗口中使用
举例:fitcurvedialog.h
#ifndef FITCURVEDIALOG_H
#define FITCURVEDIALOG_H
#include <QDialog>
#include "FitCurveChartView.h"
namespace Ui {
class FitCurveDialog;
}
class FitCurveDialog : public QDialog
{
Q_OBJECT
public:
explicit FitCurveDialog(QWidget *parent = nullptr);
~FitCurveDialog();
void initQChartView();
void updateXYGuideLine();
void resetZoomAndScroll();
QVector<int> getAxisRanges();
public slots:
void theSlotMouseEvent(int eventId, QMouseEvent *event);
void theSlotWheelEvent(QWheelEvent *event);
private:
Ui::FitCurveDialog *ui;
FitCurveChartView *curveChartView;
QChart *curveChart;
QSplineSeries* fitPointsSeriesS; //要显示的曲线原始数据
QScatterSeries* tipSeries;
QSplineSeries* xGuideSeries; //鼠标悬浮位置点的x轴辅助线
QSplineSeries* yGuideSeries; //鼠标悬浮位置点的y轴辅助线
bool isPressed = false; //图标是否在拖拽中
QPoint pressedPoint; //鼠标拖拽起点
};
#endif // FITCURVEDIALOG_H
fitcurvedialog.cpp (UI文件里面就放了一个水平布局chartLayout)
#include "fitcurvedialog.h"
#include "ui_fitcurvedialog.h"
FitCurveDialog::FitCurveDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::FitCurveDialog)
{
ui->setupUi(this);
qApp->setOverrideCursor(Qt::ArrowCursor); //允许系统弹窗、提示
initQChartView();
}
void FitCurveDialog::initQChartView() {
//创建图表框架
curveChartView = new FitCurveChartView(this);
curveChartView->setMaximumWidth(1730);
curveChartView->setMinimumHeight(480);
curveChart = new QChart();
curveChart->setTheme(QChart::ChartThemeBlueIcy);
curveChart->setContentsMargins(0, 0, 0, 0); //设置外边界全部为0, 根据自己实际情况设置
curveChart->setMargins(QMargins(5, -30, 5, 10)); //设置内边界, 根据自己实际情况设置
curveChart->setBackgroundRoundness(0); //设置表格边框圆角半径
curveChartView->setChart(curveChart);
//创建折线序列
fitPointsSeriesS = new QSplineSeries(this); //原始数据曲线
fitPointsSeriesS->setUseOpenGL(true);
xGuideSeries = new QSplineSeries(this);
yGuideSeries = new QSplineSeries(this);
tipSeries = new QScatterSeries(); // 创建一个散点数据集对象,用于显示
tipSeries->setMarkerShape(QScatterSeries::MarkerShapeCircle); // 设置绘制的散点的样式为圆
tipSeries->setMarkerSize(10);
QObject::connect(fitPointsSeriesS, &QSplineSeries::clicked, [=](const QPointF &point)mutable{
QPointF tempPoint;
QVector<QPointF> tempList(fitPointsSeriesS->pointsVector()); //复制曲线中的数据进行计算, 因为直接使用会导致卡顿
int tempX = qRound(point.x());
int tempY = -999;
for (int i = 0; i < tempList.size(); i++) {
if (tempList[i].x() == tempX) {
tempY = tempList[i].y();
tempPoint.setX(tempX);
tempPoint.setY(tempY);
break;
}
}
if (tempY != -999) {
QToolTip::showText(QCursor::pos(), QString("(%1,%2)").arg(tempX).arg(tempY));
QVector<QPointF> tipList;
tipList.append(tempPoint);
tipSeries->replace(tipList);
updateXYGuideLine();
}
});
curveChart->addSeries(xGuideSeries);
curveChart->addSeries(yGuideSeries);
curveChart->addSeries(fitPointsSeriesS);
curveChart->addSeries(tipSeries);
//添加数据绘制
size_t count = 20000;
QVector<QPointF> list;
for (size_t i = 0; i < count; i++) {
list.append(QPoint(i, int(i / 40)));
}
fitPointsSeriesS->replace(list);
//创建坐标轴
QValueAxis* axisX = new QValueAxis;
axisX->setRange(0, 20000);
axisX->setTickCount(21);
axisX->setLabelFormat("%d");
axisX->setLabelsAngle(-90); //坐标刻度文字显示角度
curveChart->addAxis(axisX,Qt::AlignBottom);
xGuideSeries->attachAxis(axisX);
yGuideSeries->attachAxis(axisX);
fitPointsSeriesS->attachAxis(axisX);
tipSeries->attachAxis(axisX);
QValueAxis* axisY = new QValueAxis;
axisY->setRange(0, 500);
axisY->setTickCount(11);
axisY->setLabelFormat("%d");
curveChart->addAxis(axisY,Qt::AlignLeft);
xGuideSeries->attachAxis(axisY);
yGuideSeries->attachAxis(axisY);
fitPointsSeriesS->attachAxis(axisY);
tipSeries->attachAxis(axisY);
// axisX->setGridLineVisible(false); //隐藏背景网格X轴框线
// axisY->setGridLineVisible(false); //隐藏背景网格Y轴框线
curveChart->legend()->markers()[0]->setVisible(false);
curveChart->legend()->markers()[1]->setVisible(false);
curveChart->legend()->markers()[2]->setVisible(false);
curveChart->legend()->markers()[3]->setVisible(false);
curveChartView->setRenderHint(QPainter::Antialiasing); //除锯齿
connect(curveChartView, &FitCurveChartView::signalMouseEvent, this, &FitCurveDialog::theSlotMouseEvent);
connect(curveChartView, &FitCurveChartView::signalWheelEvent, this, &FitCurveDialog::theSlotWheelEvent);
ui->chartLayout->addWidget(curveChartView);
}
void FitCurveDialog::theSlotMouseEvent(int eventId, QMouseEvent *event) {
if (eventId == 0){ //单击按下
isPressed = true;
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
pressedPoint = mouseEvent->pos();
} else if (eventId == 1) { //鼠标移动
if (isPressed) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
curveChart->scroll(-(mouseEvent->pos().x() - pressedPoint.x()) / 10,
(mouseEvent->pos().y() - pressedPoint.y()) / 10);
updateXYGuideLine();
}
} else if (eventId == 2) { //单击抬起
isPressed = false;
} else if (eventId == 3) { //双击
resetZoomAndScroll();
updateXYGuideLine();
}
}
void FitCurveDialog::theSlotWheelEvent(QWheelEvent *event) {
int delta = event->angleDelta().y();
if (delta > 0) {
curveChart->zoom(0.95);
} else {
curveChart->zoom(1.05);
}
updateXYGuideLine();
}
void FitCurveDialog::updateXYGuideLine() {
if (tipSeries->points().size() > 0) {
QVector<int> axisRanges = getAxisRanges();
QVector<QPointF> xGuideList, yGuideList;
int tempX = tipSeries->points()[0].x();
int tempY = tipSeries->points()[0].y();
xGuideList.append(QPointF(tempX, axisRanges[2]));
xGuideList.append(QPointF(tempX, tempY));
yGuideList.append(QPointF(axisRanges[0], tempY));
yGuideList.append(QPointF(tempX, tempY));
xGuideSeries->replace(xGuideList);
yGuideSeries->replace(yGuideList);
}
}
void FitCurveDialog::resetZoomAndScroll() {
curveChart->zoomReset();
QList<QAbstractAxis*> axesX, axesY;
axesX = curveChart->axes(Qt::Horizontal);
axesY = curveChart->axes(Qt::Vertical);
QValueAxis *curAxisX = (QValueAxis*)axesX[0];
QValueAxis *curAxisY = (QValueAxis*)axesY[0];
curAxisX->setRange(0, 20000);
curAxisY->setRange(0, 500);
}
QVector<int> FitCurveDialog::getAxisRanges() {
QList<QAbstractAxis*> axesX, axesY;
axesX = curveChart->axes(Qt::Horizontal);
axesY = curveChart->axes(Qt::Vertical);
QValueAxis *curAxisX = (QValueAxis*)axesX[0];
QValueAxis *curAxisY = (QValueAxis*)axesY[0];
QVector<int> ranges = {int(curAxisX->min()), int(curAxisX->max()), int(curAxisY->min()), int(curAxisY->max())};
return ranges;
}
FitCurveDialog::~FitCurveDialog()
{
delete ui;
}
效果:(动图依次展示:①点击曲线显示坐标->②平移->③缩放->④双击还原)