溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Qt 鼠標(biāo)/觸屏繪制平滑曲線(支持矢量/非矢量方式)

發(fā)布時(shí)間:2020-10-17 11:00:47 來源:腳本之家 閱讀:394 作者:luoyayun361 欄目:編程語言

前言

Qt通過鼠標(biāo)或者觸屏,實(shí)時(shí)繪制平滑曲線,通常有兩種方式實(shí)現(xiàn):矢量繪圖和非矢量繪圖,這兩種畫線方式從實(shí)現(xiàn)上有些不同,其原理也不太一樣,稍后會(huì)做詳細(xì)介紹。而鼠標(biāo)或者觸屏畫線也不大一樣,通常如果只實(shí)現(xiàn)鼠標(biāo)畫線的話,那么只需要重新實(shí)現(xiàn)鼠標(biāo)事件即可(mousePressEvent、mouseMoveEvent、mouseReleaseEvent),而要在觸控屏上畫線,如果需要支持多點(diǎn)畫線的話,就必須處理QTouchEvent事件才行,但是如果觸屏上只支持單點(diǎn)畫線,那也可以直接實(shí)現(xiàn)鼠標(biāo)事件,因?yàn)榈谝粋€(gè)觸點(diǎn)的事件會(huì)同時(shí)進(jìn)入到QTouchEvent和Mouse事件中。QTouchEvent中可以區(qū)分出多點(diǎn)時(shí)每個(gè)觸點(diǎn)的id,通過id進(jìn)行區(qū)分每個(gè)點(diǎn)的數(shù)據(jù)。

通常情況下,為了提升繪圖效率,要實(shí)現(xiàn)這種繪圖的功能,都是用QGraphics體系來完成,因?yàn)镼Graphics刷新機(jī)制和QWidget不太一樣,它可以做區(qū)域刷新,這樣能保證效率更高,特別是針對(duì)一些分辨率較高的設(shè)備,就很明顯了。具體這兩個(gè)體系間的區(qū)別就不在這里進(jìn)行描述。

所以,接下來為了演示矢量和非矢量畫圖方式,我們?cè)赒Graphics體系中實(shí)現(xiàn)一個(gè)簡(jiǎn)單的畫板程序。注重畫線效率,保證線條平滑無折線,無鋸齒,支持多點(diǎn)畫線。

效果圖

先開看看非矢量繪圖的效果:

Qt 鼠標(biāo)/觸屏繪制平滑曲線(支持矢量/非矢量方式)

再看矢量繪圖效果:

Qt 鼠標(biāo)/觸屏繪制平滑曲線(支持矢量/非矢量方式)

二者區(qū)別

通過上面的兩個(gè)圖對(duì)比,相信大家已經(jīng)看出了一些區(qū)別。我們?cè)僭敿?xì)介紹一下這兩者的區(qū)別。

非矢量繪圖

  • 優(yōu)點(diǎn):速度快。非矢量繪圖原理是直接在一張圖片上進(jìn)行繪制,其渲染速度很快,即便是畫了很多線條, 也不會(huì)有卡頓的效果,擦除時(shí)同樣很快。
  • 缺點(diǎn):縮放失真。由于非矢量繪圖是在圖片上渲染,當(dāng)縮放圖片時(shí),會(huì)導(dǎo)致線條模糊不清晰,如果只是小范圍的縮放還能接受,無限縮放的話就會(huì)很明顯了。

矢量繪圖

  • 優(yōu)點(diǎn):無限縮放,不失真。矢量繪圖是將點(diǎn)數(shù)據(jù)繪制生成一個(gè)單獨(dú)的對(duì)象,當(dāng)進(jìn)行縮放的時(shí)候,會(huì)重新進(jìn)行渲染,所以矢量繪圖的方式不會(huì)導(dǎo)致圖像失真。
  • 缺點(diǎn):線條多時(shí)會(huì)卡頓,擦除尤其明顯。由于矢量繪圖是生成一個(gè)單獨(dú)的對(duì)象,所以當(dāng)畫線多的情況下,會(huì)觸發(fā)所有有交集的對(duì)象進(jìn)行刷新,擦除的時(shí)候,會(huì)去計(jì)算線條之間的交集并做刪減,這個(gè)過程會(huì)很慢,并且會(huì)將整個(gè)對(duì)象item進(jìn)行刷新,所以卡頓明顯(上述效果圖就可以看出來了)。

通過以上兩者的優(yōu)缺點(diǎn)對(duì)比,根據(jù)實(shí)際需要進(jìn)行選擇實(shí)際的畫線模式。

解決實(shí)時(shí)繪圖折線問題

折線效果:

Qt 鼠標(biāo)/觸屏繪制平滑曲線(支持矢量/非矢量方式)

可以看到上述畫線有很明顯的折線,線條不平滑。

通常繪制這種線條,第一反應(yīng)想到的是講兩個(gè)點(diǎn)直接連接起來行成一條直線,但是,由于兩點(diǎn)之間距離比較大,特別是觸控屏,點(diǎn)與點(diǎn)之間并不是很密集,因?yàn)樯蠈討?yīng)用在主線程渲染的時(shí)候,系統(tǒng)會(huì)自動(dòng)丟棄一些數(shù)據(jù)點(diǎn),即便是底層上報(bào)的點(diǎn)很多,上層應(yīng)用接收到的點(diǎn)也會(huì)減少,所以不能直接用連接兩點(diǎn)的方式來實(shí)現(xiàn)。

那么,該怎么解決呢?
繪制貝塞爾曲線。

在move的過程中實(shí)時(shí)生成貝塞爾曲線path,這樣就能保證線條無折線。QPainterPath支持貝塞爾曲線繪制,參加以下函數(shù):

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.

注意該函數(shù),第一個(gè)參數(shù)是控制點(diǎn),該點(diǎn)就是上一個(gè)觸控點(diǎn),而第二個(gè)參數(shù)是前一個(gè)點(diǎn)和當(dāng)前點(diǎn)的中點(diǎn),也就是兩個(gè)點(diǎn)坐標(biāo)加起來除以2.

非矢量繪圖實(shí)現(xiàn)方式

所謂的非矢量繪圖,就是在一張圖片上進(jìn)行繪制,然后將圖片渲染到QGraphicsItem的背景上面,前面我們已經(jīng)提到,該方式渲染速度非常快,無論畫多少線條都不會(huì)影響速度,而擦除功能只需要按照同樣的方式繪制背景色即可。

但是該方式在縮放過后圖片會(huì)有些模糊,如果只是小范圍的縮放還好,無限縮放就需要用到矢量繪圖的方式了。

矢量繪圖實(shí)現(xiàn)方式

相比之下,矢量繪圖就會(huì)稍微麻煩一點(diǎn),所謂矢量繪圖,就是將path曲線直接生成一個(gè)獨(dú)立的對(duì)象,將該對(duì)象添加到scene中,這種模式下會(huì)有一個(gè)缺陷,就是當(dāng)畫線較多的情況下,刷新會(huì)比較慢,因?yàn)闀?huì)導(dǎo)致整條曲線(只要有交集)刷新,從而導(dǎo)致卡頓的效果,并且在擦除時(shí),需要實(shí)時(shí)計(jì)算擦除的path與實(shí)際線條path的交集,然后進(jìn)行計(jì)算,減去擦除的path,這個(gè)過程是最耗時(shí)的,并且也會(huì)引發(fā)整個(gè)item刷新。前面寫過文章介紹QGraphics體系的刷新機(jī)制,在這里

由于矢量繪圖需要生成一條完整的path進(jìn)行繪制,而觸控點(diǎn)是在move事件中取到,如果實(shí)時(shí)生成貝塞爾曲線去繪制,那么當(dāng)一直不松手的畫一條線時(shí),畫到后面將會(huì)越來越慢,因?yàn)閯?dòng)態(tài)生成path后會(huì)重新將整條path進(jìn)行渲染,隨著線條越長(zhǎng),那么刷新區(qū)域就會(huì)越大,這就會(huì)導(dǎo)致刷新變慢而延遲變高。那么怎么解決這個(gè)問題呢?答案就是通過雙緩沖的方式來實(shí)現(xiàn)繪制。

雙緩沖繪圖

上面介紹到,通過非矢量繪圖的方式,速度會(huì)非??欤敲措p緩沖繪圖就是要結(jié)合非矢量來進(jìn)行,其原理就是:在press事件中生成一條path,接著move中動(dòng)態(tài)增加這條path,然后在臨時(shí)層上進(jìn)行非矢量繪圖,這時(shí)候繪制的速度會(huì)非常快,最后在release事件中將完整的path繪制成矢量圖,然后將臨時(shí)層畫線清空?;驹砭褪沁@樣。

雙緩沖繪圖方式,在繪制過程中是通過非矢量的方式在臨時(shí)層進(jìn)行,release后生成完整的矢量path,這種方式速度會(huì)非??欤⑶抑苯永L制完整的一條path不會(huì)有鋸齒。所以這是最佳選擇。

代碼太多,就不附代碼了。

到此這篇關(guān)于Qt 鼠標(biāo)/觸屏繪制平滑曲線(支持矢量/非矢量方式)的文章就介紹到這了,更多相關(guān)Qt 繪制平滑曲線內(nèi)容請(qǐng)搜索億速云以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持億速云!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI