在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)位置