這篇文章主要介紹了C#怎么實(shí)現(xiàn)炫酷啟動(dòng)圖-動(dòng)態(tài)進(jìn)度條效果,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司,專(zhuān)注成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、網(wǎng)站營(yíng)銷(xiāo)推廣,域名與空間,雅安服務(wù)器托管,網(wǎng)站運(yùn)營(yíng)有關(guān)企業(yè)網(wǎng)站制作方案、改版、費(fèi)用等問(wèn)題,請(qǐng)聯(lián)系創(chuàng)新互聯(lián)。最近接到一個(gè)新需求,讓做一個(gè)動(dòng)效進(jìn)度條。
由于我們的產(chǎn)品比較大,在軟件啟動(dòng)的時(shí)候會(huì)消耗比較長(zhǎng)的時(shí)間,原生的進(jìn)度條已經(jīng)不能滿足我們的需求,這里我們就需要一個(gè)會(huì)動(dòng)的進(jìn)度條,效果如下圖所示。
光效進(jìn)度條主要是做了一個(gè)進(jìn)度動(dòng)畫(huà),在已完成的部分上進(jìn)行快速的迭代渲染,給用戶一種直觀感受,我們的軟件一直努力加載,它還活著。
有了這個(gè)進(jìn)度條之后,當(dāng)我們的進(jìn)度從40%到50%這個(gè)持續(xù)的過(guò)程中,界面再也不會(huì)出現(xiàn)假死的情況,是不是很完美呢。。。
下面我就來(lái)分析下這個(gè)動(dòng)效進(jìn)度條是怎么做的
如效果圖所示,光效進(jìn)度條不同于一般的進(jìn)度條,他在基礎(chǔ)的任務(wù)進(jìn)度之上還添加了一層光效,主要是想告訴用戶我們的軟件一直在努力運(yùn)行,請(qǐng)?jiān)谀托牡牡却幌孪隆?/p>
我自己在做功能的時(shí)候,往往喜歡先做一個(gè)測(cè)試demo,然后在把做好的功能集成在正式環(huán)境,這個(gè)功能也不列外,如第一節(jié)中展示的效果圖,就是測(cè)試demo的樣子,雖然很丑,但是基礎(chǔ)功能是有的。
現(xiàn)在的很多軟件,在進(jìn)度展示上都有了比較絢麗的效果,比如壓縮軟件,解壓文件的時(shí)候都會(huì)有動(dòng)效進(jìn)度條,用過(guò)的同學(xué)應(yīng)該都知道長(zhǎng)啥樣,而我們的光效進(jìn)度條跟這個(gè)效果差不多,除此之外我們還提供了另一種動(dòng)效,延遲動(dòng)效,他們兩個(gè)在一定程度上都展示了更友好的進(jìn)度效果。
在開(kāi)始分析功能前,首先我們先來(lái)考慮下我們的需求:動(dòng)效進(jìn)度條,也就是說(shuō)在原來(lái)的進(jìn)度條基礎(chǔ)上需要添加實(shí)時(shí)動(dòng)畫(huà),讓進(jìn)度條看起來(lái)更炫酷一些,除了光效進(jìn)度條以外,還有一種延遲到達(dá)進(jìn)度條,也屬于動(dòng)態(tài)進(jìn)度條。
延遲動(dòng)效、說(shuō)直白一點(diǎn)兒就是延遲到達(dá),當(dāng)我們?cè)O(shè)置了進(jìn)度從10%到20%時(shí),程序模擬了一個(gè)漸進(jìn)的過(guò)程,使用一個(gè)時(shí)間段走完了這10%的進(jìn)度。
下面我們分別來(lái)介紹這兩種進(jìn)度條的實(shí)現(xiàn)
實(shí)現(xiàn)炫酷的進(jìn)度條我們可以從QWidget自定義開(kāi)始寫(xiě),也就是說(shuō)從頭開(kāi)始寫(xiě),但通常我們不這樣干,因?yàn)檫@樣可能會(huì)寫(xiě)出無(wú)窮無(wú)盡的bug,而且現(xiàn)有的輪子已經(jīng)很穩(wěn)定了,為什么還要造呢。
1、光效進(jìn)度條
光效進(jìn)度條我們使用了一個(gè)小技巧,采用一個(gè)簡(jiǎn)單的辦法實(shí)現(xiàn),我們的光效進(jìn)度條控件繼承自Qt原生進(jìn)度條類(lèi)QProgressBar,在新類(lèi)中我們只需要在Qt繪制完原生進(jìn)度條之后,補(bǔ)畫(huà)動(dòng)效即可。
a、paintEvent函數(shù)
paintEvent函數(shù)是Qt的繪制函數(shù),當(dāng)界面刷新的時(shí)候,這個(gè)接口函數(shù)就會(huì)被調(diào)用,因此我們需要重寫(xiě)這個(gè)接口,首先調(diào)用父窗口的繪制方法,然后我們?cè)诶L制我們自己的動(dòng)效,代碼如下所示
QProgressBar::paintEvent(event); drawCache繪制動(dòng)效
b、drawCache繪制動(dòng)效
繪制動(dòng)效的時(shí)候,我們需要知道動(dòng)效的繪制區(qū)域,這個(gè)地方我們需要主動(dòng)去解析qss的一些參數(shù),Qt的style()->subElementRect這個(gè)接口剛好可以拿到我們需要的信息
下面簡(jiǎn)單描述下我們的實(shí)現(xiàn)流程
?首先我們獲取進(jìn)度條的幾何大小和中間進(jìn)度的幾何大小,這樣的話我們就可以計(jì)算出來(lái)各border的數(shù)值
?然后根據(jù)我們當(dāng)前的value值就可以計(jì)算出進(jìn)度條已經(jīng)走過(guò)(就是值小于我們?cè)O(shè)定的區(qū)域)的幾何大小
?我們的光效將是跑在第二步計(jì)算出來(lái)的區(qū)域上,一直循環(huán)迭代
?內(nèi)存里我們維護(hù)一個(gè)cacheValue,這個(gè)值在每次界面刷新的時(shí)候遞增,但是不能大于第二步的value值,cacheValue將是我們動(dòng)效繪制的一個(gè)關(guān)鍵參數(shù),他表示了動(dòng)效繪制的長(zhǎng)度
?構(gòu)造一個(gè)漸變刷子,設(shè)置給QPainter
?繪制動(dòng)效
上下大致描述了下繪制動(dòng)效的一個(gè)流程,下面送上具體代碼,由于篇幅原因,代碼我進(jìn)行了部分偽代碼處理。
void GMPProgressBar::drawCache() { QStyleOptionProgressBarV2 opt; QRect outerRect = style()->subElementRect(QStyle::SE_ProgressBarGroove, &opt, this); QRect innerRect = style()->subElementRect(QStyle::SE_ProgressBarContents, &opt, this); QMargins borders(構(gòu)造一個(gè)QMargins);
QRectF rect(動(dòng)效繪制區(qū)域);
if (m_iCacheValue != 0) { QPainter painter(this); QLinearGradient gradient(構(gòu)造繪圖刷子); painter.setBrush(gradient); painter.drawRoundedRect(rect, 2, 2); } }
c、定時(shí)刷新
由于我們的動(dòng)效是需要主動(dòng)去刷新的,因此我們需要聲明一個(gè)定時(shí)器,然后定時(shí)去刷新,實(shí)現(xiàn)代碼可能像下面這樣
connect(m_pCacheTimer, &QTimer::timeout, this, [this]{ if (TM_CACHE == m_mode) { ++m_iCacheValue; repaint(); }else { m_pCacheTimer->stop(); } });
定時(shí)器只需要在我們第一次設(shè)置進(jìn)度條值的時(shí)候啟動(dòng),或者當(dāng)我們?cè)O(shè)置一個(gè)新的值,而定時(shí)器沒(méi)有啟動(dòng),我們就需要去激活定時(shí)器。
TM_CACHE模式即是我們的動(dòng)效模式,TM_SMOOTH模式則是我們的延遲到達(dá)模式
connect(this, &QProgressBar::valueChanged, [this](int value){//TM_CACHE模式下 啟動(dòng)動(dòng)畫(huà)時(shí)機(jī) if (!m_pCacheTimer->isActive() && value != 0 && TM_CACHE == m_mode) { m_pCacheTimer->start(m_iRefreshleveling); } });
動(dòng)效進(jìn)度條效果如下圖所示
2、延遲到達(dá)進(jìn)度條
動(dòng)效進(jìn)度條可能更適用于啟動(dòng)界面,但是也有一些時(shí)候,我們可能需要更平緩的一個(gè)加載曲線,例如安裝軟件、卸載軟件的時(shí)候。
a、setValue
延遲到達(dá)進(jìn)度條和動(dòng)效進(jìn)度條的實(shí)現(xiàn)方式就有所差別了,對(duì)于實(shí)現(xiàn)延遲到達(dá)進(jìn)度條,我們這里重寫(xiě)了setValue函數(shù),當(dāng)外部調(diào)用該接口設(shè)置value值時(shí),我們并沒(méi)有立即去設(shè)置當(dāng)前值,而是使用了一個(gè)時(shí)間段去完成這個(gè)值得刷新。
?外部調(diào)用setValue時(shí),我們首先計(jì)算出我們應(yīng)該繪制的大寬度PixelMax、當(dāng)前已經(jīng)繪制到的大寬度cacheValue和我們的步長(zhǎng)
?設(shè)置定時(shí)器刷新頻率,并重啟定時(shí)器
?定時(shí)器刷新時(shí),cacheValue自增我們的步長(zhǎng)
?調(diào)用父類(lèi)的QProgressBar::setValue接口設(shè)置值
b、定時(shí)器
延遲達(dá)到功能的的定時(shí)器和之前我們什么的動(dòng)效定時(shí)器可以混用一個(gè),我們定時(shí)器刷新的時(shí)候,針對(duì)不同的動(dòng)畫(huà)模式,我們執(zhí)行不同的的代碼即可,實(shí)現(xiàn)代碼可能像下面這樣
connect(m_pCacheTimer, &QTimer::timeout, this, [this]{ if (TM_CACHE == m_mode) { ++m_iCacheValue; repaint(); } else if (TM_SMOOTH == m_mode) { changeSmooth(); } else { m_pCacheTimer->stop(); } });
延遲到達(dá)進(jìn)度條效果如下圖所示
3、接口說(shuō)明
光效進(jìn)度條類(lèi)對(duì)外只暴露了3個(gè)接口,分別是設(shè)置動(dòng)畫(huà)模式、動(dòng)畫(huà)時(shí)長(zhǎng)和刷新頻率
特別需要注意的是,我們這里重寫(xiě)了父類(lèi)的setValue接口,這意味著我們不能使用多態(tài)來(lái)操作這個(gè)接口
void setTransitionMode(TransitionMode mode);//設(shè)置動(dòng)畫(huà)模式 void setSmoothDuration(int duration);//設(shè)置刷新總時(shí)長(zhǎng) 模式為T(mén)M_SMOOTH時(shí)有效 void setRefreshleveling(int rate);//設(shè)置刷新頻率 每次更改TransitionMode之后會(huì)變?yōu)槟J(rèn)值
a、修改動(dòng)畫(huà)模式
修改動(dòng)畫(huà)模式的時(shí)候,我們需要清空內(nèi)存中的所有數(shù)據(jù),并把value值設(shè)為0。
void GMPProgressBar::setTransitionMode(TransitionMode mode) { if (m_mode == mode) { return; } m_mode = mode; clearData(); QProgressBar::setValue(0); }
b、其他接口
設(shè)置刷新時(shí)長(zhǎng)和頻率接口都比較簡(jiǎn)單,不做特別說(shuō)明
特別注意:這個(gè)3個(gè)接口最好是在動(dòng)畫(huà)啟動(dòng)前設(shè)置,動(dòng)畫(huà)開(kāi)始后盡量不要去調(diào)用
第二節(jié)我們主要是講述了怎么做一個(gè)動(dòng)效進(jìn)度條,這一節(jié)我們來(lái)做一個(gè)啟動(dòng)圖頁(yè)面,把這個(gè)動(dòng)效使用進(jìn)去。
啟動(dòng)圖不是我們主要分析的內(nèi)容,這個(gè)我就簡(jiǎn)單說(shuō)下這個(gè)類(lèi)的實(shí)現(xiàn)方式和一些借口說(shuō)明
1、實(shí)現(xiàn)思路
Qt已經(jīng)給我們提供了一個(gè)QSplashScreen,但是使用起來(lái)還是特別有限,因此這里我把Qt的源碼直接進(jìn)行了二次開(kāi)發(fā)
?首先Qt的原生實(shí)現(xiàn)方式基本都被移植了出來(lái)
?啟動(dòng)圖使用了簡(jiǎn)單的上下布局,上面是一張我自繪制的圖片,放在了一個(gè)QLabel上,下面是動(dòng)效進(jìn)度條
?自繪制的圖片上包括了,產(chǎn)品名稱(chēng)、logo、背景圖等等
2、背景圖切換
當(dāng)我們調(diào)用setPixmap設(shè)置背景圖時(shí),如果我們指定了多張圖,我將會(huì)啟動(dòng)一個(gè)定時(shí)器,在指定時(shí)長(zhǎng)后重新構(gòu)造一張大的背景圖,并添加到啟動(dòng)窗口上
這里主要說(shuō)明下背景圖是怎么構(gòu)造出來(lái)的,代碼如下所示
a、根據(jù)背景圖構(gòu)造啟動(dòng)圖大小,并移動(dòng)到屏幕中間
m_currentPixmap = m_lstPixmaps.at(m_iCurrentIndex); QRect size(QPoint(), m_currentPixmap.size() / m_currentPixmap.devicePixelRatio()); size.setHeight(size.height() + StatusBarHeight); setFixedSize(size.size()); m_pProgressBar->setFixedWidth(size.width() / 8 * 3); move(QApplication::desktop()->screenGeometry().center() - size.center());
b、繪制程序logo
QPainter painter(&m_currentPixmap); painter.drawPixmap(m_startPos, m_logo);
c、繪制標(biāo)題欄
painter.save(); painter.setFont(m_titleFont); QFontMetrics fontMetrics(m_titleFont); int textWidth = fontMetrics.width(m_strWindowTitle); int textHegith = m_logo.height(); QRect textTect = QRect(m_startPos + QPoint(13 + m_logo.width(), 0), QSize(textWidth, textHegith)); painter.drawText(textTect, m_strWindowTitle, QTextOption(Qt::AlignCenter)); painter.restore();
d、設(shè)置給QLabel背景圖
m_pWindowBackground->setPixmap(m_currentPixmap);
啟動(dòng)圖的效果這里就不在貼圖了,第三節(jié)上的兩個(gè)gif圖都是最終的啟動(dòng)圖效果
最后就是測(cè)試代碼了,主要是模擬了程序的一個(gè)加載過(guò)程
1、構(gòu)造啟動(dòng)圖
首先我們構(gòu)造一個(gè)啟動(dòng)圖對(duì)象,并設(shè)置程序logo和動(dòng)畫(huà)模式
GMPSplashScreen * screen = new GMPSplashScreen(QPixmap(":/splashScreen/start.png")); screen->show(); screen->setLogo(QIcon("logo.ico").pixmap(48, 48)); screen->setTransitionMode(GMPProgressBar::TM_CACHE);
2、背景圖
設(shè)置背景圖,并設(shè)置背景圖更換時(shí)間間隔
QListlstPixmap; lstPixmap.append(QPixmap(":/splashScreen/start.png")); lstPixmap.append(QPixmap(":/splashScreen/start.jpg")); screen->setPixmap(lstPixmap, 2000);
3、其他信息
設(shè)置程序的提示信息和標(biāo)題欄
screen->showMessage("Established connections", 0); screen->setTitle(QStringLiteral("廣聯(lián)達(dá)BIM土建計(jì)量GTJ2018"));
4、事件循環(huán)
這里寫(xiě)了一個(gè)死循環(huán),主要是為了模擬程序的一個(gè)加載過(guò)程,每隔10ms處理下界面刷新事件
a.processEvents(); while (1) { QTest::qSleep(10); a.processEvents(); } splashScreen w; w.show(); screen->finish(&w);
C#是一個(gè)簡(jiǎn)單、通用、面向?qū)ο蟮木幊陶Z(yǔ)言,它由微軟Microsoft開(kāi)發(fā),繼承了C和C++強(qiáng)大功能,并且去掉了一些它們的復(fù)雜特性,C#綜合了VB簡(jiǎn)單的可視化操作和C++的高運(yùn)行效率,以其強(qiáng)大的操作能力、優(yōu)雅的語(yǔ)法風(fēng)格、創(chuàng)新的語(yǔ)言特性和便捷的面向組件編程從而成為.NET開(kāi)發(fā)的選語(yǔ)言,但它不適用于編寫(xiě)時(shí)間急迫或性能非常高的代碼,因?yàn)镃#缺乏性能極高的應(yīng)用程序所需要的關(guān)鍵功能。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“C#怎么實(shí)現(xiàn)炫酷啟動(dòng)圖-動(dòng)態(tài)進(jìn)度條效果”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián)成都網(wǎng)站設(shè)計(jì)公司,關(guān)注創(chuàng)新互聯(lián)成都網(wǎng)站設(shè)計(jì)公司行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、網(wǎng)站設(shè)計(jì)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。