一、螞蟻線
摘自互動(dòng)百科:在圖像影像軟件中表示選區(qū)的動(dòng)態(tài)虛線,因?yàn)樘摼€閃爍的樣子像是一群螞蟻在跑,所以俗稱螞蟻線。在Poshop,After
Effect等軟件中比較常見。
背景:用過(guò)excel的同學(xué)都知道,當(dāng)對(duì)單元格進(jìn)行復(fù)制時(shí),單元格周圍就會(huì)出現(xiàn)一個(gè)跑動(dòng)的矩形框,這個(gè)矩形框就被稱為螞蟻線。通過(guò)設(shè)置螞蟻線的線型和調(diào)整控件有效刷新次數(shù)我們可以得到不同的跑動(dòng)效果,這是一個(gè)非常有意思的現(xiàn)象。
二、效果展示
如下圖就是螞蟻線的效果截圖,單擊單元格時(shí),會(huì)繪制一個(gè)2個(gè)像素寬的外框;當(dāng)雙擊某個(gè)單元格時(shí),就會(huì)產(chǎn)生螞蟻線,螞蟻線的線型和跑動(dòng)速度都可以定制。文末會(huì)放出演示代碼下載鏈接。
三、實(shí)現(xiàn)
說(shuō)到Qt繪圖,肯定離不開paintEvent函數(shù),而且大多數(shù)的功能都可以通過(guò)重寫paintEvent函數(shù)來(lái)完成。凡是總有例外,當(dāng)控件本身就比較復(fù)雜,或者只需要重寫控件某一部分時(shí),就需要重寫一些其他東西來(lái)完成需求,比如表格螞蟻線繪制就屬于這個(gè)例外,當(dāng)我們重寫表格時(shí)就不能重寫paintEvent函數(shù),如果重寫這個(gè)函數(shù)那么表格的所有東西就需要我們自己去繪制,一個(gè)好的辦法就是重寫
QStyledItemDelegate代理
類,通過(guò)這個(gè)類我們可以定制表格控件的每一個(gè)項(xiàng)。下面我們就來(lái)仔細(xì)的分析下基于重寫代理類的實(shí)現(xiàn)細(xì)節(jié),理解下面4個(gè)實(shí)現(xiàn)維度后螞蟻線基本就完成了。 1、繪制區(qū)域
螞蟻線是針對(duì)表格項(xiàng)來(lái)進(jìn)行繪制的,因此首先想到的就是刷新表格某一項(xiàng)來(lái)進(jìn)行提高繪制效率,通過(guò)閱讀Qt源碼,找到QTableView::paintEvent函數(shù)中對(duì)表格項(xiàng)進(jìn)行了繪制,主要是通過(guò)調(diào)用QTableViewPrivate::drawCell函數(shù)來(lái)進(jìn)行每個(gè)單元格的繪制,該函數(shù)最后一行是通過(guò)QStyledItemDelegate類的paint方法來(lái)進(jìn)行繪制,與第三節(jié)第一段的說(shuō)明對(duì)應(yīng)起來(lái)。因此如果想進(jìn)行局部刷新看來(lái)困難比較大,因此最終決定每次刷新螞蟻線時(shí)對(duì)整個(gè)表格進(jìn)行刷新。
2、定時(shí)器
定時(shí)刷新,顧名思義就是我們需要一個(gè)定時(shí)器,定時(shí)刷新表格控件。首先想到的是我們自己維護(hù)一個(gè)QTimer,通過(guò)QTimer::timeout信號(hào)來(lái)刷新表格;除此之外QObject類已經(jīng)幫我們提供了一個(gè)timerEvent回調(diào)函數(shù),我們只需要通過(guò)startTime接口來(lái)啟動(dòng)一個(gè)定時(shí)器,timerEvent函數(shù)就會(huì)被定時(shí)調(diào)用,當(dāng)然了這個(gè)回調(diào)接口同時(shí)支持多個(gè)定時(shí)器,用timeID進(jìn)行區(qū)分每個(gè)定時(shí)器。
3、繪制策略
當(dāng)選擇一個(gè)單元格時(shí)(當(dāng)前單元格發(fā)現(xiàn)變化),繪制矩形框;繪制矩形框比較簡(jiǎn)單,這塊需要注意一個(gè)地方,就是當(dāng)繪制第一列的時(shí)候矩形框可能會(huì)跑出當(dāng)前項(xiàng),導(dǎo)致矩形框顯示不全。螞蟻線繪制時(shí)也存在這個(gè)問題。
void GMPFileItemDelegate::DrawBorderRect( QPainter * painter, const QRect &
rect, bool firstColumn ) const { painter->save(); QPen pen = painter->pen();
pen.setWidth(2); pen.setColor(QColor(0, 132, 255)); painter->setPen(pen); QRect
tmpRect = rect; if (firstColumn) { tmpRect.adjust(2, 1, -1, -1); } else {
tmpRect.adjust(1, 1, -1, -1); } painter->drawRect(tmpRect); painter->restore();
} 當(dāng)雙擊單元格時(shí)繪制螞蟻線,螞蟻線繪制是通過(guò)定時(shí)器進(jìn)行控制線框奔跑速度,這塊有一個(gè)需要注意的地方是只有當(dāng)定時(shí)器引起的繪制才會(huì)使螞蟻線往前跑。
根據(jù)螞蟻線的偏移繪制開始的空白區(qū)域,螞蟻線是由7個(gè)像素的藍(lán)色和2個(gè)像素的空白循環(huán)組成,當(dāng)偏移10個(gè)像素時(shí),重新回到偏移1個(gè)像素。 if (startPoint
!= truthPoint && offset > 2) { QPolygon polygon; for (int i = 4; i <= offset;
++i)//繪制前邊偏移的像素 { if (polygon.size() >= 7) { break; } polygon.append(truthPoint
- QPoint(i , 0)); } painter->drawPoints(polygon); } 4、界面刷新
qt有自己的界面刷新策略,平時(shí)使用比較多的也不外乎update(建議刷新)、repaint(強(qiáng)制刷新)兩個(gè)接口,但是這個(gè)兩個(gè)接口調(diào)用時(shí)也不是說(shuō)界面肯定會(huì)刷新,其實(shí)這兩個(gè)接口都是使用
QWidgetBackingStoreTracker類的sendUpdateRequest接口類來(lái)拋出的界面刷新事件
,Qt窗口有一個(gè)dirtyWidget的概念,當(dāng)判定這個(gè)窗口為需要刷新的窗口時(shí)才會(huì)調(diào)用sendUpdateRequest接口進(jìn)行界面刷新,如下代碼,update和repaint區(qū)別在于調(diào)用了switch的不同分支。
void QWidgetBackingStore::sendUpdateRequest(QWidget *widget, UpdateTime
updateTime) { if (!widget) return; switch (updateTime) { case UpdateLater:
updateRequestSent = true; QApplication::postEvent(widget, new
QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); break; case UpdateNow: {
QEvent event(QEvent::UpdateRequest); QApplication::sendEvent(widget, &event);
break; } } }
對(duì)于表格控件當(dāng)我們單純調(diào)用repaint或者update函數(shù)時(shí)是不能起到刷新界面的作用,因此我們需要調(diào)用其他能直接導(dǎo)致界面刷新的接口,目前我這塊想到了直接
調(diào)用窗口自身style的polish方法,如果大家有其他好的刷新方式可以留言。 通過(guò)以上4個(gè)小點(diǎn)的說(shuō)明,螞蟻線的實(shí)現(xiàn)基本就完成了。需要完整源碼的去csdn下載吧
四、下載鏈接
Qt螞蟻線-表格 <https://download.csdn.net/download/qq_30392343/10532988>
如果您覺得文章不錯(cuò),不妨給個(gè)打賞,寫作不易,感謝各位的支持。您的支持是我最大的動(dòng)力,謝謝?。?!? ?
??
很重要--轉(zhuǎn)載聲明
* 本站文章無(wú)特別說(shuō)明,皆為原創(chuàng),版權(quán)所有,轉(zhuǎn)載時(shí)請(qǐng)用鏈接的方式,給出原文出處。同時(shí)寫上原作者:朝十晚八
<https://www.cnblogs.com/swarmbees/>?or?Twowords
<https://www.jianshu.com/u/7673f8cfb4e6>
* 如要轉(zhuǎn)載,請(qǐng)?jiān)霓D(zhuǎn)載,如在轉(zhuǎn)載時(shí)修改本文,請(qǐng)事先告知,謝絕在轉(zhuǎn)載時(shí)通過(guò)修改本文達(dá)到有利于轉(zhuǎn)載者的目的。? 奮斗中的無(wú)名小卒。。。
<http://www.cnblogs.com/swarmbees/>
熱門工具 換一換