QT使用QPainter绘制多边形维度图

        多边形统计维度图是一种用于展示多个维度的数据的图表。它通过将各个维度表示为图表中的多边形的边,根据数据的大小和比例来确定各个维度的长度。

一、简述

         本示例实现六边形战力统计维度图,一种将六个维度的战力统计以六边形图形展示的方法。六个维度是:攻击力、防御力、速度、智力、生命值、特殊能力。六边形战力统计维度图将这些维度以六个边长不等的六边形表示,每个边长代表对应维度的数值大小。通过连接这些边,可以得到一个多边形,多边形的形状和大小表示单位的整体战斗能力。一般来说,这个多边形越接近完整的六边形,说明单位在各项能力上都相对均衡和强大。

二、 设计思路        

        要实现多边形统计维度图,基类选择QWidget,使用QPainter根据图形需求画出图形。

设计思路:

  1. 将统计维度分别表示为顶点,分别标注在顶点上。这些统计维度可以根据具体需求进行选择,例如攻击力、防御力、速度等。

  2. 在多边形图的上,可以设置不同的刻度值,表示不同的水平。根据统计数据的大小,可以将数据点标注在相应的位置上。

  3. 使用不同的颜色或图案来表示不同的统计数据点,以便更好地区分不同的数据。

  4. 在六边形图的周围添加标签,用来说明各个战力统计维度的含义,以便用户更好地理解图表。

三、效果 

四、核心代码  
1、头文件
#ifndef DIMENSIONCHARTWIDGET_H
#define DIMENSIONCHARTWIDGET_H

#include <QMap>
#include <QPen>
#include <QObject>
#include <QWidget>

class DimensionInfo;
class DimensionChartWidget : public QWidget
{
    Q_OBJECT

public:
    explicit DimensionChartWidget(QWidget *parent = nullptr);

    inline QColor backgroundColor() const { return m_backgroundColor; }
    inline void setBackgroundColor(const QColor &backgroundColor) { m_backgroundColor = backgroundColor; }

    inline float radius() const { return m_radius; }// 设置维度半径
    inline void setRadius(float radius) { m_radius = radius; }

    inline int sidesNumber() const { return m_sidesNumber; } // 设置维度网格数量
    inline void setSidesNumber(int sidesNumber) {m_sidesNumber = sidesNumber; }

    inline QPen sidesPen() const { return m_sidesPen; }// 设置维度网格画笔
    inline void setSidesPen(const QPen &sidesPen) { m_sidesPen = sidesPen; }

    inline QVector<DimensionInfo> dimensionInfos() const { return m_dimensionInfos; }
    inline void setDimensionInfos(const QVector<DimensionInfo> &dimensionInfos) { m_dimensionInfos = dimensionInfos; }

    inline QPen textPen() const { return m_textPen; }//设置字体画笔
    inline void setTextPen(const QPen &textPen) { m_textPen = textPen; }

    inline QPen dimensionPen() const { return m_dimensionPen; }// 设置维度画笔
    inline void setDimensionPen(const QPen &dimensionPen) { m_dimensionPen = dimensionPen; }

    inline QFont textFont() const { return m_textFont; }//设置字体
    inline void setTextFont(const QFont &textFont) { m_textFont = textFont; }

    inline int filletRadius() const { return m_filletRadius; }
    inline void setFilletRadius(int filletRadius) { m_filletRadius = filletRadius; }

protected:
    void paintEvent(QPaintEvent*);
    void drawText(QPainter&, QPointF, QString text);
    void convertPoint(QPointF&);

private:
    void init();

private:
    QPen m_textPen;
    QPen m_sidesPen;
    QPen m_dimensionPen;
    QFont m_textFont;
    QColor m_backgroundColor;

    int m_filletRadius;
    float m_radius;
    int m_sidesNumber;
    QVector<DimensionInfo> m_dimensionInfos;
};


class DimensionInfo {
public:
    DimensionInfo() = default;
    DimensionInfo(QString text, float percentage) { m_text = text; m_percentage = percentage; }

    inline QString text() const { return m_text; }
    inline void setText(const QString &text) { m_text = text; }

    inline float percentage() const { return m_percentage; }
    inline void setPercentage(float percentage) { m_percentage = percentage; }

private:
    QString m_text;
    float m_percentage;
};
#endif // DIMENSIONCHARTWIDGET_H
2、实现代码
#include "DimensionChartWidget.h"
#include <QPainter>
#include <QtMath>
#include <QPainterPath>

DimensionChartWidget::DimensionChartWidget(QWidget *parent) : QWidget(parent)
{
    m_radius = 0;
    m_sidesNumber = 1;

    init();
}

void DimensionChartWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    painter.setPen(QColor(m_backgroundColor));
    painter.setBrush(QBrush(m_backgroundColor));
    painter.drawRoundedRect(rect(), m_filletRadius, m_filletRadius);

    // 绘图设备的坐标原点(0,0)在左上角,水平向右增长,垂直向下增长。
    // 将坐标系原点移动到界面中间
    painter.translate(width() / 2.0, height() / 2.0);

    // 设中心点到边的垂线与半径的夹角为degree=(360/count)/2
    float degree = 360.0 / m_dimensionInfos.size();

    // 开始绘制多边形,并为每个区域上色
    painter.setPen(m_sidesPen);
    QPointF lastPoint(0, -m_radius);
    QVector<QPointF> points;
    for(int i = 0; i < m_dimensionInfos.size(); i++)
    {
        float radian = qDegreesToRadians(degree * (i + 1));
        float x = m_radius * qSin(radian);
        float y = m_radius * qCos(radian);

        // 绘制该三角区块
        QPainterPath path;
        QPointF point(x, -y);
        path.lineTo(point);
        path.lineTo(lastPoint);
        path.lineTo(0, 0);
        painter.drawPath(path);

        //  绘制内线
        for(int j = m_sidesNumber - 1; j > 0; j--)
        {
            float multiple = (float)j / m_sidesNumber;
            painter.drawLine(point * multiple, lastPoint * multiple);
        }

        // 绘制文本
        painter.save();
        painter.setPen(m_textPen);
        painter.setFont(m_textFont);
        drawText(painter, point, m_dimensionInfos.at(i).text());
        painter.restore();

        lastPoint = point;
        points << point * m_dimensionInfos.at(i).percentage();
    }

    // 绘制维度信息
    painter.setPen(m_dimensionPen);
    QColor color = m_dimensionPen.color();
    color.setAlpha(150);
    painter.setBrush(QBrush(color));
    QPolygonF polygon(points);
    QPainterPath painterPath;
    painterPath.addPolygon(polygon);
    painter.drawPolygon(polygon);
}

//绘制文本
void DimensionChartWidget::drawText(QPainter& painter, QPointF point, QString text)
{
    convertPoint(point);
    QRectF textRect;
    textRect.setSize(QSize(50, 30));
    int flag = Qt::AlignCenter;
    if(point.x() > 0)
    {
        if(point.y() < 0)
        {
            //x > 0 y < 0
            textRect.setBottomLeft(point);
            textRect.setTopRight(QPoint(point.x() + 50, point.y() - 30));
            flag = Qt::AlignBottom | Qt::AlignLeft;
        }
        else if(point.y() > 0)
        {
            //x>0 y>0
            textRect.setTopLeft(point);
            textRect.setBottomRight(QPoint(point.x() + 50, point.y() + 30));
            flag = Qt::AlignTop | Qt::AlignLeft;
        }
        else
        {
            //x>0 y=0
            point.setY(point.y() - 15);
            textRect.setTopLeft(point);
            textRect.setBottomRight(QPoint(point.x() + 50, point.y() + 30));
            flag = Qt::AlignVCenter | Qt::AlignLeft;
        }
    }
    else if(point.x() < 0)
    {
        if(point.y() < 0)
        {
            //x<0 y<0
            textRect.setBottomRight(point);
            textRect.setTopLeft(QPoint(point.x() - 50, point.y() - 30));
            flag = Qt::AlignBottom | Qt::AlignRight;
        }
        else if(point.y() > 0)
        {
            //x<0 y>0
            textRect.setTopRight(point);
            textRect.setBottomLeft(QPoint(point.x() - 50, point.y() + 30));
            flag = Qt::AlignTop | Qt::AlignRight;
        }
        else
        {
            //x<0 y=0
            point.setY(point.y() - 15);
            textRect.setTopRight(point);
            textRect.setBottomLeft(QPoint(point.x() - 50, point.y() + 30));
            flag = Qt::AlignVCenter | Qt::AlignRight;
        }
    }
    else
    {
        if(point.y() < 0)
        {
            //x=0 y<0
            point.setX(point.x() - 25);
            textRect.setBottomRight(point);
            textRect.setTopLeft(QPoint(point.x() + 50, point.y() - 30));
            flag = Qt::AlignHCenter | Qt::AlignBottom;
        }
        else if(point.y() > 0)
        {
            //x=0 y>0
            point.setX(point.x() - 25);
            textRect.setTopLeft(point);
            textRect.setBottomRight(QPoint(point.x() + 50, point.y() + 30));
            flag = Qt::AlignHCenter | Qt::AlignTop;
        }
    }
    painter.drawText(textRect, flag, text);
}

void DimensionChartWidget::convertPoint(QPointF& point)
{
    if(qAbs(point.x()) < 0.001)
    {
        point.setX(0);
    }
    else if(qAbs(point.y()) < 0.001)
    {
        point.setY(0);
    }
}

void DimensionChartWidget::init()
{
    setBackgroundColor(QColor(255,255,255));

    // 设置维度网格数量
    setSidesNumber(5);

    // 设置维度半径
    setRadius(120);

    // 设置维度网格画笔
    QPen sidesPen;
    sidesPen.setColor(QColor("#0095C5"));
    sidesPen.setWidth(2);
    setSidesPen(sidesPen);

    // 设置维度画笔
    QPen dimensionPen;
    dimensionPen.setColor(Qt::GlobalColor::red);
    dimensionPen.setWidth(3);
    setDimensionPen(dimensionPen);

    // 设置字体信息
    QPen textPen;
    setTextPen(textPen);
    QFont textFont;
    textFont.setFamily("微软雅黑");
    textFont.setPointSize(10);
    setTextFont(textFont);
}

        以上是多边形统计维度图实现代码,在实际使用中,可以根据需要进行扩展,添加一些其他的功能。例如:

  1. 支持多边形的操作。使其支持多边形的旋转、平移、缩放等操作,以方便更灵活地对多边形进行分析和展示。

  2. 导入和导出多边形数据。我们可以添加文件读写功能,允许用户从外部文件导入多边形数据,并将统计维度的结果保存到文件中。

        这些功能的添加可以进一步提升多边形统计维度图的实用性和灵活性。根据具体的需求,我们可以选择扩展代码的功能,以适应不同的应用场景。      

五、使用示例

以下是一个简单的示例代码,演示了如何在Qt中使用此控件:

#include "mainwindow.h"
#include "DimensionChartWidget.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setWindowTitle("维度图");
    resize(400, 400);

    DimensionChartWidget* pDimensionChartWidget = new DimensionChartWidget(this);
    pDimensionChartWidget->resize(this->width() - 60, this->height() -60);
    pDimensionChartWidget->move(30, 30);

    QVector<DimensionInfo> dimensionInfos;
    DimensionInfo dimensionInfo("攻击力", 0.55);
    dimensionInfos.append(dimensionInfo);
    dimensionInfo.setText("防御力");
    dimensionInfo.setPercentage(0.85);
    dimensionInfos.append(dimensionInfo);
    dimensionInfo.setText("速度");
    dimensionInfo.setPercentage(0.95);
    dimensionInfos.append(dimensionInfo);
    dimensionInfo.setText("智力");
    dimensionInfo.setPercentage(0.45);
    dimensionInfos.append(dimensionInfo);
    dimensionInfo.setText("生命值");
    dimensionInfo.setPercentage(0.65);
    dimensionInfos.append(dimensionInfo);
    dimensionInfo.setText("特殊能力");
    dimensionInfo.setPercentage(0.65);
    dimensionInfos.append(dimensionInfo);
    pDimensionChartWidget->setDimensionInfos(dimensionInfos);
}

MainWindow::~MainWindow()
{

}

        以上示例是一个六边形战力统计维度图,可以用于综合评估某个实体在不同维度上的战力表现。通过提供各个维度的评分和连接评分最高点的边界来展示实体在不同维度上的能力表现。这样的图表可以帮助决策者更全面地了解和比较实体的战力,从而做出更准确的决策。

        谢谢您的关注和阅读!如有任何问题或需要帮助,请随时与我联系。希望您能继续支持并享受更多精彩的内容。祝您生活愉快!

六、源代码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/802304.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WebAssembly与JavaScript的交互(1)

前一阵子利用Balazor开发了一个NuGet站点&#xff0c;对WebAssembly进行了初步的了解&#xff0c;觉得挺有意思。在接下来的一系列文章中&#xff0c;我们将通过实例演示的方式介绍WebAssembly的一些基本概念和编程模式。首先我们先来说说什么是WebAssembly&#xff0c;它主要帮…

微调 Florence-2 - 微软的尖端视觉语言模型

Florence-2 是微软于 2024 年 6 月发布的一个基础视觉语言模型。该模型极具吸引力&#xff0c;因为它尺寸很小 (0.2B 及 0.7B) 且在各种计算机视觉和视觉语言任务上表现出色。 Florence 开箱即用支持多种类型的任务&#xff0c;包括: 看图说话、目标检测、OCR 等等。虽然覆盖面…

LRC软件、Adobe Lightroom Classic软件多版本下载+LRC教程

简介&#xff1a; Adobe Lightroom Classic&#xff08;简称LR&#xff09;是Adobe Creative Cloud大家庭中的一款专业的图片管理和编辑工具&#xff0c;用于专业摄影师、摄影爱好者以及所有不断优化数码影像的人等。其目标是以丰富的功能提供高效、一致的体验&#xff0c;帮助…

php基础: 三角形

包含&#xff1a;左三角、左上三角、右三角、右上三角、等腰三角、倒等腰三角。注意空格的数量&#xff0c;因为*号后面加了空格 /*** * 左三角形* param $n* return void*/ function triangleLeft($n){echo <pre>;for ($i 1; $i < $n; $i) {for ($j 1; $j < $i…

对服务器进行基本了解(二)

目录 一. 云服务器数据库 1.查看MYSQL版本 2.查看mysql的运行状态 3.运行mysql 4. 进入mysql的用户 5. 更改用户密码 6. 查找mysql端口号 7. 创建一个数据库 8. 查看用户 9. 查看数据库 10. 显示数据库的表 11. 修改用户的host 12. 对用户赋权 13. 开放指定端…

java.lang.IllegalArgumentException: Illegal character in path at index 40解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

数据库内核研发学习之路(三)创建postgres内置函数

本章之前已经讲明白了我们的postgres如何进行编译安装&#xff0c;这是很重要的一步&#xff0c;接下来就是学会对postgres进行小的改动&#xff0c;然后保证依然能够顺利编译安装运行&#xff01; 本章续讲内容如何创建一个内置函数。 1、内置函数和用户自定义函数的区别 熟…

基于Python+Flask+SQLite的豆瓣电影可视化系统

FlaskMySQLEcharts 基于PythonFlaskSQLite的豆瓣电影可视化系统 Echarts 不支持登录注册&#xff0c;并且信息存储在数据库中 不含爬虫代码&#xff0c;或爬虫代码已失效 简介 基于PythonFlaskMySQL的豆瓣电影可视化系统&#xff0c;采用Echart构建图表&#xff0c;支持自定…

【数据结构】二叉树全攻略,从实现到应用详解

​ &#x1f48e;所属专栏&#xff1a;数据结构与算法学习 &#x1f48e; 欢迎大家互三&#xff1a;2的n次方_ ​ &#x1f341;1. 树形结构的介绍 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做…

动手学深度学习6.3 填充和步幅-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记&#xff0c;以及对课后练习的一些思考&#xff0c;自留回顾&#xff0c;也供同学之人交流参考。 本节课程地址&#xff1a;填充和步幅_哔哩哔哩_bilibili 代码实现_哔哩哔哩_bilibili 本节教材地址&#xff1a;6.3. 填充和…

旗晟巡检机器人的应用场景有哪些?

巡检机器人作为现代科技的杰出成果&#xff0c;已广泛应用于各个关键场景。从危险的工业现场到至关重要的基础设施&#xff0c;它们的身影无处不在。它们以精准、高效、不知疲倦的特性&#xff0c;担当起保障生产、守护安全的重任&#xff0c;为行业发展注入新的活力。那么&…

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(一)-3GPP TS 23.256 技术规范概述

3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Aircraft-to-Everything&#xff09;服务的支持。 3GPP TS 23.256 技术规范&#xff1a; 以下是文档的核心内容总结&#xff1a; UAV系…

深入理解PostgreSql域类型(Domain),灵活定义数据约束,让表结构设计更加严谨

在PostgreSQL中&#xff0c;域&#xff08;Domain&#xff09;是一种用户定义的数据类型&#xff0c;它基于系统内已存在的数据类型&#xff0c;并可以附加约束条件。使用域可以增强数据的完整性和一致性&#xff0c;因为它允许开发者对特定列设定更为具体的规则&#xff0c;比…

Mysql缓存调优的基本知识(附Demo)

目录 前言1. 配置2. 缓存3. 策略 前言 基本的知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09;Mysql优化高级篇&#xff08;全&#xff09;Mysql底层原理详细剖析常见面试题&#xff08;全&#xff09; MySQL…

集群架构-web服务器(接入负载均衡+数据库+会话保持redis)--15454核心配置详解

紧接着前面的集群架构深化—中小型公司&#xff08;拓展到大型公司业务&#xff09;–下面图简单回顾一下之前做的及故障核心知识总结&#xff08;等后期完全整理后&#xff0c;上传资源希望能帮大家&#xff09; web集群架构-接入负载均衡部署web02服务器等 web集群-搭建web0…

Abaqus基于CT断层扫描的三维重建插件CT2Model 3D

插件介绍 AbyssFish CT2Model 3D V1.0 插件可将采用X射线等方法获取的计算机断层扫描&#xff08;CT&#xff09;图像在Abaqus有限元软件内进行三维重建&#xff0c;进而高效获取可供模拟分析的有限元模型。插件可用于医学影像三维重构、混凝土细观三维重建、岩心数字化等领域…

数据结构-C语言-排序(2)

代码位置&#xff1a;test-c-2024: 对C语言习题代码的练习 (gitee.com) 一、前言&#xff1a; 1.1-排序定义&#xff1a; 排序就是将一组杂乱无章的数据按照一定的规律&#xff08;升序或降序&#xff09;组织起来。(注&#xff1a;我们这里的排序采用的都为升序) 1.2-排序分…

2-36 基于matlab的流行学习算法程序

基于matlab的流行学习算法程序。通过GUI的形式将MDS、PCA、ISOMAP、LLE、Hessian LLE、Laplacian、Dissusion MAP、LTSA八种算法。程序以可视化界面进行展示&#xff0c;可直接调用进行分析。多种案例举例说明八种方法优劣&#xff0c;并且可设置自己数据进行分析。程序已调通&…

STM32智能工业自动化监控系统教程

目录 引言环境准备智能工业自动化监控系统基础代码实现&#xff1a;实现智能工业自动化监控系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;工业自动化与管理问题解决方案与优化收尾与总结 1. 引言 智能…

百度人脸识别Windows C++离线sdk C#接入

百度人脸识别Windows C离线sdk C#接入 目录 说明 设计背景 • 场景特点&#xff1a; • 客户特点&#xff1a; • 核心需求&#xff1a; SDK 包结构 效果 代码 说明 自己根据SDK封装了动态库&#xff0c;然后C#调用。 功能接口 设计背景 • 场景特点&#xff1a; -…