Qt 滑鼠/觸屏繪製平滑曲線(支援向量/非向量方式)
前言
Qt通過滑鼠或者觸屏,實時繪製平滑曲線,通常有兩種方式實現:向量繪圖和非向量繪圖,這兩種畫線方式從實現上有些不同,其原理也不太一樣,稍後會做詳細介紹。而滑鼠或者觸屏畫線也不大一樣,通常如果只實現滑鼠畫線的話,那麼只需要重新實現滑鼠事件即可(mousePressEvent、mouseMoveEvent、mouseReleaseEvent),而要在觸控屏上畫線,如果需要支援多點畫線的話,就必須處理QTouchEvent事件才行,但是如果觸屏上只支援單點畫線,那也可以直接實現滑鼠事件,因為第一個觸點的事件會同時進入到QTouchEvent和Mouse事件中。QTouchEvent中可以區分出多點時每個觸點的id,通過id進行區分每個點的資料。
通常情況下,為了提升繪圖效率,要實現這種繪圖的功能,都是用QGraphics體系來完成,因為QGraphics重新整理機制和QWidget不太一樣,它可以做區域重新整理,這樣能保證效率更高,特別是針對一些解析度較高的裝置,就很明顯了。具體這兩個體系間的區別就不在這裡進行描述。
所以,接下來為了演示向量和非向量畫圖方式,我們在QGraphics體系中實現一個簡單的畫板程式。注重畫線效率,保證線條平滑無折線,無鋸齒,支援多點畫線。
效果圖
先開看看非向量繪圖的效果:
再看向量繪圖效果:
二者區別
通過上面的兩個圖對比,相信大家已經看出了一些區別。我們再詳細介紹一下這兩者的區別。
非向量繪圖
- 優點:速度快。非向量繪圖原理是直接在一張圖片上進行繪製,其渲染速度很快,即便是畫了很多線條, 也不會有卡頓的效果,擦除時同樣很快。
- 缺點:縮放失真。由於非向量繪圖是在圖片上渲染,當縮放圖片時,會導致線條模糊不清晰,如果只是小範圍的縮放還能接受,無限縮放的話就會很明顯了。
向量繪圖
- 優點:無限縮放,不失真。向量繪圖是將點資料繪製生成一個單獨的物件,當進行縮放的時候,會重新進行渲染,所以向量繪圖的方式不會導致影象失真。
- 缺點:線條多時會卡頓,擦除尤其明顯。由於向量繪圖是生成一個單獨的物件,所以當畫線多的情況下,會觸發所有有交集的物件進行重新整理,擦除的時候,會去計算線條之間的交集並做刪減,這個過程會很慢,並且會將整個物件item進行重新整理,所以卡頓明顯(上述效果圖就可以看出來了)。
通過以上兩者的優缺點對比,根據實際需要進行選擇實際的畫線模式。
解決實時繪圖折線問題
折線效果:
可以看到上述畫線有很明顯的折線,線條不平滑。
通常繪製這種線條,第一反應想到的是講兩個點直接連線起來行成一條直線,但是,由於兩點之間距離比較大,特別是觸控屏,點與點之間並不是很密集,因為上層應用在主執行緒渲染的時候,系統會自動丟棄一些資料點,即便是底層上報的點很多,上層應用接收到的點也會減少,所以不能直接用連線兩點的方式來實現。
那麼,該怎麼解決呢?
繪製貝塞爾曲線。
在move的過程中實時生成貝塞爾曲線path,這樣就能保證線條無折線。QPainterPath支援貝塞爾曲線繪製,參加以下函式:
void QPainterPath::quadTo(const QPointF &c,const QPointF &endPoint) Adds a quadratic Bezier curve between the current position and the given endPoint with the control point specified by c. After the curve is added,the current point is updated to be at the end point of the curve.
注意該函式,第一個引數是控制點,該點就是上一個觸控點,而第二個引數是前一個點和當前點的中點,也就是兩個點座標加起來除以2.
非向量繪圖實現方式
所謂的非向量繪圖,就是在一張圖片上進行繪製,然後將圖片渲染到QGraphicsItem的背景上面,前面我們已經提到,該方式渲染速度非常快,無論畫多少線條都不會影響速度,而擦除功能只需要按照同樣的方式繪製背景色即可。
但是該方式在縮放過後圖片會有些模糊,如果只是小範圍的縮放還好,無限縮放就需要用到向量繪圖的方式了。
向量繪圖實現方式
相比之下,向量繪圖就會稍微麻煩一點,所謂向量繪圖,就是將path曲線直接生成一個獨立的物件,將該物件新增到scene中,這種模式下會有一個缺陷,就是當畫線較多的情況下,重新整理會比較慢,因為會導致整條曲線(只要有交集)重新整理,從而導致卡頓的效果,並且在擦除時,需要實時計算擦除的path與實際線條path的交集,然後進行計算,減去擦除的path,這個過程是最耗時的,並且也會引發整個item重新整理。前面寫過文章介紹QGraphics體系的重新整理機制,在這裡
由於向量繪圖需要生成一條完整的path進行繪製,而觸控點是在move事件中取到,如果實時生成貝塞爾曲線去繪製,那麼當一直不鬆手的畫一條線時,畫到後面將會越來越慢,因為動態生成path後會重新將整條path進行渲染,隨著線條越長,那麼重新整理區域就會越大,這就會導致重新整理變慢而延遲變高。那麼怎麼解決這個問題呢?答案就是通過雙緩衝的方式來實現繪製。
雙緩衝繪圖
上面介紹到,通過非向量繪圖的方式,速度會非常快,那麼雙緩衝繪圖就是要結合非向量來進行,其原理就是:在press事件中生成一條path,接著move中動態增加這條path,然後在臨時層上進行非向量繪圖,這時候繪製的速度會非常快,最後在release事件中將完整的path繪製成向量圖,然後將臨時層畫線清空。基本原理就是這樣。
雙緩衝繪圖方式,在繪製過程中是通過非向量的方式在臨時層進行,release後生成完整的向量path,這種方式速度會非常快,並且直接繪製完整的一條path不會有鋸齒。所以這是最佳選擇。
程式碼太多,就不附程式碼了。
到此這篇關於Qt 滑鼠/觸屏繪製平滑曲線(支援向量/非向量方式)的文章就介紹到這了,更多相關Qt 繪製平滑曲線內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!