利用QPainter绘制散点图

时间:2023-03-09 05:29:16
利用QPainter绘制散点图

【1】实例代码

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

利用QPainter绘制散点图

(2)工程pro文件

 QT       += core gui

 greaterThan(QT_MAJOR_VERSION, ): QT += widgets

 TARGET = painter
TEMPLATE = app SOURCES += main.cpp\
mainwindow.cpp HEADERS += mainwindow.h FORMS += mainwindow.ui

(3)头文件

 #ifndef MAINWINDOW_H
#define MAINWINDOW_H #include <QtGui>
#include <QPaintEvent>
#include <QMainWindow> #include <ctime>
#include <cstdlib> namespace Ui
{
class MainWindow;
} class MainWindow : public QMainWindow
{
Q_OBJECT public:
explicit MainWindow(QWidget *parent = );
~MainWindow(); void Paint(); public slots:
void onRefresh();
protected:
void paintEvent(QPaintEvent *); private:
Ui::MainWindow *ui;
QImage m_image;
QPainter *m_painter;
}; #endif // MAINWINDOW_H

(4)实现文件

 #include "mainwindow.h"
#include "ui_mainwindow.h" #define POINTSNUM 10
#define LowerFactor 0.8
#define UpperFactor 1.2 typedef struct Data
{
double scaleRange;
double maxScale;
double minScale;
QVector<double> vecData; Data() : scaleRange(0.0), maxScale(0.0), minScale(0.0)
{}
void init()
{
for (int i = ; i < POINTSNUM; ++i)
{
if (i % )
vecData.append(rand() % - );
else
vecData.append(rand() % + );
}
double maxElement = *(std::max_element(vecData.begin(), vecData.end()));
double minElement = *(std::min_element(vecData.begin(), vecData.end()));
if (maxElement < )
{
maxScale = maxElement * LowerFactor;
minScale = minElement * UpperFactor;
}
else if ( == maxElement)
{
maxScale = ;
minScale = minElement * UpperFactor;
}
else if (maxElement > && minElement < )
{
maxScale = maxElement * UpperFactor;
minScale = minElement * UpperFactor;
}
else if (minElement > )
{
maxScale = maxElement * UpperFactor;
minScale = minElement * LowerFactor;
} scaleRange = maxScale - minScale;
}
void print()
{
for (int i = ; i < POINTSNUM; ++i)
{
qDebug () << i << "::" << vecData[i] << " ";
}
qDebug() << endl;
}
}DataInfo; MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->mainToolBar->setVisible(true); QAction *pAction = new QAction("refresh", this);
ui->mainToolBar->addAction(pAction);
connect(pAction, &QAction::triggered, this, &MainWindow::onRefresh); resize(, ); // 窗体大小 宽度1000 高度730 m_image = QImage(, , QImage::Format_RGB32); // 画布的初始化大小设为,使用32位颜色
QColor backColor = qRgb(, , ); // 画布初始化背景色使用白色
m_image.fill(backColor); // 对画布进行填充 m_painter = new QPainter(&m_image);
m_painter->setRenderHint(QPainter::Antialiasing, true); // 设置反锯齿模式 Paint();
} void MainWindow::onRefresh()
{
m_painter->fillRect(, , - , - , Qt::white);
Paint();
update();
} void MainWindow::Paint()
{
// 确定坐标轴起点坐标
int pointx = , pointy = ; // 确定坐标轴宽度和高度,上文已定义画布大小,宽高依此而定。
int width = - pointx - ; // 宽度 = 画布宽度 - 坐标起点x - 右端间隙
int height = - * ; // 高度 = 画布高度 - 上下端的间隙高度 // 绘制视图区域
// 即外围的矩形(由左上角与右下角的两个点确定一个矩形)
m_painter->drawRect(, , - , - ); // 绘制X、Y1、Y2轴
QPointF xStartPoint(pointx, pointy);
QPointF xEndPoint(width + pointx, pointy);
m_painter->drawLine(xStartPoint, xEndPoint); // 坐标轴x宽度为width QPointF y1StartPoint(pointx, pointy - height);
QPointF y1EndPoint(pointx, pointy);
m_painter->drawLine(y1StartPoint, y1EndPoint); // 坐标轴y1高度为height QPointF y2StartPoint(pointx + width, pointy - height);
QPointF y2EndPoint(pointx + width, pointy);
m_painter->drawLine(y2StartPoint, y2EndPoint); // 坐标轴y2高度为height // (2)获得数据并分析最大值与最小值
DataInfo vectorX, vectorY1, vectorY2; // 数据储存在容器中,大小为POINTSNUM]
// 模拟随机数据
srand((int)time(NULL));
vectorX.init();
vectorY1.init();
vectorY2.init(); vectorX.print();
vectorY1.print();
vectorY2.print(); double kx = (double)(width / vectorX.scaleRange); // x轴的系数
double ky1 = (double)(height / vectorY1.scaleRange); // y1方向的比例系数
double ky2 = (double)(height / vectorY2.scaleRange); // y2方向的比例系数 // (3)绘制点
QPen penPointY1, penPointY2;
penPointY1.setColor(Qt::blue);
penPointY1.setWidth(); penPointY2.setColor(Qt::red);
penPointY2.setWidth(); for (int i = ; i < POINTSNUM; ++i)
{
double dXStart = pointx + kx * (vectorX.vecData[i] - vectorX.minScale);
m_painter->setPen(penPointY1); // 蓝色的笔,用于标记Y1各个点
m_painter->drawPoint(dXStart, pointy - (vectorY1.vecData[i] - vectorY1.minScale) * ky1); m_painter->setPen(penPointY2); // 红色的笔,用于标记Y2各个点
m_painter->drawPoint(dXStart, pointy - (vectorY2.vecData[i] - vectorY2.minScale) * ky2);
} // (4) 绘制刻度线
QPen penDegree;
penDegree.setColor(Qt::black);
penDegree.setWidth();
m_painter->setPen(penDegree); // x轴刻度线和值
// x轴 第一个刻度值
m_painter->drawText(pointx + , pointy + , QString::number(vectorX.minScale, 'f', ));
for (int i = ; i < POINTSNUM - ; ++i) // 分成10份
{
// // 选取合适的坐标,绘制一段长度为4的直线,用于表示刻度
// m_painter->drawLine(pointx + (i + 1) * width/10, pointy,
// pointx + (i+1)*width/10, pointy + 4); m_painter->drawText(pointx + (i+0.9) * width / POINTSNUM, pointy + , // 值的位置信息
QString::number(vectorX.minScale + (i+) * (vectorX.scaleRange/POINTSNUM), 'f', ));
}
// x轴 最后一个刻度值
m_painter->drawText(pointx + (POINTSNUM - + 0.8) * width / POINTSNUM, pointy + ,
QString::number(vectorX.maxScale, 'f', )); xStartPoint.setX(pointx);
xStartPoint.setY(pointy + );
xEndPoint.setX(pointx + width);
xEndPoint.setY(pointy + );
m_painter->drawLine(xStartPoint, xEndPoint); m_painter->drawText(pointx + width/, pointy + , QString("X")); // y1轴刻度线和值
// y1轴 第一个刻度值
m_painter->drawText(pointx - , pointy - , QString::number(vectorY1.minScale, 'f', ));
for (int i = ; i < POINTSNUM - ; ++i)
{
// 代码较长,但是掌握基本原理即可。
// 主要就是确定一个位置,然后画一条短短的直线表示刻度。 // m_painter->drawLine(pointx, pointy-(i+1)*height/10,
// pointx-4, pointy-(i+1)*height/10); m_painter->drawText(pointx - , pointy - (i+0.85) * height/POINTSNUM,
QString::number(vectorY1.minScale + (i+) * (vectorY1.scaleRange/POINTSNUM), 'f', ));
}
// y1轴 最后一个刻度值
m_painter->drawText(pointx - , pointy - (POINTSNUM - + 0.85) * height/POINTSNUM,
QString::number(vectorY1.maxScale, 'f', )); y1StartPoint.setX(pointx - );
y1StartPoint.setY(pointy - height); y1EndPoint.setX(pointx - );
y1EndPoint.setY(pointy);
m_painter->drawLine(y1StartPoint, y1EndPoint); m_painter->drawText(pointx - , pointy - height/, QString("Y1")); // y2轴刻度线和值
// y2轴 第一个刻度值
m_painter->drawText(pointx + width + , pointy - , QString::number(vectorY2.minScale, 'f', ));
for (int i = ; i < POINTSNUM - ; ++i)
{
// m_painter->drawLine(pointx + width, pointy-(i+1)*height/10,
// pointx + width + 4, pointy-(i+1)*height/10); m_painter->drawText(pointx + width + , pointy - (i+0.85)*height/POINTSNUM,
QString::number((vectorY2.minScale + (i+)*(vectorY2.scaleRange/POINTSNUM)), 'f' , ));
}
// Y2轴 最后一个刻度值
m_painter->drawText(pointx + width + , pointy - (POINTSNUM - + 0.85)*height/POINTSNUM,
QString::number(vectorY2.maxScale, 'f', )); y2StartPoint.setX(pointx + width + );
y2StartPoint.setY(pointy - height); y2EndPoint.setX(pointx + width + );
y2EndPoint.setY(pointy);
m_painter->drawLine(y2StartPoint, y2EndPoint); m_painter->drawText(pointx + width + , pointy - height/, QString("Y2")); // (5)绘制网格
QPen penDotLine;
penDotLine.setStyle(Qt::DotLine);
m_painter->setPen(penDotLine);
for (int i = ; i < POINTSNUM; ++i)
{
// 垂直线
m_painter->drawLine(pointx + (i+)* width/POINTSNUM, pointy,
pointx + (i+)* width/POINTSNUM, pointy - height);
// 水平线
m_painter->drawLine(pointx, pointy-(i+)*height/POINTSNUM,
pointx + width, pointy-(i+)*height/POINTSNUM);
}
} MainWindow::~MainWindow()
{
delete ui;
delete m_painter;
} void MainWindow::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawImage(, , m_image);
}

(5)main文件

 #include "mainwindow.h"
#include <QApplication> int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show(); return a.exec();
}

【2】效果图

运行结果图如下:

利用QPainter绘制散点图

Good Good Study, Day Day Up.

顺序 选择 循环 总结