Qt 绘制南丁格尔玫瑰图
项目中用来统计数据的一个数据分析部件,
可以统计某范围中的角度个数,(该范围可由外部指定),通过ToolTip事件实现鼠标悬浮显示。
可以图上右键保存png透明图片,通过QT事件函数:void QWidget::contextMenuEvent ( QContextMenuEvent * event ) [virtual protected] 实现,该函数当使用设置函数setContextMenuPolicy并传入Qt::DefaultContextMenu参数时被调用。
保存图片使用了QPixmap中的save()函数。
实现效果:
以下为程序主要代码:
头文件:
#ifndef GROSE_VIEW_H
#define GROSE_VIEW_H#include <QWidget>
#include <QPainter>
#include <QVector>
#include <QToolTip>
#include <QHelpEvent>
#include <QPixmap>
#include "guitools_global.h"class GUITOOLS_EXPORT GRoseView : public QWidget
{Q_OBJECTprotected:QRect mViewRect; // 视图矩形区域QRect mMargins; // 边距double mMaxRadius; // 最大的半径QPoint mCenter; // 绘制的中心点,视图区的中心QFont mRoseTitleFont;QFont mRoseCoordFont;QString mRoseTitle;QVector<int> mAngleCounts; // 不同角度范围对应的数据个数向量集合QVector<double> mAngleRadius; // 不同角度范围对应的半径QVector<double> mDatas; // 角度数据集int mDeltAngle; // 角度集合的范围int mMaxAngleNumber; // 方位角个数double mLineAngle; // 刻度角度间隔double mUniRdius; // 单位扇形半径QStringList mAxisLabelLists; // 横轴刻度标签列表QColor mColor; // 颜色int mUpNumber;int mCountMax;double mBestAzimuth;
public:GRoseView(QWidget *parent);~GRoseView();protected:virtual void resizeEvent(QResizeEvent* event);void paintEvent(QPaintEvent * event);void drawRosePicture(QPainter *p); // 绘制玫瑰图void drawSector(QPainter *p, int radius, int startAngle, int angleLength, QColor color); // 绘制每个扇形void drawCoordinate(QPainter *p); // 绘制坐标系void drawRoseTitle(QPainter *p);void setScale(int number); //设置横轴刻度void staAngleCount(); //设置角度相关内容virtual bool event(QEvent *event);QString angleMessageTip(double x, double y); //浮窗显示double getPointAngle(double x,double y);
public:void clear();// 设置绘图边距void setMargins(int marginTop, int marginBottom, int marginLeft, int marginRight);// 设置数据void setDatas(const QVector<double> &datas);// 设置变化角度void setDeltAngle(int deltAngle);// 设置标度字体void setCoordFont(const QFont& font);// 设置标题字体void setTitleFont(const QFont& font);// 设置标题void setTitle(const QString& title);void setColor(QColor color);// 获取最佳方位角const double &getBestAzimuth();void savePicture(QString filename); //保存图片//右键菜单事件void contextMenuEvent(QContextMenuEvent *event); private slots:void on_mSaveRoseView_triggered(bool checked);};#endif // GROSEPICTURE_H
源文件:
#include "groseview.h"
#include <qmath.h>
#include <QDebug>
#include <QMenu>
#include <QAction>
#include <QFileDialog>
#include <QMessageBox>
#include "gmath.h"GRoseView::GRoseView(QWidget *parent): QWidget(parent)
{mMaxRadius = 0;mDeltAngle = 1;mMaxAngleNumber = 0;mLineAngle = 22.5;mRoseCoordFont = QFont("Arial", 8, 50, false);mRoseTitleFont = QFont("Arial", 8, 50, false);mRoseTitle = "";mColor = Qt::red;this->setContextMenuPolicy(Qt::DefaultContextMenu); //全局开启右键菜单
}GRoseView::~GRoseView()
{}void GRoseView::resizeEvent(QResizeEvent* event)
{int marginRectWidth = width() - mMargins.left() - mMargins.right();int marginRectHeight = height() - mMargins.top() - mMargins.bottom();mViewRect.setRect(mMargins.left(), mMargins.top(), marginRectWidth, marginRectHeight); mMaxRadius = qMin(mViewRect.width()/2, mViewRect.height()/2);mCenter = QPoint((mViewRect.width() >> 1) + mMargins.left(), (mViewRect.height() >> 1) + mMargins.top());staAngleCount();
}void GRoseView::setScale(int number)
{ mMaxAngleNumber = number;int scaleValue; //scaleValue 每个小刻度代表的角度个数if(mMaxAngleNumber <= 6) {mUniRdius = mMaxRadius / mMaxAngleNumber;scaleValue = 1;mUpNumber = mMaxAngleNumber; }else {mUniRdius = mMaxRadius / 6;mUpNumber = 6;scaleValue = ceil((double)mMaxAngleNumber / 6);}mAxisLabelLists.clear();for(int i = 0;i <= mUpNumber;i += 2){mAxisLabelLists <<QString("%1").arg(qRound(scaleValue*i));}}
void GRoseView::paintEvent(QPaintEvent * event)
{if(mDatas.isEmpty() || mAngleCounts.isEmpty()) return;QPainter p(this);p.setRenderHint(QPainter::Antialiasing);p.setRenderHint(QPainter::TextAntialiasing);drawRoseTitle(&p);drawRosePicture(&p);drawCoordinate(&p);
}void GRoseView::drawCoordinate(QPainter *p)
{if(mDatas.count() == 0) return;p->setFont(mRoseCoordFont);QPen pen;QColor color(Qt::black);QFontMetrics mit = fontMetrics();pen.setWidthF(0.4);p->setPen(pen);p->drawEllipse(mCenter,qRound(mMaxRadius),qRound(mMaxRadius));//画圆环刻度、标签int flagloop = 1; //刻度长短标志位for(double i = 0; i < 360;i+=mLineAngle){p->save();QString loopText = QString::number(i);double xloop = mCenter.x() + mMaxRadius * qSin(i*PI/180); //从12点刻度处开始,每一刻度的坐标值double yloop = mCenter.y() - mMaxRadius + (mMaxRadius-mMaxRadius*qCos(i*PI/180));p->translate(xloop,yloop); //移动坐标系到相应的刻度点p->rotate(i);if(flagloop%2 != 0){p->drawText(-mit.width(loopText)/2,-mit.height()/2,loopText);p->drawLine(0,0,0,6); //长刻度}elsep->drawLine(0,0,0,4); //短刻度++flagloop;p->restore();}//画横坐标轴p->drawLine(mCenter.x(),mCenter.y(),mCenter.x()+mMaxRadius,mCenter.y()); int flagabsc = 1,scaleh,j=0; for (int i =0;i<= mUpNumber;i++){if(flagabsc%2 != 0){scaleh = 6;}elsescaleh = 4;p->drawLine(mCenter.x()+mUniRdius*i,mCenter.y(),mCenter.x()+mUniRdius*i,mCenter.y()-scaleh);if(i == 0 || i % 2 == 0){ float strw = mit.width(mAxisLabelLists.at(j)); //横轴刻度值宽度p->drawText(mCenter.x()+mUniRdius*i-strw/2,mCenter.y()+10,mAxisLabelLists.at(j));j++;}++flagabsc;}
}void GRoseView::drawRosePicture(QPainter *p)
{ p->save();int startAngle = 90;int deltaAngle = mDeltAngle;p->setPen(QPen(Qt::black));// 将画笔指定到矩形视图的中心p->translate(mCenter);for(int i = 0; i< mAngleRadius.count(); i++){if (startAngle - deltaAngle < -270) {deltaAngle = 270 + startAngle;}drawSector(p, mAngleRadius[i],startAngle, deltaAngle, mColor);startAngle -= deltaAngle;}p->restore();
}void GRoseView::drawSector(QPainter *p, int radius, int startAngle, int angleLength, QColor color)
{p->setBrush(color);QRectF rect(-radius, -radius, radius << 1, radius << 1);p->drawPie(rect, startAngle * 16, -angleLength * 16);
}void GRoseView::drawRoseTitle(QPainter *p)
{QFontMetrics fm = p->fontMetrics();p->setFont(mRoseTitleFont);p->drawText( mViewRect.left() + mViewRect.width()/2 - fm.width(mRoseTitle)/2, mViewRect.top()- fm.height() - 5, mRoseTitle);
}void GRoseView::staAngleCount() //设置数据,要实现根据角度个数
{ //调整刻度数,要求刻度为偶数个,刻度值if (mDatas.count() <= 0) return ; //为正整数int n = ceil(360.0 / mDeltAngle); mAngleCounts.fill(0, n);for (int i=0; i<mDatas.count(); i++){int index = mDatas[i] / mDeltAngle;if (index < 0 || index >= n) continue ;mAngleCounts[index]++;}mCountMax = mAngleCounts[0];for (int i=1; i<mAngleCounts.count(); i++){if (mCountMax < mAngleCounts[i]) {mCountMax = mAngleCounts[i];mBestAzimuth = i * mDeltAngle - mDeltAngle/2.0;}}// 计算出每个角度变换范围对应的半径mAngleRadius.clear();double radius;int base = 6;int relayCount = mCountMax;if (relayCount <= base) relayCount = base;relayCount = ceil((double)relayCount / base) * base;for (int i=0; i<mAngleCounts.count(); i++){radius = mAngleCounts[i] * mMaxRadius / relayCount;mAngleRadius << radius;}setScale(mCountMax);
}void GRoseView::clear()
{mAngleCounts.clear();mAngleRadius.clear();mDatas.clear();mRoseTitle = "";
}void GRoseView::setMargins(int marginTop, int marginBottom, int marginLeft, int marginRight)
{mMargins.setTop(marginTop);mMargins.setBottom(marginBottom);mMargins.setLeft(marginLeft);mMargins.setRight(marginRight);int marginRectWidth = width() - marginLeft - marginRight;int marginRectHeight = height() - marginTop - marginBottom;mViewRect.setRect(mMargins.left(), mMargins.top(), marginRectWidth, marginRectHeight); mMaxRadius = qMin(mViewRect.width()/2, mViewRect.height()/2); mCenter = QPoint((mViewRect.width() >> 1) + mMargins.left(), (mViewRect.height() >> 1) + mMargins.top());
}void GRoseView::setDatas(const QVector<double> &datas)
{mDatas = datas;staAngleCount();
}void GRoseView::setDeltAngle(int deltAngle) //设置角度间隔
{if (deltAngle >360 || deltAngle< 0){mDeltAngle = 10;}else{mDeltAngle = deltAngle;}staAngleCount();update();
}void GRoseView::setCoordFont(const QFont& font)
{mRoseTitleFont = font;
}void GRoseView::setTitleFont(const QFont& font)
{mRoseTitleFont = font;
}void GRoseView::setTitle(const QString& title)
{mRoseTitle = title;
}void GRoseView::setColor(QColor color)
{mColor = color;
}const double & GRoseView::getBestAzimuth()
{return mBestAzimuth;
}bool GRoseView::event(QEvent* event) //提示事件
{if(event->type() == QEvent::ToolTip){QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);double px = helpEvent->x();double py = helpEvent->y();QString s = angleMessageTip(px,py);QToolTip::showText(helpEvent->globalPos(),s);}return QWidget::event(event);
}QString GRoseView::angleMessageTip(double x,double y) //实现角度统计
{double dx = x - mCenter.x();double dy = y - mCenter.y();if(qSqrt(dx*dx + dy*dy) > mMaxRadius) return QString::null;double pointAngle = getPointAngle(x,y); QString s = QString::null;int n = ceil(360.0 / mDeltAngle);int index = pointAngle / mDeltAngle;int angleL = index * mDeltAngle;int angleH = mDeltAngle + index * mDeltAngle;if(angleH >360)angleH = 360;if(mAngleCounts[index] == 0)return NULL;s = ("Angle range :" + QString::number(angleL) + QString::fromLocal8Bit("") + "-" + QString::number(angleH) + QString::fromLocal8Bit("") +"\n");s += "Number of azimuthes : " + QString::number(mAngleCounts[index]) +"\n";if(mAngleCounts[index] == mCountMax)s += "Best advantage azimuth:" + QString::number(mBestAzimuth);return s;
}double GRoseView::getPointAngle(double x,double y) //得到鼠标所在坐标系中的位置
{double x1,y1;double pointRadian,pointAngle;y1 = x - mCenter.x();x1 = mCenter.y() - y;if(x >= mCenter.x()) //[0,pi]{ pointRadian = qAtan2(y1,x1);}else //[pi,2*pi]{pointRadian = qAtan2(y1,x1) + 2*PI ;}pointAngle = 180*pointRadian/PI;return pointAngle;
}void GRoseView::contextMenuEvent(QContextMenuEvent *event) //右键菜单事件
{ //设置函数在构造函数中实现Q_UNUSED(event);QMenu *menu = new QMenu(this);QAction *savepicture = new QAction(this);savepicture->setToolTip("保存图片");savepicture->setText("Saving Picture");menu->addAction(savepicture);connect(savepicture,SIGNAL(triggered(bool)),this,SLOT(on_mSaveRoseView_triggered(bool)));menu->exec(QCursor::pos());delete menu;delete savepicture;
}void GRoseView::savePicture(QString filename) //保存图片
{QPainter p(this);p.setRenderHint(QPainter::Antialiasing);p.setRenderHint(QPainter::TextAntialiasing);QPixmap pixmap(width(),height());pixmap.fill(Qt::transparent);p.begin(&pixmap);drawRoseTitle(&p);drawRosePicture(&p);drawCoordinate(&p);p.end();pixmap.save(filename);
}void GRoseView::on_mSaveRoseView_triggered(bool checked)
{QString fileName = QFileDialog::getSaveFileName(this, windowTitle(),"", QString::fromLocal8Bit("图像文件 ( *.png )"));//*.bmp*.jpg *.jpegthis->savePicture(fileName);
}
Qt 绘制南丁格尔玫瑰图相关推荐
- python+matplotlib绘制南丁格尔玫瑰图
实验:绘制南丁格尔玫瑰图 本实验有一定难度,有人说matplotlib绘图和matlab大同小异,我看除了一些函数名相同之外,其他的像参数和使用方法很不一样.另外我不知道是不是在matlab中画玫 ...
- 使用Matplotlib绘制南丁格尔玫瑰图
前言 在前文中,我们介绍了使用pyecharts绘制南丁格尔玫瑰图,本章我们再学习一下使用matplotlib绘制南丁格尔玫瑰图,了解在极坐标系中绘制柱状图.并对比一下两种不同的绘制方法,如何实现? ...
- python实验之绘制南丁格尔玫瑰图
一.实验目的 了解玫瑰图的前世今生:了解 matplotlib 标准库中的 pyplot 模块:了解在极坐标 系中绘制柱状图. 二.实验基本原理及步骤(或方案设计及理论计算) 实验步骤: 查阅文档,了 ...
- 【Python绘图】pyecharts绘制南丁格尔玫瑰图
from pyecharts.charts import Pie from pyecharts import options as opts import random# 随机颜色生成 def ran ...
- 使用excel中的雷达图绘制南丁格尔玫瑰图
效果展示: 注: 数据文件链接: https://pan.baidu.com/s/1iF_nQ6hhL0MlO8P4qPDuAA 密码: 1snj 数据展示: 绘制思路: 1.计算出确诊人数的平方根( ...
- echarts绘制嵌套环形图(南丁格尔玫瑰图)
根据专业总人数和学院总人数绘制嵌套环形图 首先,echarts的基本步骤 引入js,准备容器,初始化实例, <script src="lib/echarts.min.js"& ...
- R语言ggplot绘制鸡冠花图(南丁格尔玫瑰图)
南丁格尔玫瑰图也就是鸡冠花图,一种极坐标的柱状图.图形的大小跟变量分组的数值呈正比.从极坐标延伸出来的每一环可以当做标尺来使用,用来表示分段的大小并代表数值的高低. 首先绘制柱状图 bar<- ...
- Python数据可视化之南丁格尔玫瑰图(亲测)
文章目录 1. 什么是南丁格尔玫瑰图 2. 南丁格尔玫瑰图的绘制 1. 什么是南丁格尔玫瑰图 央视新闻用来展示疫情0增长天数的图就是南丁格尔玫瑰图. 南丁格尔玫瑰图(Nightingale rose ...
- Python数据可视化之南丁格尔玫瑰图
文章目录 1. 什么是南丁格尔玫瑰图 2. 南丁格尔玫瑰图的绘制 1. 什么是南丁格尔玫瑰图 央视新闻用来展示疫情0增长天数的图就是南丁格尔玫瑰图. 南丁格尔玫瑰图(Nightingale rose ...
- R语言-南丁格尔玫瑰图
简介 南丁格尔玫瑰图(Nightingale rose chart)即极坐标柱形图,是一种圆形的柱形图.由弗罗伦斯-南丁格尔所发明,普通柱形图的坐标系是直角坐标系,而南丁格尔玫瑰图的坐标系是极坐标系. ...
最新文章
- Matlab中画图以及plot函数及legend函数详解
- [c/c++] programming之路(25)、字符串(六)——memset,Unicode及宽字符,strset
- 成绩查询数据结构c语言,学生成绩管理系统(数据结构c语言版源代码)09169.pdf
- 启航~算法刷题第一天
- Oracle Shared Pool优化思路
- Android Q (Android 10.0)系统新特性
- 《51单片机应用开发从入门到精通》——1.3 Keil uVision2集成开发环境
- PHP中的预定义常量、预定义变量、魔术常量
- android社交软件源码,原生仿微信社交社区即时通讯聊天双端APP源码开源 带PC客户端...
- web测试和app测试的区别你知道吗?
- Mobile移动5G通信技术详解
- Taylor Swift - Mean-pdf
- 二进制拆弹(20181023-20181026)
- 命名转小驼峰大驼峰中划线
- 「MoreThanJava」一文了解二进制和CPU工作原理
- 管理费用负数报不了怎么办_管理费用发生额是负数怎么办
- 【程序员入门记录】ThinkPad E470改造记录——换屏
- 多目标/单-VRT路径规划-更新汇总
- HDU-1546 dijkstra
- 如何用word制作英语答题卡_最新初中英语考试答题卡(可编辑WORD版)教程文件