Qt繪制時(shí)鐘效果
簡(jiǎn)述
QPainter 提供了 2D 繪圖的常用操作,QTimer 提供了定時(shí)器功能,將兩者相結(jié)合,可以做出很多的自定義特效繪制。
下面,來(lái)實(shí)現(xiàn)一個(gè)每天都要接觸的東西 - 時(shí)鐘。包含了常見(jiàn)的所有功能:時(shí)針、分針、秒針。
實(shí)現(xiàn)方式
由于時(shí)鐘是妙級(jí)更新的,所以我們需要定時(shí)刷新,時(shí)鐘本身則使用之前講過(guò)的 QPainter 來(lái)進(jìn)行繪制。
使用 QTimer 定時(shí)刷新,設(shè)置超時(shí)時(shí)間為 1000 毫秒(1 秒)。
繪制時(shí)鐘,通過(guò) paintEvent() 實(shí)現(xiàn),包括:時(shí)針、分針、秒針、及面板、表盤(pán)等。
繪制小時(shí)對(duì)應(yīng)的文本,文本區(qū)域通過(guò) textRectF() 計(jì)算。
示例
效果
源碼
首先,我們構(gòu)造一個(gè)定時(shí)器 QTimer,連接其超時(shí)信號(hào) timeout() 到槽函數(shù) update(),當(dāng)調(diào)用 update() 時(shí),系統(tǒng)會(huì)自動(dòng)通知當(dāng)前界面進(jìn)行重繪(paintEvent())。
ClockWidget::ClockWidget(QWidget *parent) : QWidget(parent) { ... // 構(gòu)造定時(shí)器,設(shè)置超時(shí)為 1 秒 QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(update())); timer->start(1000); ... }
實(shí)現(xiàn)一個(gè)用于獲取文本區(qū)域的接口:
QRectF ClockWidget::textRectF(double radius, int pointSize, double angle) { QRectF rectF; rectF.setX(radius*qCos(angle*M_PI/180.0) - pointSize*2); rectF.setY(radius*qSin(angle*M_PI/180.0) - pointSize/2.0); rectF.setWidth(pointSize*4); rectF.setHeight(pointSize); return rectF; }
注意:這里,textRectF() 主要用于獲取小時(shí)對(duì)應(yīng)的文本區(qū)域。
重寫(xiě) paintEvent(),用于繪制時(shí)鐘。
void ClockWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event); // 時(shí)針、分針、秒針位置 - 多邊形 static const QPoint hourHand[3] = { QPoint(7, 8), QPoint(-7, 8), QPoint(0, -30) }; static const QPoint minuteHand[3] = { QPoint(7, 8), QPoint(-7, 8), QPoint(0, -65) }; static const QPoint secondHand[3] = { QPoint(7, 8), QPoint(-7, 8), QPoint(0, -80) }; // 時(shí)針、分針、秒針顏色 QColor hourColor(200, 100, 0, 200); QColor minuteColor(0, 127, 127, 150); QColor secondColor(0, 160, 230, 150); int side = qMin(width(), height()); QTime time = QTime::currentTime(); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 平移坐標(biāo)系原點(diǎn)至中心點(diǎn) painter.translate(width() / 2, height() / 2); // 縮放 painter.scale(side / 200.0, side / 200.0); // 繪制時(shí)針 painter.setPen(Qt::NoPen); painter.setBrush(hourColor); painter.save(); // 每圈360° = 12h 即:旋轉(zhuǎn)角度 = 小時(shí)數(shù) * 30° painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0))); painter.drawConvexPolygon(hourHand, 3); painter.restore(); painter.setPen(hourColor); // 繪制小時(shí)線(xiàn) (360度 / 12 = 30度) for (int i = 0; i < 12; ++i) { painter.drawLine(88, 0, 96, 0); painter.rotate(30.0); } int radius = 100; QFont font = painter.font(); font.setBold(true); painter.setFont(font); int pointSize = font.pointSize(); // 繪制小時(shí)文本 int nHour = 0; for (int i = 0; i < 12; ++i) { nHour = i + 3; if (nHour > 12) nHour -= 12; painter.drawText(textRectF(radius*0.8, pointSize, i * 30), Qt::AlignCenter, QString::number(nHour)); } // 繪制分針 painter.setPen(Qt::NoPen); painter.setBrush(minuteColor); painter.save(); // 每圈360° = 60m 即:旋轉(zhuǎn)角度 = 分鐘數(shù) * 6° painter.rotate(6.0 * (time.minute() + time.second() / 60.0)); painter.drawConvexPolygon(minuteHand, 3); painter.restore(); painter.setPen(minuteColor); // 繪制分鐘線(xiàn) (360度 / 60 = 6度) for (int j = 0; j < 60; ++j) { if ((j % 5) != 0) painter.drawLine(92, 0, 96, 0); painter.rotate(6.0); } // 繪制秒針 painter.setPen(Qt::NoPen); painter.setBrush(secondColor); painter.save(); // 每圈360° = 60s 即:旋轉(zhuǎn)角度 = 秒數(shù) * 6° painter.rotate(6.0 * time.second()); painter.drawConvexPolygon(secondHand, 3); painter.restore(); }
好了,注釋寫(xiě)的很清楚了,就不多做講解了,如果要做一個(gè)應(yīng)用,可以自己實(shí)現(xiàn)一些設(shè)置指針、表盤(pán)樣式外觀的一些接口。
注意:網(wǎng)上很多文本都是在旋轉(zhuǎn)之后繪制上去的,效果并不好(6 顯示的是 9),所以請(qǐng)避免這一點(diǎn)!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- QT實(shí)現(xiàn)動(dòng)態(tài)時(shí)鐘
- Qt實(shí)現(xiàn)指針式時(shí)鐘 Qt實(shí)現(xiàn)動(dòng)態(tài)時(shí)鐘
- Qt實(shí)現(xiàn)簡(jiǎn)易時(shí)鐘
- Qt繪制簡(jiǎn)單時(shí)鐘
- Qt編程實(shí)現(xiàn)小時(shí)鐘
- Qt設(shè)計(jì)時(shí)鐘效果
- QT實(shí)現(xiàn)簡(jiǎn)單時(shí)鐘效果
- Python+Pyqt實(shí)現(xiàn)簡(jiǎn)單GUI電子時(shí)鐘
- QTimer與QTime實(shí)現(xiàn)電子時(shí)鐘
- Qt實(shí)現(xiàn)簡(jiǎn)單動(dòng)態(tài)時(shí)鐘
相關(guān)文章
解決在Mac下直接解壓C++靜態(tài)庫(kù)出現(xiàn)的問(wèn)題
最近在研究C++的各種編譯構(gòu)建過(guò)程,學(xué)習(xí)了一下cmake,gyp/ninja這些自動(dòng)化構(gòu)建工具后,想著自己試下用純命令行跑一遍編譯流程。在試圖把C++靜態(tài)庫(kù)編譯為動(dòng)態(tài)庫(kù)的過(guò)程中遇到了棘手的問(wèn)題,找了好久后發(fā)現(xiàn)是跟Mac平臺(tái)相關(guān)的,這里記錄一下,望對(duì)遇到類(lèi)似問(wèn)題的童鞋有幫助。2016-12-12VS中scanf為何會(huì)報(bào)錯(cuò)詳解
在我們剛使用vs時(shí),在使用scanf函數(shù)時(shí)常會(huì)遇到報(bào)錯(cuò)提醒,下面這篇文章主要給大家介紹了關(guān)于VS中scanf為何會(huì)報(bào)錯(cuò)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02C語(yǔ)言進(jìn)程程序替換的實(shí)現(xiàn)詳解
為什么要進(jìn)程替換?因?yàn)楦高M(jìn)程創(chuàng)建出來(lái)的子進(jìn)程和父進(jìn)程擁有相同的代碼段,所以,子進(jìn)程看到的代碼和父進(jìn)程是一樣的。當(dāng)我們想要讓子進(jìn)程執(zhí)行不同的程序時(shí)候,就需要讓子進(jìn)程調(diào)用進(jìn)程程序替換的接口,從而讓子進(jìn)程執(zhí)行不一樣的代碼2022-08-08C++?vector與數(shù)組轉(zhuǎn)換寫(xiě)入/讀出文件方式
這篇文章主要介紹了C++?vector與數(shù)組轉(zhuǎn)換寫(xiě)入/讀出文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11Qt實(shí)現(xiàn)編寫(xiě)SMTP客戶(hù)端的示例詳解
這篇文章主要介紹了如何通過(guò)Qt實(shí)現(xiàn)編寫(xiě)SMTP客戶(hù)端,可以實(shí)現(xiàn)通過(guò)SMTP發(fā)送電子郵件(有文本,html,附件,內(nèi)聯(lián)文件等的MIME)。并支持SSL和SMTP身份驗(yàn)證,感興趣的可以學(xué)習(xí)一下2022-11-11C語(yǔ)言棧的表示與實(shí)現(xiàn)實(shí)例詳解
這篇文章主要介紹了C語(yǔ)言棧的表示與實(shí)現(xiàn),對(duì)于數(shù)據(jù)結(jié)構(gòu)與算法的研究有一定的借鑒價(jià)值,需要的朋友可以參考下2014-07-07Cocos2d-x 3.x入門(mén)教程(二):Node節(jié)點(diǎn)類(lèi)
這篇文章主要介紹了Cocos2d-x 3.x入門(mén)教程(二):Node節(jié)點(diǎn)類(lèi),本文對(duì)Node節(jié)點(diǎn)類(lèi)做了一個(gè)簡(jiǎn)明講解及Node類(lèi)提供的函數(shù)做了說(shuō)明,需要的朋友可以參考下2014-11-11C++可變參數(shù)函數(shù)的實(shí)現(xiàn)方法示例
這篇文章主要給大家介紹了關(guān)于C++可變參數(shù)函數(shù)的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12