项目中用来统计数据的一个数据分析部件,

可以统计某范围中的角度个数,(该范围可由外部指定),通过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 绘制南丁格尔玫瑰图相关推荐

  1. python+matplotlib绘制南丁格尔玫瑰图

    实验:绘制南丁格尔玫瑰图   本实验有一定难度,有人说matplotlib绘图和matlab大同小异,我看除了一些函数名相同之外,其他的像参数和使用方法很不一样.另外我不知道是不是在matlab中画玫 ...

  2. 使用Matplotlib绘制南丁格尔玫瑰图

    前言 在前文中,我们介绍了使用pyecharts绘制南丁格尔玫瑰图,本章我们再学习一下使用matplotlib绘制南丁格尔玫瑰图,了解在极坐标系中绘制柱状图.并对比一下两种不同的绘制方法,如何实现? ...

  3. python实验之绘制南丁格尔玫瑰图

    一.实验目的 了解玫瑰图的前世今生:了解 matplotlib 标准库中的 pyplot 模块:了解在极坐标 系中绘制柱状图. 二.实验基本原理及步骤(或方案设计及理论计算) 实验步骤: 查阅文档,了 ...

  4. 【Python绘图】pyecharts绘制南丁格尔玫瑰图

    from pyecharts.charts import Pie from pyecharts import options as opts import random# 随机颜色生成 def ran ...

  5. 使用excel中的雷达图绘制南丁格尔玫瑰图

    效果展示: 注: 数据文件链接: https://pan.baidu.com/s/1iF_nQ6hhL0MlO8P4qPDuAA 密码: 1snj 数据展示: 绘制思路: 1.计算出确诊人数的平方根( ...

  6. echarts绘制嵌套环形图(南丁格尔玫瑰图)

    根据专业总人数和学院总人数绘制嵌套环形图 首先,echarts的基本步骤 引入js,准备容器,初始化实例, <script src="lib/echarts.min.js"& ...

  7. R语言ggplot绘制鸡冠花图(南丁格尔玫瑰图)

    南丁格尔玫瑰图也就是鸡冠花图,一种极坐标的​柱状图.图形的大小跟变量分组的数值呈正比.从极坐标延伸出来的每一环可以当做标尺来使用,用来表示分段的大小并代表数值的高低. 首先绘制柱状图 bar<- ...

  8. Python数据可视化之南丁格尔玫瑰图(亲测)

    文章目录 1. 什么是南丁格尔玫瑰图 2. 南丁格尔玫瑰图的绘制 1. 什么是南丁格尔玫瑰图 央视新闻用来展示疫情0增长天数的图就是南丁格尔玫瑰图. 南丁格尔玫瑰图(Nightingale rose ...

  9. Python数据可视化之南丁格尔玫瑰图

    文章目录 1. 什么是南丁格尔玫瑰图 2. 南丁格尔玫瑰图的绘制 1. 什么是南丁格尔玫瑰图 央视新闻用来展示疫情0增长天数的图就是南丁格尔玫瑰图. 南丁格尔玫瑰图(Nightingale rose ...

  10. R语言-南丁格尔玫瑰图

    简介 南丁格尔玫瑰图(Nightingale rose chart)即极坐标柱形图,是一种圆形的柱形图.由弗罗伦斯-南丁格尔所发明,普通柱形图的坐标系是直角坐标系,而南丁格尔玫瑰图的坐标系是极坐标系. ...

最新文章

  1. Matlab中画图以及plot函数及legend函数详解
  2. [c/c++] programming之路(25)、字符串(六)——memset,Unicode及宽字符,strset
  3. 成绩查询数据结构c语言,学生成绩管理系统(数据结构c语言版源代码)09169.pdf
  4. 启航~算法刷题第一天
  5. Oracle Shared Pool优化思路
  6. Android Q (Android 10.0)系统新特性
  7. 《51单片机应用开发从入门到精通》——1.3 Keil uVision2集成开发环境
  8. PHP中的预定义常量、预定义变量、魔术常量
  9. android社交软件源码,原生仿微信社交社区即时通讯聊天双端APP源码开源 带PC客户端...
  10. web测试和app测试的区别你知道吗?
  11. Mobile移动5G通信技术详解
  12. Taylor Swift - Mean-pdf
  13. 二进制拆弹(20181023-20181026)
  14. 命名转小驼峰大驼峰中划线
  15. 「MoreThanJava」一文了解二进制和CPU工作原理
  16. 管理费用负数报不了怎么办_管理费用发生额是负数怎么办
  17. 【程序员入门记录】ThinkPad E470改造记录——换屏
  18. 多目标/单-VRT路径规划-更新汇总
  19. HDU-1546 dijkstra
  20. 如何用word制作英语答题卡_最新初中英语考试答题卡(可编辑WORD版)教程文件

热门文章

  1. 站在商业、技术与人文三叉路口的实体书店
  2. 虚拟服务器怎么选操作系统,虚拟主机怎样选择合适的操作系统
  3. UML系列——包图Package
  4. 被认为是世界史上50个最伟大的发明有哪些?
  5. 利用吉洪若夫正则化及其西尔韦斯特方程来修复受损图像
  6. 快速导出PDF文件中所有图片(使用Adobe Acrobat 10 )
  7. 如何将图片转成png格式?图片的格式怎么转换
  8. 影响中国软件人物之:倪光南院士
  9. 阿里云如何查看服务器操作系统
  10. 台式计算机无线接入,台式计算机有线连接路由器WiFi方法图步骤,可以详细设置无线内容(...