创建嵌套甜甜圈图表

注: 这是 "带 Widgets 图库的图表"示例的一部分。

首先创建一个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);

定义了三个变量,用于定义甜甜圈图表。最小和最大尺寸定义了整个甜甜圈的相对尺寸,minSize 是最小甜甜圈的相对内部尺寸,maxSize 是最大甜甜圈的相对外部尺寸。

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

下面的代码块定义了各个甜甜圈及其切片。首先创建一个新的QPieSeries 对象。每个甜甜圈的切片数量是随机的。内部 for 循环以随机值创建切片,切片标签与随机值相同。然后将切片的标签设置为可见,并将其颜色设置为白色。为了让示例更有趣,切片的悬停信号被连接到 widget 的插槽,其内部工作原理将在后面解释。最后,切片被添加到甜甜圈中。调整甜甜圈的大小以实现甜甜圈的嵌套。然后将甜甜圈添加到 widget 的甜甜圈列表和图表中。

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 插槽代码如下。如果切片设置为 exploded,则停止控制甜甜圈旋转的计时器。然后从切片中获取切片的起始角和终止角。为了突出显示选中的切片,从包含选中切片的甜甜圈向外延伸的所有其他甜甜圈的起始角和终止角都会被修改,以免 "挡住 "突出显示的切片。如果片不再被选中,则返回原始状态。

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.