Verschachtelte Donut-Diagramme erstellen
Hinweis: Dies ist Teil des Beispiels Diagramme mit Widgets-Galerie.
Beginnen wir mit der Erstellung einer QChartView Instanz und der Aktivierung des Antialiasing. Ein QChart Objekt wird dann von der QChartView Instanz erhalten. Die Legende wird deaktiviert und der Titel des Diagramms wird festgelegt. In der letzten Zeile werden die Animationen des Diagramms aktiviert.
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);
Es werden drei Variablen definiert, die zur Definition des Donut-Diagramms verwendet werden. Min. und max. Größe definieren die relative Größe des gesamten Donuts. minSize ist die relative innere Größe des kleinsten Donuts. maxSize ist die relative äußere Größe des größten Donuts.
Der folgende Codeblock definiert die einzelnen Donuts und ihre Slices. Zunächst wird ein neues QPieSeries Objekt erstellt. Die Anzahl der Slices in jedem Donut wird randomisiert. Die interne for-Schleife erzeugt die Slices mit einem zufälligen Wert und einem Label, das dem Wert entspricht. Anschließend wird die Beschriftung des Slices sichtbar gemacht und seine Farbe auf weiß gesetzt. Um das Beispiel interessanter zu machen, wird das Hovered-Signal des Slice mit dem Slot des Widgets verbunden, dessen Funktionsweise später erklärt wird. Schließlich wird das Slice dem Donut hinzugefügt. Die Größe des Donuts wird angepasst, um die Verschachtelung der Donuts zu erreichen. Dann wird der Donut in die Donut-Liste des Widgets und in das Diagramm eingefügt.
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); }
Schließlich wird das Widget in einem von der Anwendung verwendeten Layout platziert.
auto mainLayout = new QGridLayout; mainLayout->addWidget(chartView, 1, 1); setLayout(mainLayout);
Um das Beispiel interessanter zu machen, werden die Donuts alle 1,25 Sekunden zufällig gedreht.
m_updateTimer = new QTimer(this); connect(m_updateTimer, &QTimer::timeout, this, &NestedDonutsWidget::updateRotation); m_updateTimer->start(1250);
Der updatedRotation-Slot des Widgets ist unten definiert. Er durchläuft alle Donuts und ändert ihre aktuelle Drehung um einen Zufallswert.
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); } }
Der bereits erwähnte Code für den Slot explodeSlice ist weiter unten zu finden. Wenn das Slice auf explodiert gesetzt ist, wird der Timer, der die Rotation der Donuts steuert, angehalten. Dann werden die Start- und Endwinkel des Slice aus dem Slice ermittelt. Um das ausgewählte Slice hervorzuheben, werden die Start- und Endwinkel aller anderen Donuts, die außerhalb des Donuts liegen, der das ausgewählte Slice enthält, so geändert, dass sie dem hervorgehobenen Slice nicht den Weg "versperren". Wenn die Scheibe nicht mehr ausgewählt ist, wird der ursprüngliche Zustand wiederhergestellt.
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); }
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.