zoukankan      html  css  js  c++  java
  • 利用QPainter绘制散点图

    【1】实例代码

    (1)代码目录结构(备注:QtCreator默认步骤新建工程)

    (2)工程pro文件

     1 QT       += core gui
     2 
     3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
     4 
     5 TARGET = painter
     6 TEMPLATE = app
     7 
     8 
     9 SOURCES += main.cpp
    10         mainwindow.cpp
    11 
    12 HEADERS  += mainwindow.h
    13 
    14 FORMS    += mainwindow.ui

    (3)头文件

     1 #ifndef MAINWINDOW_H
     2 #define MAINWINDOW_H
     3 
     4 #include <QtGui>
     5 #include <QPaintEvent>
     6 #include <QMainWindow>
     7 
     8 
     9 #include <ctime>
    10 #include <cstdlib>
    11 
    12 namespace Ui
    13 {
    14     class MainWindow;
    15 }
    16 
    17 class MainWindow : public QMainWindow
    18 {
    19     Q_OBJECT
    20 
    21 public:
    22     explicit MainWindow(QWidget *parent = 0);
    23     ~MainWindow();
    24 
    25     void Paint();
    26 
    27 public slots:
    28     void onRefresh();
    29 protected:
    30     void paintEvent(QPaintEvent *);
    31 
    32 private:
    33     Ui::MainWindow *ui;
    34     QImage m_image;
    35     QPainter *m_painter;
    36 };
    37 
    38 #endif // MAINWINDOW_H

    (4)实现文件

      1 #include "mainwindow.h"
      2 #include "ui_mainwindow.h"
      3 
      4 #define POINTSNUM 10
      5 #define LowerFactor 0.8
      6 #define UpperFactor 1.2
      7 
      8 typedef struct Data
      9 {
     10     double scaleRange;
     11     double maxScale;
     12     double minScale;
     13     QVector<double> vecData;
     14 
     15     Data() : scaleRange(0.0), maxScale(0.0), minScale(0.0)
     16     {}
     17     void init()
     18     {
     19         for (int i = 0; i < POINTSNUM; ++i)
     20         {
     21             if (i % 2)
     22                 vecData.append(rand() % 50 - 10);
     23             else
     24                 vecData.append(rand() % 50 + 10);
     25         }
     26         double maxElement = *(std::max_element(vecData.begin(), vecData.end()));
     27         double minElement = *(std::min_element(vecData.begin(), vecData.end()));
     28         if (maxElement < 0)
     29         {
     30             maxScale = maxElement * LowerFactor;
     31             minScale = minElement * UpperFactor;
     32         }
     33         else if (0 == maxElement)
     34         {
     35             maxScale = 2;
     36             minScale = minElement * UpperFactor;
     37         }
     38         else if (maxElement > 0 && minElement < 0)
     39         {
     40             maxScale = maxElement * UpperFactor;
     41             minScale = minElement * UpperFactor;
     42         }
     43         else if (minElement > 0)
     44         {
     45             maxScale = maxElement * UpperFactor;
     46             minScale = minElement * LowerFactor;
     47         }
     48 
     49         scaleRange = maxScale - minScale;
     50     }
     51     void print()
     52     {
     53         for (int i = 0; i < POINTSNUM; ++i)
     54         {
     55             qDebug () << i << "::" << vecData[i] << " ";
     56         }
     57         qDebug() << endl;
     58     }
     59 }DataInfo;
     60 
     61 MainWindow::MainWindow(QWidget *parent)
     62     : QMainWindow(parent),
     63       ui(new Ui::MainWindow)
     64 {
     65     ui->setupUi(this);
     66     ui->mainToolBar->setVisible(true);
     67 
     68     QAction *pAction = new QAction("refresh", this);
     69     ui->mainToolBar->addAction(pAction);
     70     connect(pAction, &QAction::triggered, this, &MainWindow::onRefresh);
     71 
     72     resize(1000, 730); // 窗体大小 宽度1000 高度730
     73 
     74     m_image = QImage(990, 710, QImage::Format_RGB32);  // 画布的初始化大小设为,使用32位颜色
     75     QColor backColor = qRgb(255, 255, 255);    // 画布初始化背景色使用白色
     76     m_image.fill(backColor); // 对画布进行填充
     77 
     78     m_painter = new QPainter(&m_image);
     79     m_painter->setRenderHint(QPainter::Antialiasing, true); // 设置反锯齿模式
     80 
     81     Paint();
     82 }
     83 
     84 void MainWindow::onRefresh()
     85 {
     86     m_painter->fillRect(10, 10, 980 - 10, 700 - 10, Qt::white);
     87     Paint();
     88     update();
     89 }
     90 
     91 void MainWindow::Paint()
     92 {
     93     // 确定坐标轴起点坐标
     94     int pointx = 80, pointy = 650;
     95 
     96     // 确定坐标轴宽度和高度,上文已定义画布大小,宽高依此而定。
     97     int width = 980 - pointx - 70;  // 宽度 = 画布宽度 - 坐标起点x - 右端间隙
     98     int height = 700 - 2 * 50;      // 高度 = 画布高度 - 上下端的间隙高度
     99 
    100     // 绘制视图区域
    101     // 即外围的矩形(由左上角与右下角的两个点确定一个矩形)
    102     m_painter->drawRect(20, 30, 980 - 10, 700 - 20);
    103 
    104     // 绘制X、Y1、Y2轴
    105     QPointF xStartPoint(pointx, pointy);
    106     QPointF xEndPoint(width + pointx, pointy);
    107     m_painter->drawLine(xStartPoint, xEndPoint); // 坐标轴x宽度为width
    108 
    109     QPointF y1StartPoint(pointx, pointy - height);
    110     QPointF y1EndPoint(pointx, pointy);
    111     m_painter->drawLine(y1StartPoint, y1EndPoint); // 坐标轴y1高度为height
    112 
    113     QPointF y2StartPoint(pointx + width, pointy - height);
    114     QPointF y2EndPoint(pointx + width, pointy);
    115     m_painter->drawLine(y2StartPoint, y2EndPoint); // 坐标轴y2高度为height
    116 
    117     // (2)获得数据并分析最大值与最小值
    118     DataInfo vectorX, vectorY1, vectorY2; // 数据储存在容器中,大小为POINTSNUM]
    119     // 模拟随机数据
    120     srand((int)time(NULL));
    121     vectorX.init();
    122     vectorY1.init();
    123     vectorY2.init();
    124 
    125     vectorX.print();
    126     vectorY1.print();
    127     vectorY2.print();
    128 
    129     double kx = (double)(width / vectorX.scaleRange); // x轴的系数
    130     double ky1 = (double)(height / vectorY1.scaleRange);  // y1方向的比例系数
    131     double ky2 = (double)(height / vectorY2.scaleRange);  // y2方向的比例系数
    132 
    133     // (3)绘制点
    134     QPen penPointY1, penPointY2;
    135     penPointY1.setColor(Qt::blue);
    136     penPointY1.setWidth(5);
    137 
    138     penPointY2.setColor(Qt::red);
    139     penPointY2.setWidth(5);
    140 
    141     for (int i = 0; i < POINTSNUM; ++i)
    142     {
    143         double dXStart = pointx + kx * (vectorX.vecData[i] - vectorX.minScale);
    144         m_painter->setPen(penPointY1); // 蓝色的笔,用于标记Y1各个点
    145         m_painter->drawPoint(dXStart, pointy - (vectorY1.vecData[i] - vectorY1.minScale) * ky1);
    146 
    147         m_painter->setPen(penPointY2); // 红色的笔,用于标记Y2各个点
    148         m_painter->drawPoint(dXStart, pointy - (vectorY2.vecData[i] - vectorY2.minScale) * ky2);
    149     }
    150 
    151     // (4) 绘制刻度线
    152     QPen penDegree;
    153     penDegree.setColor(Qt::black);
    154     penDegree.setWidth(2);
    155     m_painter->setPen(penDegree);
    156 
    157     // x轴刻度线和值
    158     // x轴 第一个刻度值
    159     m_painter->drawText(pointx + 3, pointy + 12, QString::number(vectorX.minScale, 'f', 3));
    160     for (int i = 0; i < POINTSNUM - 1; ++i) // 分成10份
    161     {
    162 //        // 选取合适的坐标,绘制一段长度为4的直线,用于表示刻度
    163 //        m_painter->drawLine(pointx + (i + 1) * width/10, pointy,
    164 //                         pointx + (i+1)*width/10, pointy + 4);
    165 
    166         m_painter->drawText(pointx + (i+0.9) * width / POINTSNUM, pointy + 12, // 值的位置信息
    167                          QString::number(vectorX.minScale + (i+1) * (vectorX.scaleRange/POINTSNUM), 'f', 3));
    168     }
    169     // x轴 最后一个刻度值
    170     m_painter->drawText(pointx + (POINTSNUM - 1 + 0.8) * width / POINTSNUM, pointy + 12,
    171                      QString::number(vectorX.maxScale, 'f', 3));
    172 
    173     xStartPoint.setX(pointx);
    174     xStartPoint.setY(pointy + 20);
    175     xEndPoint.setX(pointx + width);
    176     xEndPoint.setY(pointy + 20);
    177     m_painter->drawLine(xStartPoint, xEndPoint);
    178 
    179     m_painter->drawText(pointx + width/2, pointy + 35, QString("X"));
    180 
    181     // y1轴刻度线和值
    182     // y1轴 第一个刻度值
    183     m_painter->drawText(pointx - 25, pointy - 3, QString::number(vectorY1.minScale, 'f', 3));
    184     for (int i = 0; i < POINTSNUM - 1; ++i)
    185     {
    186         // 代码较长,但是掌握基本原理即可。
    187         // 主要就是确定一个位置,然后画一条短短的直线表示刻度。
    188 
    189 //        m_painter->drawLine(pointx, pointy-(i+1)*height/10,
    190 //                         pointx-4, pointy-(i+1)*height/10);
    191 
    192         m_painter->drawText(pointx - 25, pointy - (i+0.85) * height/POINTSNUM,
    193                          QString::number(vectorY1.minScale + (i+1) * (vectorY1.scaleRange/POINTSNUM), 'f', 3));
    194     }
    195     // y1轴 最后一个刻度值
    196     m_painter->drawText(pointx - 25, pointy - (POINTSNUM - 1 + 0.85) * height/POINTSNUM,
    197                      QString::number(vectorY1.maxScale, 'f', 3));
    198 
    199     y1StartPoint.setX(pointx - 35);
    200     y1StartPoint.setY(pointy - height);
    201 
    202     y1EndPoint.setX(pointx - 35);
    203     y1EndPoint.setY(pointy);
    204     m_painter->drawLine(y1StartPoint, y1EndPoint);
    205 
    206     m_painter->drawText(pointx - 55, pointy - height/2, QString("Y1"));
    207 
    208     // y2轴刻度线和值
    209     // y2轴 第一个刻度值
    210     m_painter->drawText(pointx + width + 10, pointy - 3, QString::number(vectorY2.minScale, 'f', 3));
    211     for (int i = 0; i < POINTSNUM - 1; ++i)
    212     {
    213 //        m_painter->drawLine(pointx + width, pointy-(i+1)*height/10,
    214 //                         pointx + width + 4, pointy-(i+1)*height/10);
    215 
    216         m_painter->drawText(pointx + width + 10, pointy - (i+0.85)*height/POINTSNUM,
    217                          QString::number((vectorY2.minScale + (i+1)*(vectorY2.scaleRange/POINTSNUM)), 'f' , 3));
    218     }
    219     // Y2轴 最后一个刻度值
    220     m_painter->drawText(pointx + width + 10, pointy - (POINTSNUM - 1 + 0.85)*height/POINTSNUM,
    221                      QString::number(vectorY2.maxScale, 'f', 3));
    222 
    223     y2StartPoint.setX(pointx + width + 40);
    224     y2StartPoint.setY(pointy - height);
    225 
    226     y2EndPoint.setX(pointx + width + 40);
    227     y2EndPoint.setY(pointy);
    228     m_painter->drawLine(y2StartPoint, y2EndPoint);
    229 
    230     m_painter->drawText(pointx + width + 50, pointy - height/2, QString("Y2"));
    231 
    232     // (5)绘制网格
    233     QPen penDotLine;
    234     penDotLine.setStyle(Qt::DotLine);
    235     m_painter->setPen(penDotLine);
    236     for (int i = 0; i < POINTSNUM; ++i)
    237     {
    238         // 垂直线
    239         m_painter->drawLine(pointx + (i+1)* width/POINTSNUM, pointy,
    240                          pointx + (i+1)* width/POINTSNUM, pointy - height);
    241         // 水平线
    242         m_painter->drawLine(pointx, pointy-(i+1)*height/POINTSNUM,
    243                          pointx + width, pointy-(i+1)*height/POINTSNUM);
    244     }
    245 }
    246 
    247 MainWindow::~MainWindow()
    248 {
    249     delete ui;
    250     delete m_painter;
    251 }
    252 
    253 void MainWindow::paintEvent(QPaintEvent *)
    254 {
    255     QPainter painter(this);
    256     painter.drawImage(0, 0, m_image);
    257 }

    (5)main文件

     1 #include "mainwindow.h"
     2 #include <QApplication>
     3 
     4 int main(int argc, char *argv[])
     5 {
     6     QApplication a(argc, argv);
     7     MainWindow w;
     8     w.show();
     9 
    10     return a.exec();
    11 }

    【2】效果图

    运行结果图如下:

    Good Good Study, Day Day Up.

    顺序 选择 循环 总结

  • 相关阅读:
    通过实验窥探javascript的解析执行顺序
    HTML5实战与剖析之原生拖拽(四可拖动dragable属性和其他成员)
    Google Guava之Optional优雅的使用null
    sharding-jdbc源码学习(一)简介
    重构——改善既有代码的设计
    spring自定义标签
    java自定义注解
    开源项目集合
    Lombok引入简化Java代码
    设计模式之建造者模式
  • 原文地址:https://www.cnblogs.com/Braveliu/p/6880099.html
Copyright © 2011-2022 走看看