當(dāng)前位置:首頁 > 芯聞號(hào) > 充電吧
[導(dǎo)讀]在文章之前,首先看看這篇文章要實(shí)現(xiàn)的效果: 數(shù)據(jù)拾取就是在鼠標(biāo)經(jīng)過線條時(shí),會(huì)捕獲一些特征數(shù)據(jù),上圖是捕獲離鼠標(biāo)最接近的點(diǎn)。Qwt提供了拾取數(shù)據(jù)的現(xiàn)成的類,同時(shí)也留有非常好的接口,用戶可以任意擴(kuò)展,下面

在文章之前,首先看看這篇文章要實(shí)現(xiàn)的效果:

數(shù)據(jù)拾取就是在鼠標(biāo)經(jīng)過線條時(shí),會(huì)捕獲一些特征數(shù)據(jù),上圖是捕獲離鼠標(biāo)最接近的點(diǎn)。

Qwt提供了拾取數(shù)據(jù)的現(xiàn)成的類,同時(shí)也留有非常好的接口,用戶可以任意擴(kuò)展,下面就介紹Qwt專門負(fù)責(zé)拾取數(shù)據(jù)及鼠標(biāo)跟蹤用的QwtPicker及其子類。并對(duì)其擴(kuò)展,構(gòu)建一個(gè)用于顯示鼠標(biāo)經(jīng)過圖像時(shí)捕獲最近點(diǎn)的拾取器。

拾取器

Qwt拾取器QwtPicker,用于顯示鼠標(biāo)經(jīng)過圖像時(shí)的信息,內(nèi)置了一些坐標(biāo)變換和鼠標(biāo)位置及動(dòng)作等函數(shù)

QwtPicker

QwtPicker的繼承關(guān)系如下圖所示

這個(gè)類可以捕獲當(dāng)前鼠標(biāo)位置及動(dòng)作,同時(shí)使用戶在圖表上顯示一些特殊的信息。

拾取器的”橡皮圈“(Rubber Band)

所謂橡皮圈,就是在圖表上的一些附加顯示
QwtPicker有個(gè)QwtPicker::RubberBand的枚舉,此枚舉例舉了默認(rèn)的橡皮圈:

HLineRubberBand
A horizontal line ( only for QwtPickerMachine::PointSelection )

VLineRubberBand
A vertical line ( only for QwtPickerMachine::PointSelection )

CrossRubberBand
A crosshair ( only for QwtPickerMachine::PointSelection )

RectRubberBand
A rectangle ( only for QwtPickerMachine::RectSelection )

EllipseRubberBand
An ellipse ( only for QwtPickerMachine::RectSelection )

PolygonRubberBand
A polygon ( only for QwtPickerMachine::PolygonSelection )

UserRubberBand
Values >= UserRubberBand can be used to define additional rubber bands.

HLineRubberBand是一個(gè)水平線,VLineRubberBand是一個(gè)垂直線,CrossRubberBand是十字線,如下圖所示:

坐標(biāo)變換

在重寫拾取器之前需要先了解qwt的一些函數(shù),其中最重要的就是坐標(biāo)變換問題
由于qwt是一個(gè)繪圖控件,圖形有圖形刻度的坐標(biāo),控件有控件的坐標(biāo),可能圖形坐標(biāo)x軸是0到100萬,y軸是0到10萬,這個(gè)圖卻在屏幕上只有x方向600像素,y方向400像素,這時(shí),鼠標(biāo)在圖形屏幕上點(diǎn)(200,200)位置,對(duì)應(yīng)圖形坐標(biāo)的位置是多少,這需要一個(gè)轉(zhuǎn)變,QwtPlotPicker內(nèi)置兩個(gè)函數(shù)實(shí)現(xiàn)圖形屏幕坐標(biāo)到圖形數(shù)值坐標(biāo)的轉(zhuǎn)換以及逆轉(zhuǎn)換:

把圖形數(shù)值坐標(biāo)轉(zhuǎn)換為屏幕坐標(biāo):

QRect???transform?(const?QRectF?&)?const
QPoint??transform?(const?QPointF?&)?const

把屏幕坐標(biāo)轉(zhuǎn)換為圖形數(shù)值坐標(biāo):

QRectF?invTransform?(const?QRect?&)?const
QPointF?invTransform?(const?QPoint?&)?const

有了這兩個(gè)函數(shù),就可以方便的對(duì)坐標(biāo)進(jìn)行轉(zhuǎn)換了。

自定義拾取器

雖然Qwt內(nèi)置了幾種常用的”橡皮圈“,但是使用者肯定有許多不一樣的需求,例如本文開頭顯示的圖片所示,隨著鼠標(biāo)的移動(dòng),自動(dòng)捕抓最近的點(diǎn),并把最近點(diǎn)的信息顯示出來,且文字顏色也有相應(yīng)的改變,這種特殊要求,就必須自己重寫QwtPicker

重寫QwtPicker主要需要重寫如下虛函數(shù):

//用于控制顯示文字內(nèi)容及區(qū)域的:
virtual?QwtText?????trackerText?(const?QPoint?&pos)?const
virtual?QRect???trackerRect?(const?QFont?&)?const
//用于控制’橡皮筋‘RubberBand的繪制的
virtual?void????drawRubberBand?(QPainter?*)?const
//用于控制追蹤鼠標(biāo)顯示的內(nèi)容(默認(rèn)是顯示文字及一個(gè)矩形背景)
virtual?void????drawTracker?(QPainter?*)?const

drawRubberBand

為了實(shí)現(xiàn)上面追蹤最近點(diǎn)的拾取器
這里自定義一個(gè)拾取器,繼承于QwtPlotPicker

頭文件:

#includeclass?QwtPlotCurve;
class?SAXYDataTracker:?public?QwtPlotPicker
{
public:
????SAXYDataTracker(QWidget?*?canvas);
protected:
????virtual?void?drawRubberBand?(QPainter?*painter)?const;
};

實(shí)現(xiàn)文件:

SAXYDataTracker::SAXYDataTracker(QWidget*?canvas)?:
????QwtPlotPicker(?canvas?)
{
????setTrackerMode(?QwtPlotPicker::ActiveOnly?);
????setRubberBand(?UserRubberBand??);
????setStateMachine(?new?QwtPickerTrackerMachine()?);
}

void?SAXYDataTracker::drawRubberBand(QPainter*?painter)?const
{
????if?(?!isActive()?||?rubberBand()?==?NoRubberBand?||
????????rubberBandPen().style()?==?Qt::NoPen?)
????{
????????return;
????}
????QPolygon?pickedPoint?=?pickedPoints?();
????if(pickedPoint.count?()?<?1)
????????return;
????QwtPlotPicker::drawRubberBand?(painter);
????//獲取鼠標(biāo)的客戶坐標(biāo)位置
????const?QPoint?pos?=?pickedPoint[0];

????QwtPainter::drawLine(?painter,?pos.x(),
????pos.y(),?0,0?);
}

這里只做一個(gè)簡(jiǎn)單的實(shí)現(xiàn),就是繪制一條線到(0,0)點(diǎn)

drawRubberBand 是在繪圖畫布上進(jìn)行重繪,在QwtPickerTrackerMachine的狀態(tài)下,只要鼠標(biāo)移動(dòng)就會(huì)觸發(fā)

上面只是一個(gè)小例子,大家可以忽略,請(qǐng)看下面詳細(xì)教程:

最近點(diǎn)捕獲拾取器 求最近點(diǎn)

QwtPlotCurve提供了求最近點(diǎn)的函數(shù)int QwtPlotCurve::closestPoint(const QPoint& _pos_,double * _dist_ = NULL)const
效果是找到鼠標(biāo)最近的一個(gè)點(diǎn):

不過,注意,此函數(shù)是遍歷整個(gè)曲線所有點(diǎn)來求取的,在曲線點(diǎn)數(shù)非常多時(shí),謹(jǐn)慎使用

自定義最近點(diǎn)捕獲Picker

定義求取圖形最近點(diǎn)的函數(shù)
頭文件:

#includeclass?QwtPlotCurve;
class?QwtPlotItem;
class?SAXYDataTracker:?public?QwtPlotPicker
{
public:
????SAXYDataTracker(QWidget?*?canvas);

protected:
????virtual?QwtText?trackerTextF(const?QPointF?&?pos)?const;
????virtual?QRect?trackerRect(const?QFont?&?font)?const;
????virtual?void?drawRubberBand?(QPainter?*painter)?const;
????void?calcClosestPoint(const?QPoint&?pos);
private:
????///
????///?brief?記錄最近點(diǎn)的信息
????///
????class?closePoint
????{
????public:
????????closePoint();
????????QwtPlotCurve?*?curve()?const{return?this->m_curve;}
????????void?setCurve(QwtPlotCurve?*?cur);
????????bool?isValid()?const;
????????QPointF?getClosePoint()?const;
????????int?index()?const{return?this->m_index;}
????????void?setIndex(int?i){this->m_index?=?i;}
????????double?distace()?const{return?this->m_distace;}
????????void?setDistace(double?d){this->m_distace?=?d;}
????????void?setInvalid();
????private:
????????QwtPlotCurve?*m_curve;
????????int?m_index;
????????double?m_distace;
????};
????closePoint?m_closePoint;
private?slots:
????//捕獲鼠標(biāo)移動(dòng)的槽
????void?mouseMove(const?QPoint?&pos);
public?slots:
????void?itemAttached(QwtPlotItem*?plotItem,bool?on);
};

源文件: (跳過吧?。?/p>

#include "SAXYDataTracker.h"
#include

下面等我慢慢介紹上面的代碼:

求全局最近點(diǎn)

函數(shù):
void calcClosestPoint(const QPoint& pos);
是用于求取全局最近點(diǎn)的,為了防止頻繁求取,我們把得到的最近點(diǎn)信息保存下來,因此建立了一個(gè)內(nèi)部類:

///
///?brief?記錄最近點(diǎn)的信息
///
class?closePoint
{
public:
???closePoint();
???QwtPlotCurve?*?curve()?const{return?this->m_curve;}
???void?setCurve(QwtPlotCurve?*?cur);
???bool?isValid()?const;
???QPointF?getClosePoint()?const;
???int?index()?const{return?this->m_index;}
???void?setIndex(int?i){this->m_index?=?i;}
???double?distace()?const{return?this->m_distace;}
???void?setDistace(double?d){this->m_distace?=?d;}
???void?setInvalid();
private:
???QwtPlotCurve?*m_curve;
???int?m_index;
???double?m_distace;
};

此類的作用就是保存最近點(diǎn)的信息,這里并沒有把那個(gè)點(diǎn)保存了下來,而是保存了對(duì)應(yīng)的曲線和索引。
通過QPointF getClosePoint() const函數(shù)可以獲取最近點(diǎn)。
void calcClosestPoint(const QPoint& pos);的實(shí)現(xiàn)就是遍歷plot里的所有曲線,并求取其最近的那個(gè)點(diǎn),并把信息保存在closePoint里,這里連點(diǎn)距離借用了Qt的QLineF類來求,當(dāng)然自己寫也是很簡(jiǎn)單的事情。
函數(shù)void calcClosestPoint(const QPoint& pos)里,首先把屏幕坐標(biāo)轉(zhuǎn)換為坐標(biāo)軸的數(shù)值坐標(biāo)

//把屏幕坐標(biāo)轉(zhuǎn)換為圖形的數(shù)值坐標(biāo)
QPointF?mousePoint?=?invTransform(pos);

并用一個(gè)double記錄最短的距離,初始化為double的最大值,用到了stl里的numeric_limits函數(shù)

std::numeric_limits::max?();

最后檢查最大值的曲線與上一次的曲線是否一樣,不一樣就更換RubberBand的顏色,實(shí)現(xiàn)RubberBand的顏色跟隨曲線一致

//說明最近點(diǎn)的曲線更換了,標(biāo)記線的顏色換為當(dāng)前曲線的顏色
if(m_closePoint.isValid?()?&&?oldCur!=m_closePoint.curve?())
{
?????QPen?p(m_closePoint.curve?()->pen?());
?????p.setWidth?(1);
?????setRubberBandPen?(p);
}

繪制鼠標(biāo)到最近點(diǎn)的連線

最近點(diǎn)求取后,就是繪制鼠標(biāo)到最近點(diǎn)的連線

本例里重載了三個(gè)QwtPicker的虛函數(shù):

????virtual?QwtText?trackerTextF(const?QPointF?&?pos)?const;
????virtual?QRect?trackerRect(const?QFont?&?font)?const;
????virtual?void?drawRubberBand?(QPainter?*painter)?const;

其中virtual void drawRubberBand (QPainter *painter) const;是為了繪制橡皮筋(RubberBand)其實(shí)就是圖表的繪制用的。

void?SAXYDataTracker::drawRubberBand(QPainter*?painter)?const
{
????if?(?!isActive()?||?rubberBand()?==?NoRubberBand?||
????????rubberBandPen().style()?==?Qt::NoPen?)
????{
????????return;
????}
????if(!m_closePoint.isValid?())
????????return;
????QPolygon?pickedPoint?=?pickedPoints?();
????if(pickedPoint.count?()?<?1)
????????return;
????//獲取鼠標(biāo)的客戶坐標(biāo)位置
????const?QPoint?pos?=?pickedPoint[0];
????const?QPointF?closePoint?=?m_closePoint.getClosePoint?();
????const?QPoint?cvp?=?transform?(closePoint);
????QwtPainter::drawLine?(painter,pos,cvp);
????QRect?r(0,0,10,10);
????r.moveCenter?(cvp);
????QwtPainter::drawRect?(painter,r);
}

QPolygon pickedPoint = pickedPoints ();函數(shù)獲取鼠標(biāo)當(dāng)前的點(diǎn),當(dāng)然,用trackerPosition 一樣能獲取,在這里效果一致:

//獲取鼠標(biāo)的客戶坐標(biāo)位置
const?QPoint?pos?=?trackerPosition?();
if(pos.isNull?())
????return;

m_closePoint.getClosePoint獲取最近的那個(gè)點(diǎn),此點(diǎn)是數(shù)值結(jié)果,需要轉(zhuǎn)變?yōu)槠聊蛔鴺?biāo),因此使用了QwtPlotPicker::transform函數(shù),把數(shù)值結(jié)果轉(zhuǎn)換為屏幕坐標(biāo)

const?QPointF?closePoint?=?m_closePoint.getClosePoint?();
const?QPoint?cvp?=?transform?(closePoint);

之后就是繪制圖形了:

QwtPainter::drawLine?(painter,pos,cvp);
QRect?r(0,0,10,10);
r.moveCenter?(cvp);
QwtPainter::drawRect?(painter,r);

Qwt把繪圖的函數(shù)封裝在QwtPainter的類里,此類全部為靜態(tài)函數(shù),相當(dāng)于命名空間,負(fù)責(zé)所有QPainter的操作。這樣可以在const函數(shù)里使用QPainter。

這時(shí)就能繪制一個(gè)線,從鼠標(biāo)的位置連接到最近點(diǎn)的位置。

繪制文本

QwtPicker的跟蹤文本繪制有兩個(gè)虛函數(shù):

????virtual?QwtText?trackerTextF(const?QPointF?&?pos)?const;
????virtual?QRect?trackerRect(const?QFont?&?font)?const;

virtual QwtText trackerTextF(const QPointF & pos) const;負(fù)責(zé)顯示的內(nèi)容
virtual QRect trackerRect(const QFont & font) const;負(fù)責(zé)繪制的區(qū)域

繪制區(qū)域需要根據(jù)內(nèi)容來設(shè)定:

QRect?SAXYDataTracker::trackerRect(const?QFont&?font)?const
{
????QRect?r?=?QwtPlotPicker::trackerRect(?font?);
????r?+=?QMargins(5,5,5,5);
????return?r;
}

QwtPlotPicker::trackerRect( font );可獲取默認(rèn)的繪制區(qū)域,此區(qū)域緊緊包裹著文字,為了好看點(diǎn),讓區(qū)域外擴(kuò)5像素r += QMargins(5,5,5,5);

trackerTextF用來控制顯示的信息

QwtText SAXYDataTracker::trackerTextF(const QPointF& pos) const
{
 ? ?QwtText trackerText;
 ? ?if(!m_closePoint.isValid ())
 ? ? ? ?return trackerText;
 ? ?trackerText.setColor( Qt::black );
 ? ?QColor lineColor = m_closePoint.curve()->pen ().color ();
 ? ?QColor bkColor(lineColor);
 ? ?bkColor.setAlpha (30);
 ? ?trackerText.setBorderPen( m_closePoint.curve()->pen () );
 ? ?trackerText.setBackgroundBrush( bkColor );
 ? ?QPointF point = m_closePoint.getClosePoint ();
 ? ?QString info = QStringLiteral("y:%2
") ? ? ? ? ? ? ? ? ? .arg(lineColor.name ()).arg(point.y ()) ? ? ? ? ? ? ? ? ? + ? ? ? ? ? ? ? ? ? QStringLiteral("x:%2") ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?.arg(lineColor.name ()).arg(point.x ()); ? ?trackerText.setText( info ); ? ?trackerText.setBorderRadius (5); ? ?return trackerText; }

QwtText 支撐html文本的顯示,同時(shí)能比較方便的設(shè)置背景及畫刷,這里使用html把文字用與曲線相同的顏色繪制,背景使用曲線相同顏色的背景,不過透明度更低。
最終效果如下:

這是有5條325000個(gè)點(diǎn)的數(shù)據(jù)線的繪制情況:

可以看到C++的響應(yīng)速度還是很可觀的

要點(diǎn) Qwt圖形數(shù)值坐標(biāo)轉(zhuǎn)換為屏幕坐標(biāo)以及屏幕坐標(biāo)轉(zhuǎn)換為數(shù)值坐標(biāo):

QRect???transform?(const?QRectF?&)?const
QPoint??transform?(const?QPointF?&)?const

QRectF?invTransform?(const?QRect?&)?const
QPointF?invTransform?(const?QPoint?&)?const

QwtPlotCurve求最近點(diǎn):
QwtPlotCurve提供了求最近點(diǎn)的函數(shù)int QwtPlotCurve::closestPoint(const QPoint& _pos_,double * _dist_ = NULL)const

本文源碼都在原文中

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉