Qt中使用QWT繪製柱狀圖一類多種顏色
主要難實現功能:
1:柱狀圖實現了一類下有多種顏色顯示,
2:文字、每個柱狀體可以進行偏移
3:修改柱狀體的寬度
4:修改有效圖表的滑鼠顯示狀態
實現效果如圖所示1-1:
QWT中給的example例子也可以實現一種型別對應多種顏色的柱狀圖,但是,無法實現文字以及柱狀圖的偏移。
很明顯,當前效果圖的文字以及柱狀圖顯示在了網格中間。如果有博友想實現和我一樣的效果,那就請繼續往下看。
該效果我是在example的例子基礎上進行改進的,其中基本框架不變,在我看來,沒有實現不了的功能,只有你對這個庫的熟悉程度,該功能程式碼簡單,但是還是耗費了我三天的時間。
下面我進行功能講解
1:設定QChart的整體背景色
m_pChart->setAutoFillBackground(true);
m_pChart->setFrameStyle(QFrame::NoFrame);
m_pChart->setLineWidth(0);
m_pChart->setPalette(QColor(255, 255, 255));
2:設定有效區域的背景色
QwtPlotCanvas *canvas = new QwtPlotCanvas(); canvas->setFrameStyle(QFrame::NoFrame); m_pChart->setCanvas(canvas);
3:設定X、Y座標軸資料
當前X軸顯示的是0-30條資料,Y軸是0-8條資料
m_pChart->setAxisScale(QwtPlot::xBottom, 0, 30);
m_pChart->setAxisMaxMajor(QwtPlot::xBottom, 30);
m_pChart->setAxisMaxMinor(QwtPlot::xBottom, 0);
m_pChart->setAxisScale(QwtPlot::yLeft, 0, 8); m_pChart->setAxisMaxMajor(QwtPlot::yLeft, 6); m_pChart->setAxisMaxMinor(QwtPlot::yLeft, 2);
這是設定X、Y軸的基本設定,如果想要設定字型呢?如下:
QFont fontX;
fontX.setFamily(QStringLiteral("微軟雅黑"));
fontX.setPointSize(12);
m_pChart->setAxisFont(QwtPlot::xBottom, fontX);
在此處,我只是顯示了X軸的字型設定,Y軸同理,就不顯示了。
4:設定網格線
QwtPlotGrid *grid = new QwtPlotGrid;
grid->setMajorPen(QColor(193, 193, 193), 1, Qt::SolidLine);
grid->attach(m_pChart);
如果按照當前程式碼設定網格時,大家會發現,中間刻度沒有網格線顯示,效果如下圖所示:
如果有需要類似功能的,僅用上面程式碼就可以實現。但是,有人卻說,想要中間刻度也有網格線顯示,那麼,使用以下程式碼實現
QwtPlotGrid *grid = new QwtPlotGrid;
grid->enableXMin(true);
grid->enableYMin(true);
grid->setMajorPen(QColor(193, 193, 193), 1, Qt::SolidLine);
grid->setMinorPen(QColor(193, 193, 193), 1, Qt::SolidLine);
grid->attach(m_pChart);
強制顯示網格線的中間刻度網格線。經過設定之後,就和1-1圖一致,根據大家需求自行設定。
5:插入實際資料
當前操作是在柱狀圖中插入資料,可以對每一條柱狀體進行顏色設定,實現程式碼:
m_pChartItemAir = new CustomBarChartItem();
QStringList listPData;
QVector<double> vetSample;
for (int i = 0; i < vetColorData.size(); i++)
{
ColorData stInfo = vetColorData[i];
vetSample.append(stInfo.nNum);
QString sText = QString::number(i+1, 10);
listPData.append(sText);
QColor color = stInfo.color;
m_pChartItemPress->InsertBarData(sText, color);
}
//資料插入之後,進行繫結
m_pChartItemPress->setSamples(vetSample);
m_pChartItemPress->attach(m_pChartPress);
CustomBarChartItem該類是我對QwtPlotBarChart類的重寫。
其中,InsertBarData()該函式設定了每個柱狀體對應的不同顏色值。
插入資料之後,進行資料繫結。
InsertBarData()中呼叫QwtPlotBarChart::itemChanged(),讓類中自動呼叫specialSymbol() 該函式進行顏色值更改
QwtColumnSymbol * CustomBarChartItem::specialSymbol(int sampleIndex, const QPointF&) const
{
//TODO: 我們希望每個條形都有不同的顏色
CustomBarChartColumnSymbol *symbol = new CustomBarChartColumnSymbol(QwtColumnSymbol::Box);
symbol->setFrameStyle(QwtColumnSymbol::NoFrame);
symbol->SetColumnMoveLen(m_nMoveLen);
QColor currentColor(Qt::white);
QString sHit = "";
if ((sampleIndex >= 0) && (sampleIndex < m_listColor.size()))
{
currentColor = m_listColor[sampleIndex];
sHit = m_listLabel.at(sampleIndex);
}
symbol->setPalette(currentColor);
return symbol;
}
實現改變顏色的核心程式碼是:symbol->setPalette(currentColor);
6:X軸刻度值優化
CustomBarChartScaleDraw *pScaleDraw = new CustomBarChartScaleDraw(Qt::Orientation::Horizontal, listPressLabel);
pScaleDraw->SetXBottomMoveLens(10);
m_pChart->setAxisScaleDraw(QwtPlot::xBottom, pScaleDraw);
其中,setAxisScaleDraw的第一個引數是控制,是X軸?Y軸
當前CustomBarChartScaleDraw類是我對QwtScaleDraw的重寫,具體類實現
CustomBarChartScaleDraw::CustomBarChartScaleDraw(Qt::Orientation orientation, const QStringList &labels):
QwtScaleDraw()
{
m_listLabels = labels;
//設定 間距、中間刻度、主刻度
setTickLength(QwtScaleDiv::MinorTick, 0);
setTickLength(QwtScaleDiv::MediumTick, 0);
setTickLength(QwtScaleDiv::MajorTick, 0);
enableComponent(QwtScaleDraw::Backbone, false); //不顯示主軸線
setSpacing(0); //設定文字與 座標軸之間的距離
//setAlignment(Alignment::LeftScale);
}
CustomBarChartScaleDraw::~CustomBarChartScaleDraw()
{
}
void CustomBarChartScaleDraw::SetXBottomMoveLens(int nMoveLen)
{
m_nMoveLen = nMoveLen;
}
QwtText CustomBarChartScaleDraw::label(double value) const
{
//TODO:用於顯示文字
QwtText wtText;
const int nIndex = qRound(value);
if ((nIndex >= 0) && (nIndex < m_listLabels.size()))
{
QString sText = m_listLabels[nIndex];
QString sNewText = "";
for (int i = 0; i < m_nMoveLen; i++)
{
sNewText += " ";
}
sText = sNewText + sText;
wtText = sText;
}
return wtText;
}
7:設定X軸文字偏移
第6步驟中,SetXBottomMoveLens()函式實現的功能就是對X軸文字進行偏移。
8:設定每個柱狀體的寬度
setLayoutPolicy(FixedSampleSize);
setLayoutHint(nWidth); //設定了柱狀體的寬度
9:設定每個柱狀體的偏移量
寫到這裡,大家會發現,執行之後,效果差強人意,如圖所示。
每個柱狀圖都在網格的垂直線上,而且第一位還顯示不全,看起來很是不舒服。下面需要設定對柱狀圖的偏移,這個功能可真是不好改,改了一天才弄好 -_-||
修改柱狀圖的偏移需要在QwtColumnSymbol類中進行修改,那麼重寫該類,叫做CustomBarChartColumnSymbol這個名字,對draw函式進行過載
virtual void draw(QPainter *painter, const QwtColumnRect &rect) const;
加入QWT原始碼之後,可以檢視到draw函式的實現,我們需要仿照原始碼中進行實現,只是修改下顯示位置。因為在QwtColumnSymbol中,修改柱狀圖區域的類未對外開放,所以,只能依靠draw的QwtColumnRect 類進行修改。
當draw在呼叫drawBox函式時,需要將修改的QwtColumnRect的區域傳給父類,這樣就會修改顯示位置。
直接上程式碼更直接一些
void CustomBarChartColumnSymbol::draw(QPainter *painter, const QwtColumnRect &rect) const
{
QwtColumnRect rectNew = rect;
if (m_nMoveLens > 0)
{
int nMin = rectNew.hInterval.minValue() + m_nMoveLens;
rectNew.hInterval.setMinValue(nMin);
int nMax = rectNew.hInterval.maxValue() + m_nMoveLens;
rectNew.hInterval.setMaxValue(nMax);
}
painter->save();
switch (this->style())
{
case QwtColumnSymbol::Box:
{
drawBox(painter, rectNew);
}
break;
default:;
}
painter->restore();
}
修改的位置,其實是對QwtColumnRect的 QwtInterval hInterval; 進行修改。因為實現的是需要對X軸進行偏移,所以只對該引數進行修改,其餘按照父類的draw進行實現。
CustomBarChartColumnSymbol的程式碼實現:
CustomBarChartColumnSymbol::CustomBarChartColumnSymbol(Style sStyle/* = NoStyle*/) :QwtColumnSymbol(sStyle)
{
m_nMoveLens = 0;
}
CustomBarChartColumnSymbol::~CustomBarChartColumnSymbol()
{
}
void CustomBarChartColumnSymbol::SetColumnMoveLen(int nMoveLen)
{
m_nMoveLens = nMoveLen;
}
void CustomBarChartColumnSymbol::draw(QPainter *painter, const QwtColumnRect &rect) const
{
QwtColumnRect rectNew = rect;
if (m_nMoveLens > 0)
{
int nMin = rectNew.hInterval.minValue() + m_nMoveLens;
rectNew.hInterval.setMinValue(nMin);
int nMax = rectNew.hInterval.maxValue() + m_nMoveLens;
rectNew.hInterval.setMaxValue(nMax);
}
painter->save();
switch (this->style())
{
case QwtColumnSymbol::Box:
{
drawBox(painter, rectNew);
}
break;
default:;
}
painter->restore();
}
其中,偏移位置的大小是由 SetColumnMoveLen進行設定的。
10:修改滑鼠的顯示狀態
canvas->setCursor(Qt::ArrowCursor); //修改滑鼠在畫布上的顯示方式,系統預設是十字架形狀
在實現過程中,大家會發現,實現的網格效果和我的有些不一致,網格線並沒有呈現閉合狀態,可以使用以下程式碼實現
m_pChart->plotLayout()->setAlignCanvasToScales(true);
以上最難實現的功能實現方法已經全部列舉了,如果需要檢視原始碼的,可以使用以下連結進行下載: