QCustomPlot之柱狀圖(三)

在QCustomPlot中,柱狀圖需要使用QCPBars類, QCPBars的使用很簡單

豎向柱狀圖

創(chuàng)建一個柱狀圖,并且設(shè)置它的風(fēng)格

QCPAxis *keyAxis = customPlot->xAxis;
QCPAxis *valueAxis = customPlot->yAxis;
QCPBars *fossil = new QCPBars(keyAxis, valueAxis);  // 使用xAxis作為柱狀圖的key軸,yAxis作為value軸

fossil->setAntialiased(false); // 為了更好的邊框效果,關(guān)閉抗齒鋸
fossil->setName("Fossil fuels"); // 設(shè)置柱狀圖的名字,可在圖例中顯示
fossil->setPen(QPen(QColor(0, 168, 140).lighter(130))); // 設(shè)置柱狀圖的邊框顏色
fossil->setBrush(QColor(0, 168, 140));  // 設(shè)置柱狀圖的畫刷顏色

之后,我們?yōu)橹鶢顖D的key軸設(shè)置一個文字類型的軸

// 為柱狀圖設(shè)置一個文字類型的key軸,ticks決定了軸的范圍,而labels決定了軸的刻度文字的顯示
QVector<double> ticks;
QVector<QString> labels;
ticks << 1 << 2 << 3 << 4 << 5 << 6 << 7;
labels << "USA" << "Japan" << "Germany" << "France" << "UK" << "Italy" << "Canada";
QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
textTicker->addTicks(ticks, labels);

keyAxis->setTicker(textTicker);        // 設(shè)置為文字軸

設(shè)置柱狀圖軸范圍,并且為其添加數(shù)據(jù)數(shù)據(jù)

keyAxis->setTickLabelRotation(60);     // 軸刻度文字旋轉(zhuǎn)60度
keyAxis->setSubTicks(false);           // 不顯示子刻度
keyAxis->setTickLength(0, 4);          // 軸內(nèi)外刻度的長度分別是0,4,也就是軸內(nèi)的刻度線不顯示
keyAxis->setRange(0, 8);               // 設(shè)置范圍
keyAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);

valueAxis->setRange(0, 12.1);
valueAxis->setPadding(35);             // 軸的內(nèi)邊距,可以到QCustomPlot之開始(一)看圖解 
valueAxis->setLabel("Power Consumption in\nKilowatts per Capita (2007)");
valueAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);
QVector<double> fossilData;
fossilData  << 0.86*10.5 << 0.83*5.5 << 0.84*5.5 << 0.52*5.8 << 0.89*5.2 << 0.90*4.2 << 0.67*11.2;
fossil->setData(ticks, fossilData);
豎向柱狀圖

橫向柱狀圖

橫向柱狀圖也很簡單,只要設(shè)置key軸為y軸,value軸為x軸即可

QCPAxis *keyAxis = customPlot->yAxis;
QCPAxis *valueAxis = customPlot->xAxis;
橫向柱狀圖

柱狀堆積圖

為了展示堆積圖,我們再添加了兩個柱狀圖

QCPBars *regen = new QCPBars(keyAxis, valueAxis);
QCPBars *nuclear = new QCPBars(keyAxis, valueAxis);
QCPBars *fossil = new QCPBars(keyAxis, valueAxis);  // 使用xAxis作為柱狀圖的key軸,yAxis作為value軸

設(shè)置它們的數(shù)據(jù)

QVector<double> fossilData, nuclearData, regenData;
fossilData  << 0.86*10.5 << 0.83*5.5 << 0.84*5.5 << 0.52*5.8 << 0.89*5.2 << 0.90*4.2 << 0.67*11.2;
nuclearData << 0.08*10.5 << 0.12*5.5 << 0.12*5.5 << 0.40*5.8 << 0.09*5.2 << 0.00*4.2 << 0.07*11.2;
regenData   << 0.06*10.5 << 0.05*5.5 << 0.04*5.5 << 0.06*5.8 << 0.02*5.2 << 0.07*4.2 << 0.25*11.2;
fossil->setData(ticks, fossilData);
nuclear->setData(ticks, nuclearData);
regen->setData(ticks, regenData);

接下來設(shè)置堆積方式

regen->setStackingGap(1);    // 設(shè)置堆積在其它柱狀圖上時的間距(像素)
nuclear->setStackingGap(1);

nuclear->moveAbove(fossil);  // 將nuclear移到fossil之上
regen->moveAbove(nuclear);
柱狀堆積圖

柱狀分組圖

柱狀分組圖需要引入一個新的類:QCPBarsGroup,首先注釋掉上面的堆積方式的代碼

QCPBarsGroup *group = new QCPBarsGroup(customPlot);  

QList<QCPBars*> bars;
bars << fossil << nuclear << regen;

foreach (QCPBars *bar, bars) {
  // 設(shè)置柱狀圖的寬度類型為以key坐標(biāo)軸計(jì)算寬度的大小,其實(shí)默認(rèn)就是這種方式
  bar->setWidthType(QCPBars::wtPlotCoords);
  bar->setWidth(bar->width() / bars.size()); // 設(shè)置柱狀圖的寬度大小
  group->append(bar);  // 將柱狀圖加入柱狀圖分組中
}

group->setSpacingType(QCPBarsGroup::stAbsolute);  // 設(shè)置組內(nèi)柱狀圖的間距,按像素
group->setSpacing(2);     // 設(shè)置較小的間距值,這樣看起來更緊湊
柱狀分組圖

柱狀圖寬度類型和柱狀分組圖間距類型

柱狀圖有三種寬度類型,分別是:

  • QCPBars::wtAbsolute 寬度是絕對像素大小,即setWidth設(shè)置為多少就是多少
  • QCPBars::wtAxisRectRatio 寬度大小是以QCPAxisRect的大小決定的,當(dāng)key軸為水平的時候,寬度大小為setWidth設(shè)置的比例值乘以QCPAxisRect的寬度;key軸為垂直的時候,是乘以QCPAxisRect的高度
  • QCPBars::wtPlotCoords 寬度大小是以key坐標(biāo)軸刻度位置以及setWidth設(shè)置的值確定,寬度的計(jì)算方式為當(dāng)前key±width

柱狀分組圖的間距類型和柱狀圖的寬度類型是類似的

在柱狀圖上顯示值

有時候我們需要在柱狀圖上顯示具體的值,這時我們僅需繼承QCPBars

// 頭文件CustomBars.h
class CustomBars : public QCPBars
{
public:
    explicit CustomBars(QCPAxis *keyAxis, QCPAxis *valueAxis);

    Qt::Alignment textAligment() const { return mTextAlignment; }
    double spacing() const { return mSpacing; }
    QFont font() const { return mFont; }

    void setTextAlignment(Qt::Alignment alignment);
    void setSpacing(double spacing);
    void setFont(const QFont &font);

protected:
    Qt::Alignment mTextAlignment;   // 文字對齊方式
    double mSpacing;                // 文字與柱狀圖的間距,這里按像素大小
    QFont mFont;                    // 文字使用的字體

    virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE;
};
// 源文件CustomBars.cpp
CustomBars::CustomBars(QCPAxis *keyAxis, QCPAxis *valueAxis)
    : QCPBars (keyAxis, valueAxis),
      mTextAlignment(Qt::AlignCenter),
      mSpacing(5),
      mFont(QFont(QLatin1String("sans serif"), 12))
{

}

void CustomBars::setTextAlignment(Qt::Alignment alignment)
{
    mTextAlignment = alignment;
}

void CustomBars::setSpacing(double spacing)
{
    mSpacing = spacing;
}

void CustomBars::setFont(const QFont &font)
{
    mFont = font;
}

draw函數(shù)的繪制 我們直接拷貝QCPBars的draw函數(shù)源碼過來,在其上面修改即可

// 源文件CustomBars.cpp
void CustomBars::draw(QCPPainter *painter)
{

    // 以上是拷貝的源碼部分
    painter->drawPolygon(barRect);

    // 我們僅需在 painter->drawPolygon(barRect); 這行下增加以下的內(nèi)容即可
    
    // 計(jì)算文字的位置
    painter->setFont(mFont);                     // 設(shè)置字體
    QString text = QString text = QString::number(it->value, 'g', 2);   // 取得當(dāng)前value軸的值,保留兩位精度

    QRectF textRect = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip | mTextAlignment, text);  // 計(jì)算文字所占用的大小

    if (mKeyAxis.data()->orientation() == Qt::Horizontal) {    // 當(dāng)key軸為水平軸的時候
        if (mKeyAxis.data()->axisType() == QCPAxis::atTop)     // 上軸,移動文字到柱狀圖下面
            textRect.moveTopLeft(barRect.bottomLeft() + QPointF(0, mSpacing));
        else                                                   // 下軸,移動文字到柱狀圖上面
            textRect.moveBottomLeft(barRect.topLeft() - QPointF(0, mSpacing));
        textRect.setWidth(barRect.width());
        painter->drawText(textRect, Qt::TextDontClip | mTextAlignment, text);
    } else {                                                  // 當(dāng)key軸為豎直軸的時候
        if (mKeyAxis.data()->axisType() == QCPAxis::atLeft)   // 左軸,移動文字到柱狀圖右邊
            textRect.moveTopLeft(barRect.topRight() + QPointF(mSpacing, 0));
        else                                                  // 右軸,移動文字到柱狀圖左邊
            textRect.moveTopRight(barRect.topLeft() - QPointF(mSpacing, 0));
        textRect.setHeight(barRect.height());
        painter->drawText(textRect, Qt::TextDontClip | mTextAlignment, text);
    }
    
    // 以下是拷貝的源碼部分
}

使用很簡單,僅需將QCPBars替換成CustomBars

CustomBars *regen = new CustomBars(keyAxis, valueAxis);
CustomBars *nuclear = new CustomBars(keyAxis, valueAxis);
CustomBars *fossil = new CustomBars(keyAxis, valueAxis);  // 使用xAxis作為柱狀圖的key軸,yAxis作為value軸
在柱狀圖上顯示數(shù)值

最后補(bǔ)充一點(diǎn)

我們可以通過setBaseValue函數(shù)設(shè)置柱狀圖的起點(diǎn)位置,這個函數(shù)僅對最底下的柱狀圖有效果(即其沒有堆積在別的柱狀圖之上)

foreach (QCPBars *bar, bars) {
  // 設(shè)置柱狀圖的寬度類型為以key坐標(biāo)軸計(jì)算寬度的大小,其實(shí)默認(rèn)就是這種方式
  bar->setBaseValue(2.5);     // 設(shè)置柱狀圖的起點(diǎn)為value軸值為2.5的位置
}
設(shè)置柱狀圖起點(diǎn)位置
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容