Qt實(shí)現(xiàn)實(shí)時(shí)鼠標(biāo)繪制圖形
上一章節(jié)介紹了關(guān)于QGraphicsView的基礎(chǔ)講解,以及簡(jiǎn)單的類(lèi)圖創(chuàng)建,由上一章節(jié)中最后展示的動(dòng)畫(huà)效果來(lái)看,今年主要講述如何在QGraphicsView架構(gòu)下,實(shí)時(shí)拖動(dòng)鼠標(biāo)繪制圖形!
今天主要以矩形為例,再來(lái)看一下展示效果吧!
功能實(shí)現(xiàn)
想要實(shí)現(xiàn)鼠標(biāo)拖拽繪圖的效果,離不開(kāi)鼠標(biāo)的三大事件:按下、移動(dòng)、釋放
那么具體實(shí)現(xiàn)實(shí)時(shí)繪制矩形框的核心流程是什么呢?
第一步:鼠標(biāo)左鍵點(diǎn)擊,記錄初始點(diǎn)擊位置
第二步:在窗口中移動(dòng)鼠標(biāo),實(shí)時(shí)獲取鼠標(biāo)拖動(dòng)點(diǎn),根據(jù)拖動(dòng)點(diǎn)繪制指定形狀
第三步:鼠標(biāo)點(diǎn)擊右鍵釋放鼠標(biāo),繪制最終圖形
描述的實(shí)現(xiàn)流程很簡(jiǎn)單,那么,接下來(lái)就實(shí)際操作吧!
在進(jìn)行鼠標(biāo)點(diǎn)擊繪制的時(shí)候,為了兼容多個(gè)圖形的實(shí)時(shí)繪制,這里,不只是用兩個(gè)QPoint成員變量記錄鼠標(biāo)點(diǎn),而是采取了vector<QPontF>
容器存儲(chǔ)的方式。
例如:三角形圖形,需要三個(gè)點(diǎn)才能確定圖形;曲線圖形,是由N多個(gè)點(diǎn)才能確定圖形;等等。。。
所以說(shuō),這里采用了vector容器進(jìn)行數(shù)據(jù)存儲(chǔ),任何圖形的點(diǎn)都可以進(jìn)行存儲(chǔ)。
所有的圖形枚舉類(lèi)型,如下表格:
枚舉類(lèi)型 | 形狀 |
---|---|
Drawing_Normal | 無(wú)圖形繪制 |
Drawing_Circular | 圓形 |
Drawing_StraightLine | 直線 |
Drawing_Rectangular | 矩形 |
Drawing_Triangle | 三角形 |
Drawing_ManyLineSegements | 多線段 |
Drawing_Curve | 曲線 |
今天只講述 矩形:Drawing_Rectangular
1:記錄圖形第一個(gè)繪制點(diǎn)
只有鼠標(biāo)點(diǎn)擊后才能獲取當(dāng)前點(diǎn)擊點(diǎn)的位置,所以,記錄按下點(diǎn)操作應(yīng)該是在鼠標(biāo)的mousePressEvent中實(shí)現(xiàn)的。
void QCustomQGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent * e) { //TODO:鼠標(biāo)左鍵,點(diǎn)擊繪制圖形;鼠標(biāo)右鍵,點(diǎn)擊拖動(dòng)圖形 QGraphicsScene::mousePressEvent(e); if (e->button() & Qt::LeftButton) { //當(dāng)圖形處于繪制狀態(tài)時(shí) if (m_enumShape!= Drawing_Normal) { //記錄鼠標(biāo)按下的點(diǎn) m_vetPoints.push_back(e->scenePos()); } } }
代碼解析:當(dāng)進(jìn)入到鼠標(biāo)按下消息后,只有在左鍵按下?tīng)顟B(tài)時(shí),才做繪圖操作,并且當(dāng)前形狀枚舉類(lèi)型有效。
2:實(shí)時(shí)獲取鼠標(biāo)最新位置并繪圖
鼠標(biāo)想要實(shí)時(shí)繪制,那一定是在鼠標(biāo)的mouseMoveEvent事件中操作的。
void QCustomQGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent * e) { //TODO:鼠標(biāo)移動(dòng)時(shí),如果存在有效圖形類(lèi)型,進(jìn)行圖形繪制 QGraphicsScene::mouseMoveEvent(e); if (m_enumShape!= Drawing_Normal) { m_pTempLayer->DrawShape(m_enumShape, m_vetPt, e->scenePos()); } }
代碼解析:當(dāng)鼠標(biāo)進(jìn)入到mouseMoveEvent事件后,并且,當(dāng)前枚舉類(lèi)型處于有效狀態(tài)時(shí),需要實(shí)時(shí)繪制圖形。
函數(shù)DrawShape的講解:
參數(shù)1:圖形的枚舉類(lèi)型,根據(jù)不同枚舉,繪制不同的圖形
參數(shù)2:vector<QPointF>
傳入已經(jīng)記錄的鼠標(biāo)點(diǎn),可以是多個(gè),但最少是1個(gè)。就例如當(dāng)前繪制矩形來(lái)說(shuō),該容器中只是存儲(chǔ)了一個(gè)繪制點(diǎn)。
參數(shù)3:鼠標(biāo)在mouseMoveEvent中實(shí)時(shí)拖動(dòng)點(diǎn)
DrawShape函數(shù)實(shí)現(xiàn)代碼,如下:
void QTempCanvasLayer::DrawShape(ENUM_DrawingGraphic enumShape, std::vector<QPointF> vetPt, QPointF ptCurrent) { m_pTempCanvasImg->fill(Qt::transparent); m_pTempPainter->setRenderHint(QPainter::Antialiasing, true); m_pTempPainter->setCompositionMode(QPainter::CompositionMode_Source); m_pTempPainter->setPen(QPen(QColor(51, 51, 51), 1, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin)); switch (enumShape) { case Drawing_Circular: //圓形 break; case Drawing_StraightLine: //直線 break; case Drawing_Rectangular: //矩形 m_pTempPainter->drawRect(QRectF(vetPt[0], ptCurrent)); break; case Drawing_Triangle: //三角形 break; case Drawing_ManyLineSegements: //多線段 break; case Drawing_Curve: //曲線 break; default: break; } update(); }
代碼講解:switch語(yǔ)句之前的內(nèi)容都是在設(shè)置圖形的風(fēng)格,比如:setRenderHint防止圖形走樣;最需要我們注意的是下面一句代碼:
m_pTempCanvasImg->fill(Qt::transparent);
如果你忘記設(shè)置了,當(dāng)鼠標(biāo)在拖動(dòng)繪制圖形時(shí),會(huì)導(dǎo)致拖拽線條重疊的效果,就如下面展示效果一樣,如圖所示:
3:釋放繪制點(diǎn),繪制最終圖形
鼠標(biāo)事件:mouseReleaseEvent
void QCustomQGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent * e) { //TODO:鼠標(biāo)釋放之后操作 QGraphicsScene::mouseReleaseEvent(e); if (m_enumShape == Drawing_Normal) { return; } //存在有效的圖形類(lèi)型,進(jìn)行最終圖形繪制 if (e->button() & Qt::RightButton) { if (m_enumShape == Drawing_Rectangular) { //繪制直線,需要存儲(chǔ)兩個(gè)有效點(diǎn) if (m_vetPt.size() == 2) { this->DrawRealShape(m_vetPt); //如果當(dāng)前正在繪制圖形,直接清除 this->ClearCurrentDrawingShape(); } } } }
代碼解析:觸發(fā)了鼠標(biāo)釋放事件后,并且是鼠標(biāo)右鍵點(diǎn)擊(在這里都是以鼠標(biāo)右鍵點(diǎn)擊作為最終的圖形繪制完成),此時(shí),根據(jù)不同的枚舉類(lèi)型進(jìn)行圖形繪制。
對(duì)于矩形圖形來(lái)說(shuō),只需要兩個(gè)有效的點(diǎn)就會(huì)完整對(duì)圖形的繪制,其中this->DrawRealShape中進(jìn)行最終點(diǎn)的繪制。
一個(gè)圖形數(shù)據(jù)繪制成功之后,需要將上一次存儲(chǔ)的臨時(shí)點(diǎn)進(jìn)行清除,以備后續(xù)圖形繪制使用,說(shuō)白了,也就是vector<QPointF>容器需要清除
實(shí)現(xiàn)完成了鼠標(biāo)的三大事件,一個(gè)完整的實(shí)時(shí)鼠標(biāo)圖形繪制思路已經(jīng)完成了。
總結(jié)
實(shí)現(xiàn)鼠標(biāo)實(shí)時(shí)繪圖的功能,無(wú)論是MFC框架還是Qt框架,基本原理都是一致的,基本上不會(huì)離開(kāi)鼠標(biāo)的三大事件。
到此這篇關(guān)于Qt實(shí)現(xiàn)實(shí)時(shí)鼠標(biāo)繪制圖形的文章就介紹到這了,更多相關(guān)Qt鼠標(biāo)繪制圖形內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言中時(shí)間戳轉(zhuǎn)換成時(shí)間字符串的方法
在PE格式里有個(gè)字段是文件的創(chuàng)建時(shí)間戳,我想把轉(zhuǎn)成字符串,今天小編給大家分享一段代碼,可以比較直觀的看出,需要的的朋友參考下2017-02-02C++設(shè)計(jì)模式中的工廠模式詳細(xì)介紹
工廠模式,是一種實(shí)例化對(duì)象的方式,只要輸入需要實(shí)例化對(duì)象的名字,就可以通過(guò)工廠對(duì)象的相應(yīng)工廠函數(shù)來(lái)制造你需要的對(duì)象2022-09-09C語(yǔ)言 枚舉類(lèi)型(Enum)詳解及示例代碼
本文主要介紹C語(yǔ)言 枚舉類(lèi)型,這里提供了詳細(xì)的相關(guān)資料及示例代碼,以便大家學(xué)習(xí)參考,有興趣的小伙伴可以參考下2016-08-08C/C++獲取當(dāng)前時(shí)間的方法總結(jié)(最全)
這篇文章主要為大家整理了C/C++中獲取當(dāng)前時(shí)間的最全方法,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)和借鑒價(jià)值,需要的可以了解一下2023-03-03C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單職工信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單職工信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07VS Code遠(yuǎn)程連接Linux服務(wù)器調(diào)試C程序的操作方法
這篇文章主要介紹了VS Code遠(yuǎn)程連接Linux服務(wù)器調(diào)試C程序的操作方法,打開(kāi)遠(yuǎn)程 Linux 服務(wù)器上的文件夾本文以 /root/ 為例,給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-12-12Qt自定義表頭實(shí)現(xiàn)過(guò)濾功能的方法
這篇文章主要個(gè)給大家介紹了關(guān)于Qt自定義表頭實(shí)現(xiàn)過(guò)濾功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Qt具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07