Qt使用QWT繪制柱狀圖詳解
有的時候我們會遇到這樣一種功能,需要在柱狀圖中顯示不同顏色的柱狀體,每個主狀態(tài)代表的狀態(tài)不同,那么如果只是用簡單的QChart是難以實現(xiàn)的。
QT中提供了一個叫做QWT的庫。QWT,全稱是Qt Widgets for Technical Applications,是一個基于LGPL版權(quán)協(xié)議的開源項目,可生成各種統(tǒng)計圖。它為具有技術(shù)專業(yè)背景的程序提供GUI組件和一組實用類,其目標(biāo)是以基于2D方式的窗體部件來顯示數(shù)據(jù),數(shù)據(jù)源以數(shù)值,數(shù)組或一組浮點數(shù)等方式提供,輸出方式可以是Curves(曲線),Slider(滾動條),Dials(圓盤),Compasses(儀表盤)等等。該工具庫基于Qt開發(fā),所以也繼承了Qt的跨平臺特性。
下面介紹的實現(xiàn)效果如下所示:
主要難實現(xiàn)功能:
1:柱狀圖實現(xiàn)了一類下有多種顏色顯示,
2:文本、每個柱狀體可以進(jìn)行偏移
3:修改柱狀體的寬度
4:修改有效圖表的鼠標(biāo)顯示狀態(tài)
QWT中給的example例子也可以實現(xiàn)一種類型對應(yīng)多種顏色的柱狀圖,但是,無法實現(xiàn)文字以及柱狀圖的偏移。
很明顯,當(dāng)前效果圖的文本以及柱狀圖顯示在了網(wǎng)格中間。如果有博友想實現(xiàn)和我一樣的效果,那就請繼續(xù)往下看。
該效果我是在example的例子基礎(chǔ)上進(jìn)行改進(jìn)的,其中基本框架不變,在我看來,沒有實現(xiàn)不了的功能,只有你對這個庫的熟悉程度,該功能代碼簡單,但是還是耗費(fèi)了我三天的時間。
下面我進(jìn)行功能講解
1:設(shè)置QChart的整體背景色
m_pChart->setAutoFillBackground(true); m_pChart->setFrameStyle(QFrame::NoFrame); m_pChart->setLineWidth(0); m_pChart->setPalette(QColor(255, 255, 255));
2:設(shè)置有效區(qū)域的背景色
QwtPlotCanvas *canvas = new QwtPlotCanvas(); canvas->setFrameStyle(QFrame::NoFrame); m_pChart->setCanvas(canvas);
3:設(shè)置X、Y坐標(biāo)軸數(shù)據(jù)
當(dāng)前X軸顯示的是0-30條數(shù)據(jù),Y軸是0-8條數(shù)據(jù)
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);
這是設(shè)置X、Y軸的基本設(shè)置,如果想要設(shè)置字體呢?如下:
QFont fontX; fontX.setFamily(QStringLiteral("微軟雅黑")); fontX.setPointSize(12); m_pChart->setAxisFont(QwtPlot::xBottom, fontX);
在此處,我只是顯示了X軸的字體設(shè)置,Y軸同理,就不顯示了。
4:設(shè)置網(wǎng)格線
QwtPlotGrid *grid = new QwtPlotGrid; grid->setMajorPen(QColor(193, 193, 193), 1, Qt::SolidLine); grid->attach(m_pChart);
如果按照當(dāng)前代碼設(shè)置網(wǎng)格時,大家會發(fā)現(xiàn),中間刻度沒有網(wǎng)格線顯示,效果如下圖所示:
如果有需要類似功能的,僅用上面代碼就可以實現(xiàn)。但是,有人卻說,想要中間刻度也有網(wǎng)格線顯示,那么,使用以下代碼實現(xiàn)
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);
強(qiáng)制顯示網(wǎng)格線的中間刻度網(wǎng)格線。經(jīng)過設(shè)置之后,就和1-1圖一致,根據(jù)大家需求自行設(shè)置。
5:插入實際數(shù)據(jù)
當(dāng)前操作是在柱狀圖中插入數(shù)據(jù),可以對每一條柱狀體進(jìn)行顏色設(shè)置,實現(xiàn)代碼:
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); } //數(shù)據(jù)插入之后,進(jìn)行綁定 m_pChartItemPress->setSamples(vetSample); m_pChartItemPress->attach(m_pChartPress);
CustomBarChartItem該類是我對QwtPlotBarChart類的重寫。
其中,InsertBarData()該函數(shù)設(shè)置了每個柱狀體對應(yīng)的不同顏色值。
插入數(shù)據(jù)之后,進(jìn)行數(shù)據(jù)綁定。
InsertBarData()中調(diào)用QwtPlotBarChart::itemChanged(),讓類中自動調(diào)用specialSymbol() 該函數(shù)進(jìn)行顏色值更改
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; }
實現(xiàn)改變顏色的核心代碼是:symbol->setPalette(currentColor);
6:X軸刻度值優(yōu)化
CustomBarChartScaleDraw *pScaleDraw = new CustomBarChartScaleDraw(Qt::Orientation::Horizontal, listPressLabel); pScaleDraw->SetXBottomMoveLens(10); m_pChart->setAxisScaleDraw(QwtPlot::xBottom, pScaleDraw);
其中,setAxisScaleDraw的第一個參數(shù)是控制,是X軸?Y軸
當(dāng)前CustomBarChartScaleDraw類是我對QwtScaleDraw的重寫
7:設(shè)置X軸文本偏移
第6步驟中,SetXBottomMoveLens()函數(shù)實現(xiàn)的功能就是對X軸文本進(jìn)行偏移。
8:設(shè)置每個柱狀體的寬度
setLayoutPolicy(FixedSampleSize); setLayoutHint(nWidth); //設(shè)定了柱狀體的寬度
9:設(shè)置每個柱狀體的偏移量
寫到這里,大家會發(fā)現(xiàn),運(yùn)行之后,效果差強(qiáng)人意,如圖所示。
每個柱狀圖都在網(wǎng)格的垂直線上,而且第一位還顯示不全,看起來很是不舒服。下面需要設(shè)置對柱狀圖的偏移,這個功能可真是不好改,改了一天才弄好 -_-||
修改柱狀圖的偏移需要在QwtColumnSymbol類中進(jìn)行修改,那么重寫該類,叫做CustomBarChartColumnSymbol這個名字,對draw函數(shù)進(jìn)行重載
virtual void draw(QPainter *painter, const QwtColumnRect &rect) const;
加入QWT源碼之后,可以查看到draw函數(shù)的實現(xiàn),我們需要仿照源碼中進(jìn)行實現(xiàn),只是修改下顯示位置。因為在QwtColumnSymbol中,修改柱狀圖區(qū)域的類未對外開放,所以,只能依靠draw的QwtColumnRect 類進(jìn)行修改。
當(dāng)draw在調(diào)用drawBox函數(shù)時,需要將修改的QwtColumnRect的區(qū)域傳給父類,這樣就會修改顯示位置。
直接上代碼更直接一些
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; 進(jìn)行修改。因為實現(xiàn)的是需要對X軸進(jìn)行偏移,所以只對該參數(shù)進(jìn)行修改,其余按照父類的draw進(jìn)行實現(xiàn)。
CustomBarChartColumnSymbol的代碼實現(xiàn)
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進(jìn)行設(shè)置的。
10:修改鼠標(biāo)的顯示狀態(tài)
canvas->setCursor(Qt::ArrowCursor); //修改鼠標(biāo)在畫布上的顯示方式,系統(tǒng)默認(rèn)是十字架形狀
在實現(xiàn)過程中,大家會發(fā)現(xiàn),實現(xiàn)的網(wǎng)格效果和我的有些不一致,網(wǎng)格線并沒有呈現(xiàn)閉合狀態(tài),可以使用以下代碼實現(xiàn)
m_pChart->plotLayout()->setAlignCanvasToScales(true);
到此這篇關(guān)于Qt使用QWT繪制柱狀圖詳解的文章就介紹到這了,更多相關(guān)Qt QWT柱狀圖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于C++出現(xiàn)Bus error問題的排查與解決
項目代碼中經(jīng)常出現(xiàn)莫名其妙的Bus error問題,并且代碼中增加很多try catch 后依然不能將錯誤捕獲,一旦Bus erro出現(xiàn),進(jìn)程直接崩潰掉,所以本文給大家介紹了關(guān)于C++出現(xiàn)Bus error問題的排查與解決,需要的朋友可以參考下2024-01-01關(guān)于AVLTree(C++實現(xiàn))沒有統(tǒng)一旋轉(zhuǎn)操作的問題
這篇文章主要介紹了關(guān)于AVLTree(C++實現(xiàn))沒有統(tǒng)一旋轉(zhuǎn)操作的問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2020-02-02C++數(shù)據(jù)結(jié)構(gòu)之鏈表的創(chuàng)建
這篇文章主要介紹了C++數(shù)據(jù)結(jié)構(gòu)之鏈表的創(chuàng)建的相關(guān)資料,希望通過本文幫助到大家,讓大家理解掌握這部分內(nèi)容,需要的朋友可以參考下2017-10-10OpenCV數(shù)字圖像處理基于C++之圖像形態(tài)學(xué)處理詳解
OpenCV是一款由Intel公司俄羅斯團(tuán)隊發(fā)起并參與和維護(hù)的一個計算機(jī)視覺處理開源軟件庫,支持與計算機(jī)視覺和機(jī)器學(xué)習(xí)相關(guān)的眾多算法,下面這篇文章主要給大家介紹了關(guān)于OpenCV數(shù)字圖像處理基于C++之圖像形態(tài)學(xué)處理的相關(guān)資料,需要的朋友可以參考下2022-12-12