qt6 chart 画k线图
实现的基本功能:
1. 显示k线, 附赠一个close指标
2. 根据鼠标移动,画十字线
3. 跟随鼠标,显示当前k线的一个值。
4. 可以移动、缩放图形
运行过程中发现:如果图中放了两个数据序列,横坐标默认是绑定第一个指定的序列,需要单独指定第二个序列的坐标。
运行环境:qt 6.5 (其他环境未测试)
CMakeLists文件:
cmake_minimum_required(VERSION 3.14) project(chart5 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 REQUIRED COMPONENTS Charts Core Gui) # 下面candlestickdatareader.cpp .h 不是必须的,从qt example里copy出来的 # acme_data.txt 也是。 做实验不用自己编数据 add_executable(chart5 main.cpp candlestickdatareader.cpp candlestickdatareader.h ) target_link_libraries(chart5 Qt::Charts Qt::Core Qt::Gui ) set_source_files_properties("acme_data.txt" PROPERTIES QT_RESOURCE_ALIAS "acme" ) qt6_add_resources(chart5 "chart5data" PREFIX "/" FILES "acme_data.txt" )
主文件:
#include <QtCharts/QBarCategoryAxis> #include <QtCharts/QCandlestickSeries> #include <QtCharts/QChartView> #include <QtCharts/QValueAxis> #include <QtCore/QDateTime> #include <QtCore/QFile> #include <QtWidgets/QApplication> #include <QtWidgets/QMainWindow> #include <QtWidgets> #include <QtCharts> #include <QDebug> #include <QObject> #include "candlestickdatareader.h" class ChartView : public QChartView { public: ChartView(QChart* chart = nullptr); virtual ~ChartView(); protected: virtual void mouseMoveEvent(QMouseEvent *pEvent) override; virtual void mousePressEvent(QMouseEvent *pEvent) override; virtual void mouseReleaseEvent(QMouseEvent *pEvent) override; virtual void wheelEvent(QWheelEvent *pEvent) override; virtual void enterEvent(QEnterEvent *pEvent)override; virtual void leaveEvent(QEvent *pEvent)override; private: bool leftButtonPressed; QPoint prePos; QGraphicsLineItem* x_line; QGraphicsLineItem* y_line; QGraphicsSimpleTextItem* cursor_text; }; ChartView::ChartView(QChart *chart): QChartView(chart), leftButtonPressed(false) , prePos(0, 0) { // 创建线 x_line = new QGraphicsLineItem(); // 设置颜色 x_line->setPen(QPen(QColor( 100, 100, 100 ))); x_line->setZValue(2); y_line = new QGraphicsLineItem(); y_line->setPen(QPen(QColor( 100, 100, 100 ))); y_line->setZValue(2); // 添加到scene中。 this->scene()->addItem(x_line); this->scene()->addItem(y_line); cursor_text = new QGraphicsSimpleTextItem; this->scene()->addItem(cursor_text); } ChartView::~ChartView() { } //// 鼠标移动 void ChartView::mouseMoveEvent(QMouseEvent *pEvent) { if (leftButtonPressed) { QPoint oDeltaPos = pEvent->pos() - prePos; this->chart()->scroll(-oDeltaPos.x(), oDeltaPos.y()); prePos = pEvent->pos(); } // 绘制线 x_line->setLine(pEvent->pos().rx(),0,pEvent->pos().rx(),this->height()); y_line->setLine(0,pEvent->pos().ry(),this->width(),pEvent->pos().ry()); // 设置显示内容 auto valpos = chart()->mapToValue(pEvent->pos()); int x = int(valpos.x()); QCandlestickSeries *candle = qobject_cast<QCandlestickSeries *>(chart()->series().at(0)); if (x<0) x = 0; if (x>=candle->count()) x = candle->count()-1; auto d = candle->sets().at(x)->close(); cursor_text->setText(QString("sit:%1:%2").arg(x).arg(d)); // 调整显示内容到鼠标右上 auto pos = pEvent->pos(); pos.setY(pos.ry()-20); pos.setX(pos.rx()+10); cursor_text->setPos(pos); __super::mouseMoveEvent(pEvent); } //// 鼠标按键 void ChartView::mousePressEvent(QMouseEvent *pEvent) { if (pEvent->button() == Qt::LeftButton) { leftButtonPressed = true; prePos = pEvent->pos(); this->setCursor(Qt::OpenHandCursor); } __super::mousePressEvent(pEvent); } //// 鼠标抬起 void ChartView::mouseReleaseEvent(QMouseEvent *pEvent) { if (pEvent->button() == Qt::LeftButton) { leftButtonPressed = false; this->setCursor(Qt::ArrowCursor); } __super::mouseReleaseEvent(pEvent); } void ChartView::wheelEvent(QWheelEvent *pEvent) { qreal rVal; if (pEvent->angleDelta().y() > 0) rVal = 0.99; else rVal = 1.01; // 1. 读取视图基本信息 QRectF oPlotAreaRect = this->chart()->plotArea(); QPointF oCenterPoint = oPlotAreaRect.center(); // 2. 水平调整 oPlotAreaRect.setWidth(oPlotAreaRect.width() * rVal); // 3. 竖直调整 oPlotAreaRect.setHeight(oPlotAreaRect.height() * rVal); // 4.1 计算视点,视点不变,围绕中心缩放 //QPointF oNewCenterPoint(oCenterPoint); // 4.2 计算视点,让鼠标点击的位置移动到窗口中心 //QPointF oNewCenterPoint(pEvent->pos()); // 4.3 计算视点,让鼠标点击的位置尽量保持不动(等比换算,存在一点误差) QPointF oNewCenterPoint(2 * oCenterPoint - pEvent->position() - (oCenterPoint - pEvent->position()) / rVal); // 5. 设置视点 oPlotAreaRect.moveCenter(oNewCenterPoint); // 6. 提交缩放调整 this->chart()->zoomIn(oPlotAreaRect); __super::wheelEvent(pEvent); } void ChartView::enterEvent(QEnterEvent *pEvent) { x_line->setVisible(true); y_line->setVisible(true); cursor_text->setVisible(true); __super::enterEvent(pEvent); } void ChartView::leaveEvent(QEvent *pEvent) { x_line->setVisible(false); y_line->setVisible(false); cursor_text->setVisible(false); __super::leaveEvent(pEvent); } int main(int argc, char *argv[]) { QApplication a(argc, argv); QCandlestickSeries *acmeSeries = new QCandlestickSeries(); acmeSeries->setName("Acme Ltd"); acmeSeries->setIncreasingColor(QColor(Qt::green)); acmeSeries->setDecreasingColor(QColor(Qt::red)); QLineSeries *closeSeries = new QLineSeries(); closeSeries->setName("close"); closeSeries->setColor(QColor(Qt::black)); // 示例数据 QFile acmeData(":acme"); if (!acmeData.open(QIODevice::ReadOnly | QIODevice::Text)) return 1; QStringList categories; CandlestickDataReader dataReader(&acmeData); int i = 0; while (!dataReader.atEnd()) { QCandlestickSet *set = dataReader.readCandlestickSet(); if (set) { acmeSeries->append(set); closeSeries->append(QPointF(i++, set->close())); categories << QDateTime::fromMSecsSinceEpoch(set->timestamp()).toString("dd"); } } QChart *chart = new QChart(); chart->addSeries(acmeSeries); chart->addSeries(closeSeries); chart->setTitle("Acme Ltd Historical Data (July 2015)"); chart->setAnimationOptions(QChart::SeriesAnimations); chart->createDefaultAxes(); QBarCategoryAxis *axisX = qobject_cast<QBarCategoryAxis *>(chart->axes(Qt::Horizontal).at(0)); axisX->setCategories(categories); QValueAxis *axisY = qobject_cast<QValueAxis *>(chart->axes(Qt::Vertical).at(0)); axisY->setMax(axisY->max() * 1.01); axisY->setMin(axisY->min() * 0.99);
chart->legend()->setVisible(true); chart->legend()->setAlignment(Qt::AlignBottom); QChartView *chartView = new ChartView(chart); // 抗锯齿 chartView->setRenderHint(QPainter::Antialiasing); QMainWindow window; window.setCentralWidget(chartView); window.resize(800, 600); window.show(); return a.exec(); }