Qt例子学习笔记 - Examples/Qt-6.2.0/charts/donutbreakdown

//创建甜甜圈细分图表
//让我们首先为图表定义一些数据。

    QPieSeries *series1 = new QPieSerise();
    series1->setName("Fossil fuels");
    series1->append("Oil",353295);
    series1->append("Coal",188500);
    series1->append("Naturel gas",148680);
    series1->append("Peat",94545);

    QPieSeries *series2 = new QPieSeries();
    series2->setName("Renewables");
    series2->append("Wood fuels",319663);
    series2->append("Hydro power",45875);
    series2->append("Wind power",1060);

    QPieSeries *series3 = new QPieSeries();
    series3->setName(Others);
    series3->append("Nuclear energy",238789);
    series3->append("Import energy",37802);
    series3->append("other",32441);

//然后我们创建一个图表,在其中添加数据。
//请注意,这是我们自己从 QChart 派生的图表。

    DonutBreakdownChart *donutBreakdown = new DonutBreakdownChart();
    donutBreakdown->setAnimationOptions(QChart::AllAnimations);
    donutBreakdown->legend()->setAlignment(Qt::AlignRight);
    donutBreakdown->addBreakdownSeries(series1,Qt::red);
    donutBreakdown->addBreakdownSeries(series2,Qt::darkGreen);
    donutBreakdown->addBreakdownSeries(series3,Qt::darkBlue);

//我们自己的图表以这样一种方式工作:
//我们在构造函数中创建一个主系列,
//我们创建一个主系列,它聚合了细分系列提供的数据。
//这是中间的饼图。

    DonutBreakdownChart::DonutBreakdownChart(QGraphicsItem *parent,Qt::WindowFlags &Flags)
        :QChart(QChart::ChartTypeCartesian,parent,wFlags)
    {
        //create the series for main center pie
        m_mainSeries = new QPieSeries();
        m_mainSeries->setPieSize(0.7);
        QChart::addSeries(m_mainSeries);
    }

//当添加细分系列时,数据用于在主系列中创建切片
//细分系列本身用于创建定位的甜甜圈段,
//使其与主系列中的相应切片对齐。

    void DonutBreakdownChart::addBreakdownSeries(QPieSeries *breakdownSeries,QColor color)
    {
        QFont font("Arial",8);

        //add breakdown series as a slice to enter pie
        MainSlice *mainSlice = new MainSlice(breakdownSeries);
        mainSlice->setName(breakdownSeries->name());
        mainSlice->setValue(breakdownSeries->sum());
        m_mainSeries->append(mainSlice);

        //customize the slice
        mainSlice->setBrush(color);
        mainSlice->setLabelVisible();
        mainSlice->setLabelColor(Qt::white);
        mainSlice->setLabelPosition(QPieSlice::LabelInsideHorizontal);
        mainSlice->setLabelFont(font);

        //position and customize the breakdown series
        breakdownSeries->setPieSize(0.8);
        breakdownSeries->setHoleSize(0.7);
        breakdownSeries->setLabelsVisible();
        const auto slices = breakdownSeries->slices();
        for(QPieSlice *slice : slices)
        {
            color = color.lighter(115);
            slice->setBrush(color);
            slice->setLabelFont(font);
        }

        //add the series to the chart
        QChart::addSeries(breakdownSeries);

        //recalculate breakdown donut segment
        recalculateAngles();

        //update customize legend markers
        updateLegendMarkers();
    }

//下面是如何计算甜甜圈段的开始和结束角度。

    void DonutBreakdownChart::recalculateAngles()
    {
        float angle = 0;
        const auto slices = m_mainSeries->slices();
        for(QPieSlice *slice :: slices)
        {
            QPieSeries *breakdownSeries = qobeject_cast<MainSlice *>(slice)->breakdownSeries();
            breakdownSeries->setPieStartAngle(angle);
            angle += slice->percentage() * 360.0; //full pie is 360.0
            breakdownSeries->setPieEndAngle(angle);
        }
    }

//自定义图例标记以显示细分百分比。 主关卡切片的标记被隐藏。

    void DonutBreakdownChart::updateLegendMarkers()
    {
        //go through all markers
        const auto aliseries = series();
        for(QAbstractSeries *series : allseries)
        {
            const auto markers = legend()->marker(series);
            for(QLegendMarker *maker : makers)
            {
                QPieLegendMarker *pieMarker = qobject_cast<QPieLegendMarker*>(marker);
                if(series == m_mainSeries)
                {
                    //hide markers from main series
                    pieMarker->setVisible(false);
                }
                else
                {
                    //modify markers from breakdown series
                    pieMarker->setLabel(QString("%1 %2")
                                .arg(pieMarker->slice()->label())
                                .arg(pieMarker->slice()->percentage() * 100,0,'f',2));
                    pieMarker->setFont(QFont("Arial",8));            
                }
            }
        }
    }

//相反,主要级别切片在标签上显示百分比。

    MainSlice::MainSlice(QPieSeries *breakdownSeries,QObject *parent)
        :QPieSlice(parent)
        ,m_breakdownSeries(breakdownSeries)
    {
        connect(this,&MainSlice::percentageChanged,this,&MainSlice::updateLabel);
    }
    
    void MainSlice::updateLabel()
    {
        this->setLabel(QString("%1 %2").arg(m_name).arg(percentage() * 100,0,'f',2));
    }

//现在我们已经定义了图表,我们最终可以创建一个 QChartView 并显示图表。

    QMainWindow window;
    QChartView *chartView = new QChartView(donutBreakdown);
    charView->setRenderHint(QPainter::Antialiasing);
    window.setCentralWidget(chartView);
    window.resize(800,500);
    window.show();

main.cpp

#include 
#include 
#include 
#include 
#include "donutbreakdownchart.h"

QT_USE_NAMESPACE

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

    //![1]
    // Graph is based on data of 'Total consumption of energy increased by 10 per cent in 2010'
    // Statistics Finland, 13 December 2011
    // http://www.stat.fi/til/ekul/2010/ekul_2010_2011-12-13_tie_001_en.html

    QPieSeries *series1 = new QPieSeries();
    series1->setName("Fossil fuels");
    series1->append("Oil", 353295);
    series1->append("Coal", 188500);
    series1->append("Natural gas", 148680);
    series1->append("Peat", 94545);

    QPieSeries *series2 = new QPieSeries();
    series2->setName("Renewables");
    series2->append("Wood fuels", 319663);
    series2->append("Hydro power", 45875);
    series2->append("Wind power", 1060);

    QPieSeries *series3 = new QPieSeries();
    series3->setName("Others");
    series3->append("Nuclear energy", 238789);
    series3->append("Import energy", 37802);
    series3->append("Other", 32441);
    //![1]

    //![2]
    DonutBreakdownChart *donutBreakdown = new DonutBreakdownChart();
    donutBreakdown->setAnimationOptions(QChart::AllAnimations);
    donutBreakdown->setTitle("Total consumption of energy in Finland 2010");
    donutBreakdown->legend()->setAlignment(Qt::AlignRight);
    donutBreakdown->addBreakdownSeries(series1, Qt::red);
    donutBreakdown->addBreakdownSeries(series2, Qt::darkGreen);
    donutBreakdown->addBreakdownSeries(series3, Qt::darkBlue);
    //![2]

    //![3]
    QMainWindow window;
    QChartView *chartView = new QChartView(donutBreakdown);
    chartView->setRenderHint(QPainter::Antialiasing);
    window.setCentralWidget(chartView);
    window.resize(800, 500);
    window.show();
    //![3]

    return a.exec();
}

mainslice.h

#ifndef MAINSLICE_H
#define MAINSLICE_H

#include 
#include 

QT_USE_NAMESPACE
//饼图有一个值和一个标签。
//当切片添加到饼图系列时,
//QPieSeries 对象计算切片占系列中所有切片总和的百分比
//以确定图表中切片的实际大小。
//饼图切片有一个值和一个标签 .
//当切片添加到饼图系列时
//QPieSeries 对象计算切片与系列中所有切片的总和相比的百分比,
//以确定图表中切片的实际大小。
//默认情况下,标签是隐藏的。
//如果它是可见的,它可以位于切片外部并通过臂连接到它
//或者水平或平行于切片弧的切线或法线在切片内部居中。
//默认情况下,切片的视觉外观由主题设置,
//但可以通过指定切片属性来覆盖主题。
//但是,如果在自定义切片后更改主题,则所有自定义都将丢失。
//为了使用户能够与饼图进行交互,
//当用户单击饼图或将鼠标悬停在饼图上时
//会发出一些基本信号。

class MainSlice : public QPieSlice
{
    Q_OBJECT
public:
    MainSlice(QPieSeries *breakdownSeries, QObject *parent = 0);
    //饼图系列由定义为 QPieSlice 对象的切片组成。
    //切片可以有任何值
    //因为 QPieSeries 对象计算切片与系列中所有切片总和的百分比
    //以确定图表中切片的实际大小
    //图表上的饼图大小和位置通过使用范围从 0.0 到 1.0 
    //的相对值进行控制。
    //这些与实际的图表矩形有关。
    //默认情况下,饼图定义为完整饼图。
    //可以通过设置系列的起始角度和角度跨度来创建部分饼图
    //一个完整的馅饼是 360 度,其中 0 是 12 点钟。
    QPieSeries *breakdownSeries() const;

    void setName(QString name);
    QString name() const;

public Q_SLOTS:
    void updateLabel();

private:
    QPieSeries *m_breakdownSeries;
    QString m_name;
};

#endif // MAINSLICE_H

mainslice.cpp

#include "mainslice.h"

QT_USE_NAMESPACE

//![1]
MainSlice::MainSlice(QPieSeries *breakdownSeries, QObject *parent)
    : QPieSlice(parent),
      m_breakdownSeries(breakdownSeries)
{
    connect(this, &MainSlice::percentageChanged, this, &MainSlice::updateLabel);
}
//![1]

QPieSeries *MainSlice::breakdownSeries() const
{
    return m_breakdownSeries;
}

void MainSlice::setName(QString name)
{
    m_name = name;
}

QString MainSlice::name() const
{
    return m_name;
}

//![2]
void MainSlice::updateLabel()
{
    this->setLabel(QString("%1 %2%").arg(m_name).arg(percentage() * 100, 0, 'f', 2));
}
//![2]

#include "moc_mainslice.cpp"

donutbreakdownchart.h

#ifndef DONUTBREAKDOWNCHART_H
#define DONUTBREAKDOWNCHART_H

#include 
#include 

QT_USE_NAMESPACE

class DonutBreakdownChart : public QChart
{
public:
    DonutBreakdownChart(QGraphicsItem *parent = nullptr, Qt::WindowFlags wFlags = {});
    void addBreakdownSeries(QPieSeries *series, QColor color);

private:
    void recalculateAngles();
    void updateLegendMarkers();

private:
    QPieSeries *m_mainSeries;
};

#endif // DONUTBREAKDOWNCHART_H

donutbreakdownchart.cpp

#include "donutbreakdownchart.h"
#include "mainslice.h"
#include 
#include 

QT_USE_NAMESPACE

//它为编写您自己的自定义项目提供了一个轻量级的基础。
//这包括通过其事件处理程序定义项目的几何形状、碰撞检测、其绘制实现和项目交互
//QGraphicsItem 是图形视图框架的一部分
//项目的所有几何信息都基于其局部坐标系
//项目的位置 pos() 是唯一不在本地坐标中操作的函数
//因为它返回父坐标中的位置
//图形视图坐标系详细描述了坐标系。
//您可以通过调用 setVisible() 设置项目是否应该可见(即,绘制和接受事件)。
//隐藏项目也会隐藏其子项。
//同样,您可以通过调用 setEnabled() 启用或禁用项目。
//如果您禁用一个项目,它的所有子项也将被禁用。
//。 默认情况下,项目既可见又启用。
//要切换项目是否被选中,首先通过设置 ItemIsSelectable 标志启用选择
//然后调用 setSelected()。
//通常,作为用户交互的结果,选择由场景切换。
//要编写自己的图形项,首先要创建 QGraphicsItem 的子类
//然后从实现它的两个纯虚公共函数开始
//boundingRect(),它返回项所绘制区域的估计值
//和paint(),它实现 实际的绘画。 例如:
/*
    class SimpleItem : public QGraphicsItem
    {
        public:
            QRectF boundingRect() const override
            {
                qreal penWidth = 1;
                return QRectF(-10-penWidth / 2, -10 - penWidth / 2,
                              20 + penWidth, 20 + penWidth);
            }

            void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                        QWidget *widget) override
            {
                painter->drawRoundedRect(-10,-10,20,20,5,5);
            }
    };
*/
//![1]
//ChartTypeCartesian 笛卡尔图。
DonutBreakdownChart::DonutBreakdownChart(QGraphicsItem *parent, Qt::WindowFlags wFlags)
    : QChart(QChart::ChartTypeCartesian, parent, wFlags)
{
    // create the series for main center pie
    m_mainSeries = new QPieSeries();
    m_mainSeries->setPieSize(0.7);
    QChart::addSeries(m_mainSeries);
}
//![1]

//![2]
void DonutBreakdownChart::addBreakdownSeries(QPieSeries *breakdownSeries, QColor color)
{
    QFont font("Arial", 8);

    // add breakdown series as a slice to center pie
    MainSlice *mainSlice = new MainSlice(breakdownSeries);
    mainSlice->setName(breakdownSeries->name());
    mainSlice->setValue(breakdownSeries->sum());
    m_mainSeries->append(mainSlice);

    // customize the slice
    mainSlice->setBrush(color);
    mainSlice->setLabelVisible();
    mainSlice->setLabelColor(Qt::white);
    mainSlice->setLabelPosition(QPieSlice::LabelInsideHorizontal);
    mainSlice->setLabelFont(font);

    // position and customize the breakdown series
    breakdownSeries->setPieSize(0.8);
    breakdownSeries->setHoleSize(0.7);
    breakdownSeries->setLabelsVisible();
    const auto slices = breakdownSeries->slices();
    for (QPieSlice *slice : slices) {
        color = color.lighter(115);
        slice->setBrush(color);
        slice->setLabelFont(font);
    }

    // add the series to the chart
    QChart::addSeries(breakdownSeries);

    // recalculate breakdown donut segments
    recalculateAngles();

    // update customize legend markers
    updateLegendMarkers();
}
//![2]

//![3]
void DonutBreakdownChart::recalculateAngles()
{
    qreal angle = 0;
    const auto slices = m_mainSeries->slices();
    for (QPieSlice *slice : slices) {
        QPieSeries *breakdownSeries = qobject_cast<MainSlice *>(slice)->breakdownSeries();
        breakdownSeries->setPieStartAngle(angle);
        angle += slice->percentage() * 360.0; // full pie is 360.0
        breakdownSeries->setPieEndAngle(angle);
    }
}
//![3]

//![4]
void DonutBreakdownChart::updateLegendMarkers()
{
    // go through all markers
    const auto allseries = series();
    for (QAbstractSeries *series : allseries) {
        const auto markers = legend()->markers(series);
        for (QLegendMarker *marker : markers) {
            QPieLegendMarker *pieMarker = qobject_cast<QPieLegendMarker *>(marker);
            if (series == m_mainSeries) {
                // hide markers from main series
                pieMarker->setVisible(false);
            } else {
                // modify markers from breakdown series
                pieMarker->setLabel(QString("%1 %2%")
                                    .arg(pieMarker->slice()->label())
                                    .arg(pieMarker->slice()->percentage() * 100, 0, 'f', 2));
                pieMarker->setFont(QFont("Arial", 8));
            }
        }
    }
}
//![4]

Qt例子学习笔记 - Examples/Qt-6.2.0/charts/donutbreakdown_第1张图片

你可能感兴趣的:(Qt,Qt,学习,qt,开发语言)