IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Creating Nested Donut Charts

Shows how to create a nested donut chart using the QPieSeries API.

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

Creating Nested Donut Charts

This is part of the Charts with Widgets Gallery example.

Image non disponible

Let's start by creating a QChartView instance and enabling the Antialiasing on it. A QChart object is then obtained from the QChartView instance. The legend is disabled and the title of the chart is set. Last line enables the animations of the chart.

 
Sélectionnez
auto chartView = new QChartView(this);
chartView->setRenderHint(QPainter::Antialiasing);
QChart *chart = chartView->chart();
chart->legend()->setVisible(false);
chart->setTitle("Nested Donuts (Hover over segments to explode them)");
chart->setAnimationOptions(QChart::AllAnimations);
chart->layout()->setContentsMargins(0, 0, 0, 0);

Three variables are defined that will be used to define the donut chart. Min and max size define the relative size of the whole donut. minSize is the relative inner size of the smallest donut. maxSize is the relative outer size of the biggest donut.

 
Sélectionnez
qreal minSize = 0.1;
qreal maxSize = 0.9;
int donutCount = 5;

The following block of code defines the individual donuts and their slices. First a new QPieSeries object is created. The number of slices in each donut is randomized. The internal for loop creates the slices with a random value and label same as the value. Next the label of the slice is set to be visible and its color is set to white. To make the example more interesting the hovered signal of the slice is connected to widget's slot, of which the inner workings are explained later. Finally the slice is added to the donut. The donut's size is adjusted to achieve the nesting of the donuts. Then the donut is added to the widget's list of donuts and to the chart.

 
Sélectionnez
for (int i = 0; i < donutCount; i++) {
    auto donut = new QPieSeries;
    int sliceCount =  3 + QRandomGenerator::global()->bounded(3);
    for (int j = 0; j < sliceCount; j++) {
        qreal value = 100 + QRandomGenerator::global()->bounded(100);
        auto slice = new QPieSlice(QString("%1").arg(value), value);
        slice->setLabelVisible(true);
        slice->setLabelColor(Qt::white);
        slice->setLabelPosition(QPieSlice::LabelInsideTangential);
        connect(slice, &QPieSlice::hovered, this, &NestedDonutsWidget::explodeSlice);
        donut->append(slice);
        donut->setHoleSize(minSize + i * (maxSize - minSize) / donutCount);
        donut->setPieSize(minSize + (i + 1) * (maxSize - minSize) / donutCount);
    }
    m_donuts.append(donut);
    chartView->chart()->addSeries(donut);
}

Finally the widget is placed in a layout used by the application.

 
Sélectionnez
auto mainLayout = new QGridLayout;
mainLayout->addWidget(chartView, 1, 1);
setLayout(mainLayout);

To make the example more interesting the donuts are rotated randomly every 1.25 sec.

 
Sélectionnez
m_updateTimer = new QTimer(this);
connect(m_updateTimer, &QTimer::timeout, this, &NestedDonutsWidget::updateRotation);
m_updateTimer->start(1250);

The widget's updatedRotation slot is defined below. It goes through all of the donuts and modifies their current rotation by a random value.

 
Sélectionnez
void NestedDonutsWidget::updateRotation()
{
    for (int i = 0; i < m_donuts.count(); i++) {
        QPieSeries *donut = m_donuts.at(i);
        qreal phaseShift =  -50 + QRandomGenerator::global()->bounded(100);
        donut->setPieStartAngle(donut->pieStartAngle() + phaseShift);
        donut->setPieEndAngle(donut->pieEndAngle() + phaseShift);
    }
}

The earlier mentioned explodeSlice slot code is provided below. If the slice is set to exploded, then stop the timer that controls the donuts rotation. Then the slice's start and end angles are obtained from the slice. To highlight the selected slice all the other donuts that lie outward from the one that contains the selected slice have their start and end angles modified so that they wouldn't "block" the way for the hightlighted slice. If the slice is no longer selected return to the original state.

 
Sélectionnez
void NestedDonutsWidget::explodeSlice(bool exploded)
{
    auto slice = qobject_cast<QPieSlice *>(sender());
    if (exploded) {
        m_updateTimer->stop();
        qreal sliceStartAngle = slice->startAngle();
        qreal sliceEndAngle = slice->startAngle() + slice->angleSpan();

        QPieSeries *donut = slice->series();
        qreal seriesIndex = m_donuts.indexOf(donut);
        for (int i = seriesIndex + 1; i < m_donuts.count(); i++) {
            m_donuts.at(i)->setPieStartAngle(sliceEndAngle);
            m_donuts.at(i)->setPieEndAngle(360 + sliceStartAngle);
        }
    } else {
        for (int i = 0; i < m_donuts.count(); i++) {
            m_donuts.at(i)->setPieStartAngle(0);
            m_donuts.at(i)->setPieEndAngle(360);
        }
        m_updateTimer->start();
    }
    slice->setExploded(exploded);
}

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+