Qt实现能力值控件(多边形能力值控件)

本例分享如何使用Qt实现一个多边形能力值控件

CCapabilityDiagram

效果如下:

图1

直入主题,

头文件:

CCapabilityDiagram.h
#ifndef CCAPABILITYDIAGRAM_H
#define CCAPABILITYDIAGRAM_H

#include <QWidget>
#include <QMetaObject>

class CCapabilityDiagram: public QWidget
{
    Q_OBJECT
public:
    struct CapabilityDiagramItem
    {
        quint64 id;
        QString name;
        quint64 value;
    };
    typedef QList<CapabilityDiagramItem> CapabilityDiagramItemList;

    CCapabilityDiagram(QWidget* parent = NULL);
    ~CCapabilityDiagram();

private:
    quint64 mMaxValue; //* 最大值
    quint64 mMinValue; //* 最小值
    float   mValueScaleMapping; //* 缩放关系
    QColor  mVertexPathBorderColor; //* 顶点边框颜色
    QColor  mVertexPathColor; //* 背景填充色
    QColor  mPercentVertexLineColor; //* 等分线边框颜色
    QColor  mValuePathColor; //* 能力值填充色
    QColor  mValuePathBorderColor; //* 能力值边框色
    quint64 mPercentCount; //* 等分线条数
    QFont   mNameFont; //* item名字的字体
    QColor  mNameColor; //* item名字的颜色

    CapabilityDiagramItemList mCapabilityDiagramItemList;

    void paintEvent(QPaintEvent *e);
    void mouseMoveEvent(QMouseEvent *e);

public:
    void setMaxValue(quint64 v);//* 设置最大值
    quint64 getMaxValue();//* 最大值

    //* 设置最大值和像素的映射关系,必须 > 0,
    //* 例如最大值100, v == 1.5,那么就是150像素来表示100值
    void setValueScaleMapping(float v);

    void setCapabilityDiagramItemList(const CapabilityDiagramItemList& li); //* 设置能力列表
    CapabilityDiagramItemList getCapabilityDiagramItemList(); //* 能力列表
};

Q_DECLARE_METATYPE(CCapabilityDiagram::CapabilityDiagramItem)
Q_DECLARE_METATYPE(CCapabilityDiagram::CapabilityDiagramItemList)

#endif // CCAPABILITYDIAGRAM_H

cpp文件:

CCapabilityDiagram.cpp

#include "CCapabilityDiagram.h"

#include <QPainter>
#include <math.h>
#include <QDebug>

CCapabilityDiagram::CCapabilityDiagram(QWidget *parent)
    :QWidget(parent)
    ,mMaxValue(100)
    ,mMinValue(0)
    ,mValueScaleMapping(1.f)
    ,mPercentCount(10)
{
    this->setMouseTracking(true);
    mVertexPathBorderColor = QColor(91,93,97); //* 顶点边框颜色
    mVertexPathColor = "#5B5E60";
    mVertexPathColor.setAlphaF(0.81);

    mPercentVertexLineColor = QColor(91,93,97); //* 等分线边框颜色

    mValuePathColor = "#C8A666";
    mValuePathColor.setAlphaF(0.6);
    mValuePathBorderColor = QColor(200,166,102);

    mNameColor = "#2D2E2F";
    mNameFont.setFamily("GBJenLei-Medium");
    mNameFont.setPixelSize(14);;

    CapabilityDiagramItemList li;
    for(int i = 0; i <6; i++)
    {
        CapabilityDiagramItem d;
        d.id = i;
        d.name = QString("Item %1").arg(i);
        d.value = i * 20;
        li << d;
    }
    setCapabilityDiagramItemList(li);
}

CCapabilityDiagram::~CCapabilityDiagram()
{

}

void CCapabilityDiagram::paintEvent(QPaintEvent *e)
{
    __super::paintEvent(e);

    int vertexCount = mCapabilityDiagramItemList.count();
    if(vertexCount == 0)
        return;


    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing);
    QPointF centerPoint = rect().center();
    double stepAngle = 360.f / vertexCount;

    const QPointF mousePos = mapFromGlobal(QCursor::pos()) - centerPoint;

    //*设置坐标系原点到cetner
    p.translate(centerPoint);

    //画定点框
    //p.fillRect(QRect(-10,-10, 20,20), Qt::red); //* 用于调试
    QVector<QPointF> vertexPoints;
    quint64 r = mMaxValue;
    for(int i = 0; i < vertexCount; i++)
    {
        //int offsetAngle = stepAngle + (i * stepAngle);
        int offsetAngle = 90 + (i * stepAngle);
        int offsetX = -cos(offsetAngle * 3.1415 / 180.0 ) * r;
        int offsetY = -sin(offsetAngle * 3.1415 / 180.0 ) * r;
        vertexPoints << QPointF(offsetX * mValueScaleMapping, offsetY * mValueScaleMapping);

        //p.drawLine(QPoint(0,0), vertexPoints.last());
    }
    QPainterPath vertexPath;
    vertexPath.addPolygon(vertexPoints);
    p.fillPath(vertexPath, mVertexPathColor);
    p.drawPolygon(vertexPoints); //* 图形的顶点

    //* percentCount等分线 (max / percentCount) 百分线
    p.setPen(QPen(mPercentVertexLineColor, 3, Qt::SolidLine));
    int percentStep = mPercentCount;
    float scaleValue = 1.f/percentStep;
    QList<QVector<QPointF>> percentVertexPointsList;
    for(int i = 0; i < percentStep; i++)
    {
        QVector<QPointF> percentVertexPoints;
        float r = mMaxValue * scaleValue * i;
        for(int ii = 0; ii < vertexCount; ii++)
        {
            //int offsetAngle = stepAngle + (ii * stepAngle);
            int offsetAngle = 90 + (ii * stepAngle);
            int offsetX = -cos(offsetAngle * 3.1415 / 180.0 ) * r;
            int offsetY = -sin(offsetAngle * 3.1415 / 180.0 ) * r;
            percentVertexPoints << QPointF(offsetX * mValueScaleMapping, offsetY * mValueScaleMapping);
        }
        percentVertexPointsList << percentVertexPoints;

        p.drawPoints(percentVertexPoints); //* 等分线顶点
        p.drawPolygon(percentVertexPoints);
    }
    for(int i = 0; i < percentVertexPointsList.count() - 1; i++) //* 画能力值等高线
    {
        QPainterPath percentVertexPath;
        if(i == 0)
        {
            QPainterPath firstPercentVertexPath;
            firstPercentVertexPath.addPolygon(vertexPoints);
            firstPercentVertexPath.addPolygon(percentVertexPointsList[i]);
            p.fillPath(firstPercentVertexPath, i % 2 == 0 ? mVertexPathColor.darker() : mVertexPathColor);

        }

        percentVertexPath.addPolygon(percentVertexPointsList[i]);
        percentVertexPath.addPolygon(percentVertexPointsList[i + 1]);
        p.fillPath(percentVertexPath, i % 2 != 0 ? mVertexPathColor.darker() : mVertexPathColor);
    }

    //* 画顶点线
    p.setPen(QPen(mVertexPathBorderColor.darker(), 1, Qt::SolidLine));
    for(int i = 0; i < vertexPoints.count(); i++)
    {
        p.drawLine(QPoint(0,0), vertexPoints[i]);
    }

    //画能力多边形
    p.setPen(QPen(mValuePathColor, 3, Qt::SolidLine));
    QVector<QPointF> valueVertexPoints;
    for(int i = 0; i < vertexCount; i++)
    {
        float r = mMaxValue * ((float)mCapabilityDiagramItemList[i].value / mMaxValue);
        r = r > mMaxValue ? mMaxValue : r;
        //int offsetAngle = stepAngle + (i * stepAngle);
        int offsetAngle = 90 + (i * stepAngle);
        int offsetX = -cos(offsetAngle * 3.1415 / 180.0 ) * r;
        int offsetY = -sin(offsetAngle * 3.1415 / 180.0 ) * r;
        valueVertexPoints << QPointF(offsetX * mValueScaleMapping, offsetY * mValueScaleMapping);
    }
    QPainterPath valuePath;
    valuePath.addPolygon(valueVertexPoints);
    if(QPolygonF(valueVertexPoints).containsPoint(mousePos, Qt::WindingFill))
    {
        p.fillPath(valuePath, mValuePathColor.lighter());
    }
    else
    {
        p.fillPath(valuePath, mValuePathColor);
    }
    p.drawPolygon(valueVertexPoints);


    //画名字
    p.setPen(QPen(mNameColor, 1, Qt::SolidLine));
    p.setFont(mNameFont);
    for(int i = 0; i < vertexCount; i++)
    {
        QString name = mCapabilityDiagramItemList[i].name;
        int nameWidth = p.fontMetrics().width(name);
        int nameHegiht = p.fontMetrics().height();
        QPoint namePos = vertexPoints[i].toPoint();

        if(namePos.x() < 0) //* 避免遮挡
        {
            namePos.setX(namePos.x() - nameWidth);
        }
        if(namePos.y() < 0)
        {
            namePos.setY(namePos.y() - nameHegiht);
        }

        if(namePos.x() == 0) //* 居中
        {
            namePos.setX(namePos.x() - nameWidth / 2);
        }
        if(namePos.y() == 0)
        {
            namePos.setY(namePos.y() - nameHegiht / 2);
        }

        QRect nameRect = QRect(namePos, QSize(nameWidth, nameHegiht));
        p.drawText(nameRect, Qt::AlignCenter, name);
    }
}

void CCapabilityDiagram::mouseMoveEvent(QMouseEvent *e)
{
    __super::mouseMoveEvent(e);
    update();
}

void CCapabilityDiagram::setMaxValue(quint64 v)
{
    mMaxValue = v;
    update();
}

quint64 CCapabilityDiagram::getMaxValue()
{
    return mMaxValue;
}

void CCapabilityDiagram::setValueScaleMapping(float v)
{
    mValueScaleMapping = v;
    update();
}

void CCapabilityDiagram::setCapabilityDiagramItemList(const CCapabilityDiagram::CapabilityDiagramItemList &li)
{
    mCapabilityDiagramItemList = li;
    update();
}

CCapabilityDiagram::CapabilityDiagramItemList CCapabilityDiagram::getCapabilityDiagramItemList()
{
    return mCapabilityDiagramItemList;
}

 

在实现了我们的控件之后来尝试一下如何使用:

#include <QApplication>

#include "CCapabilityDiagram.h"


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    CCapabilityDiagram* capabilityDiagram = new CCapabilityDiagram;
    CCapabilityDiagram::CapabilityDiagramItemList li;
    for(int i = 0; i <6; i++)
    {
        CCapabilityDiagram::CapabilityDiagramItem d;
        d.id = i;
        d.name = QString(QStringLiteral("能力值 %1")).arg(i);
        d.value = i * 20;
        li << d;
    }
    capabilityDiagram->setCapabilityDiagramItemList(li);

    capabilityDiagram->show();

    return a.exec();
}

 

运行结果:

至此我们使用Qt来实现一个多边形能力值控件就成功了。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值