入れ子ドーナツ・チャートの作成

注: これはCharts with Widgets Galleryの例の一部です。

まず、QChartView インスタンスを作成し、アンチエイリアスを有効にします。次にQChartView インスタンスからQChart オブジェクトを取得します。凡例は無効化され、チャートのタイトルが設定されます。最後の行は、チャートのアニメーションを有効にする。

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);

ドーナツ・チャートの定義に使われる3つの変数が定義されている。minSizeは最小のドーナツの内側の相対サイズ、maxSizeは最大のドーナツの外側の相対サイズです。

qreal minSize = 0.1;
qreal maxSize = 0.9;
int donutCount = 5;

次のコードのブロックは、個々のドーナツとそのスライスを定義します。まず、新しいQPieSeries オブジェクトが作成されます。各ドーナツのスライス数はランダムである。内部のforループがランダムな値と同じラベルでスライスを作成する。次に、スライスのラベルが見えるように設定され、色が白に設定されます。この例をより面白くするために、スライスのホバー信号がウィジェットのスロットに接続されます。最後に、スライスがドーナツに追加されます。ドーナツのサイズは、ドーナツの入れ子になるように調整される。それから、ドーナツがウィジェットのドーナツ・リストとチャートに追加されます。

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);
}

最後に、ウィジェットはアプリケーションで使われるレイアウトに配置されます。

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

この例をより面白くするために、ドーナツは1.25秒ごとにランダムに回転します。

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

ウィジェットのupdatedRotationスロットを以下に定義します。これは、すべてのドーナツを調べて、現在の回転をランダムな値で変更します。

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);
    }
}

先に述べたexplodeSliceスロットのコードを以下に示します。スライスがexplodeに設定されたら、ドーナツの回転を制御するタイマーを止める。その後、スライスの開始角度と終了角度をスライスから取得します。選択されたスライスを強調するために、選択されたスライスを含むドーナツから外側にある他のドーナツの開始角度と終了角度をすべて変更し、強調されたスライスの道を「ふさがない」ようにします。スライスが選択されなくなったら、元の状態に戻る。

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.