Qt編寫自定義控件54-時鍾儀表盤


一、前言

這個控件沒有太多的應用場景,主要就是練手,論美觀的話比不上之前發過的一個圖片時鍾控件,所以此控件也是作為一個基礎的繪制demo出現在Qt源碼中,我們可以在Qt的安裝目錄下找到一個時鍾控件的繪制,甚至還有qml版本,本控件無非就是一個儀表邊框加上時鍾分鍾刻度再加上時分秒指針,打完收工,我是在此基礎上增加了可以設置各種顏色,然后鼠標右鍵可設置四種效果 普通效果/彈簧效果/連續效果/隱藏效果,彈簧效果的意思是秒鍾走動的時候,先移動到超過指定位置,然后又重新彈回來,連續效果的意思是將步長減少,一點點的移動,將秒鍾的定時器精度調高。還有一個新增的功能是內置了設置系統時間公共槽函數,支持任意操作系統。

二、實現的功能

  • 1:可設置邊框顏色
  • 2:可設置前景色背景色
  • 3:可設置時鍾分鍾秒鍾指針顏色
  • 4:可設置刷新間隔
  • 5:鼠標右鍵可設置四種效果 普通效果/彈簧效果/連續效果/隱藏效果
  • 6:增加設置系統時間公共槽函數,支持任意操作系統

三、效果圖

四、頭文件代碼

#ifndef GAUGECLOCK_H
#define GAUGECLOCK_H

/**
 * 時鍾儀表盤控件 作者:feiyangqingyun(QQ:517216493) 2016-10-23
 * 1:可設置邊框顏色
 * 2:可設置前景色背景色
 * 3:可設置時鍾分鍾秒鍾指針顏色
 * 4:可設置刷新間隔
 * 5:鼠標右鍵可設置四種效果 普通效果/彈簧效果/連續效果/隱藏效果
 * 6:增加設置系統時間公共槽函數,支持任意操作系統
 */

#include <QWidget>

#ifdef quc
#if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
#include <QtDesigner/QDesignerExportWidget>
#else
#include <QtUiPlugin/QDesignerExportWidget>
#endif

class QDESIGNER_WIDGET_EXPORT GaugeClock : public QWidget
#else
class GaugeClock : public QWidget
#endif

{
	Q_OBJECT
	Q_ENUMS(SecondStyle)

	Q_PROPERTY(QColor crownColorStart READ getCrownColorStart WRITE setCrownColorStart)
	Q_PROPERTY(QColor crownColorEnd READ getCrownColorEnd WRITE setCrownColorEnd)

	Q_PROPERTY(QColor foreground READ getForeground WRITE setForeground)
	Q_PROPERTY(QColor background READ getBackground WRITE setBackground)

	Q_PROPERTY(QColor pointerHourColor READ getPointerHourColor WRITE setPointerHourColor)
	Q_PROPERTY(QColor pointerMinColor READ getPointerMinColor WRITE setPointerMinColor)
	Q_PROPERTY(QColor pointerSecColor READ getPointerSecColor WRITE setPointerSecColor)

    Q_PROPERTY(SecondStyle secondStyle READ getSecondStyle WRITE setSecondStyle)

public:
	enum SecondStyle {
		SecondStyle_Normal = 0,     //普通效果
		SecondStyle_Spring = 1,     //彈簧效果
		SecondStyle_Continue = 2,   //連續效果
		SecondStyle_Hide = 3        //隱藏效果
	};

	explicit GaugeClock(QWidget *parent = 0);
	~GaugeClock();

protected:
	void paintEvent(QPaintEvent *);
	void drawCrown(QPainter *painter);
	void drawBg(QPainter *painter);
	void drawScale(QPainter *painter);
	void drawScaleNum(QPainter *painter);
	void drawHour(QPainter *painter);
	void drawMin(QPainter *painter);
	void drawSec(QPainter *painter);
	void drawDot(QPainter *painter);

private:
    QColor crownColorStart;         //外邊框漸變開始顏色
	QColor crownColorEnd;           //外邊框漸變結束顏色

	QColor foreground;              //前景色
	QColor background;              //背景色

	QColor pointerHourColor;        //時鍾指針顏色
	QColor pointerMinColor;         //分鍾指針顏色
	QColor pointerSecColor;         //秒鍾指針顏色

    SecondStyle secondStyle;        //秒針走動樣式

	QTimer *timer;                  //定時器繪制
	int hour, min, sec, msec;       //時分秒毫秒

	QTimer *timerSpring;            //定時器顯示彈簧效果
	double angleSpring;             //彈簧角度

	QAction *action_secondstyle;    //秒針樣式右鍵菜單

private slots:
	void doAction();
	void updateTime();
	void updateSpring();

public:
	SecondStyle getSecondStyle()    const;

	QColor getCrownColorStart()     const;
	QColor getCrownColorEnd()       const;

	QColor getForeground()          const;
	QColor getBackground()          const;

	QColor getPointerHourColor()    const;
	QColor getPointerMinColor()     const;
	QColor getPointerSecColor()     const;

	QSize sizeHint()                const;
	QSize minimumSizeHint()         const;

public Q_SLOTS:
	//設置秒針走動樣式
    void setSecondStyle(const SecondStyle &secondStyle);
	//設置系統時間
    void setSystemDateTime(const QString &year, const QString &month, const QString &day,
                           const QString &hour, const QString &min, const QString &sec);

	//設置外邊框漸變顏色
    void setCrownColorStart(const QColor &crownColorStart);
    void setCrownColorEnd(const QColor &crownColorEnd);

	//設置前景色
    void setForeground(const QColor &foreground);
	//設備背景色
    void setBackground(const QColor &background);

	//設置時鍾指針顏色
    void setPointerHourColor(const QColor &pointerHourColor);
	//設置分鍾指針顏色
    void setPointerMinColor(const QColor &pointerMinColor);
	//設置秒鍾指針顏色
    void setPointerSecColor(const QColor &pointerSecColor);
};

#endif // GAUGECLOCK_H


五、核心代碼

void GaugeClock::paintEvent(QPaintEvent *)
{
    int width = this->width();
    int height = this->height();
    int side = qMin(width, height);

    //繪制准備工作,啟用反鋸齒,平移坐標軸中心,等比例縮放
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    painter.translate(width / 2, height / 2);    
    painter.scale(side / 200.0, side / 200.0);

    //繪制外邊框
    drawCrown(&painter);
    //繪制背景
    drawBg(&painter);
    //繪制刻度線
    drawScale(&painter);
    //繪制刻度值
    drawScaleNum(&painter);
    //繪制時鍾指針
    drawHour(&painter);
    //繪制分鍾指針
    drawMin(&painter);
    //繪制秒鍾指針
    drawSec(&painter);
    //繪制中心蓋板
    drawDot(&painter);
}

void GaugeClock::drawCrown(QPainter *painter)
{
    int radius = 99;
    painter->save();
    painter->setPen(Qt::NoPen);
    QLinearGradient crownGradient(0, -radius, 0, radius);
    crownGradient.setColorAt(0, crownColorStart);
    crownGradient.setColorAt(1, crownColorEnd);
    painter->setBrush(crownGradient);
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
    painter->restore();
}

void GaugeClock::drawBg(QPainter *painter)
{
    int radius = 92;
    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(background);
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
    painter->restore();
}

void GaugeClock::drawScale(QPainter *painter)
{
    int radius = 90;
    painter->save();

    QPen pen;
    pen.setColor(foreground);
    pen.setCapStyle(Qt::RoundCap);

    for (int i = 0; i <= 60; i++) {
        if (i % 5 == 0) {
            pen.setWidthF(1.5);
            painter->setPen(pen);
            painter->drawLine(0, radius - 10, 0, radius);
        } else {
            pen.setWidthF(0.5);
            painter->setPen(pen);
            painter->drawLine(0, radius - 5, 0, radius);
        }

        painter->rotate(6);
    }

    painter->restore();
}

void GaugeClock::drawScaleNum(QPainter *painter)
{
    int radius = 70;
    painter->save();
    painter->setPen(foreground);

    double startRad = 60 * (M_PI / 180);
    double deltaRad = 30 * (M_PI / 180);

    for (int i = 0; i < 12; i++) {
        double sina = qSin(startRad - i * deltaRad);
        double cosa = qCos(startRad - i * deltaRad);
        QString strValue = QString("%1").arg(i + 1);

        double textWidth = fontMetrics().width(strValue);
        double textHeight = fontMetrics().height();
        int x = radius * cosa - textWidth / 2;
        int y = -radius * sina + textHeight / 4;
        painter->drawText(x, y, strValue);
    }

    painter->restore();
}

void GaugeClock::drawHour(QPainter *painter)
{
    painter->save();

    //設置畫筆平滑圓角
    QPen pen;
    pen.setCapStyle(Qt::RoundCap);
    painter->setPen(pointerHourColor);
    painter->setBrush(pointerHourColor);

    QPolygon pts;
    pts.setPoints(4, -3, 8, 3, 8, 2, -40, -2, -40);    

    painter->rotate(30.0 * ((hour + min / 60.0)));    
    painter->drawConvexPolygon(pts);

    painter->restore();
}

void GaugeClock::drawMin(QPainter *painter)
{
    painter->save();

    //設置畫筆平滑圓角
    QPen pen;
    pen.setCapStyle(Qt::RoundCap);
    painter->setPen(pointerMinColor);
    painter->setBrush(pointerMinColor);

    QPolygon pts;
    pts.setPoints(4, -2, 8, 2, 8, 1, -60, -1, -60);

    painter->rotate(6.0 * (min + sec / 60.0));    
    painter->drawConvexPolygon(pts);

    painter->restore();
}

void GaugeClock::drawSec(QPainter *painter)
{
    if (secondStyle == SecondStyle_Hide) {
        return;
    }

    painter->save();

    //設置畫筆平滑圓角
    QPen pen;
    pen.setCapStyle(Qt::RoundCap);
    painter->setPen(pointerSecColor);
    painter->setBrush(pointerSecColor);

    QPolygon pts;
    pts.setPoints(3, -1, 10, 1, 10, 0, -70);

    painter->rotate(angleSpring);
    painter->drawConvexPolygon(pts);

    painter->restore();
}

void GaugeClock::drawDot(QPainter *painter)
{
    painter->save();
    QConicalGradient coneGradient(0, 0, -90.0);
    coneGradient.setColorAt(0.0, background);
    coneGradient.setColorAt(0.5, foreground);
    coneGradient.setColorAt(1.0, background);
    painter->setOpacity(0.9);
    painter->setPen(Qt::NoPen);
    painter->setBrush(coneGradient);
    painter->drawEllipse(-5, -5, 10, 10);
    painter->restore();
}

void GaugeClock::doAction()
{
    QAction *action = (QAction *)sender();
    QString str = action->text();

    if (str == "彈簧效果") {
        action->setText("連續效果");
        setSecondStyle(SecondStyle_Spring);
    } else if (str == "連續效果") {
        action->setText("隱藏效果");
        setSecondStyle(SecondStyle_Continue);
    } else if (str == "隱藏效果") {
        action->setText("普通效果");
        setSecondStyle(SecondStyle_Hide);
    } else if (str == "普通效果") {
        action->setText("彈簧效果");
        setSecondStyle(SecondStyle_Normal);
    }
}

六、控件介紹

  1. 超過150個精美控件,涵蓋了各種儀表盤、進度條、進度球、指南針、曲線圖、標尺、溫度計、導航條、導航欄,flatui、高亮按鈕、滑動選擇器、農歷等。遠超qwt集成的控件數量。
  2. 每個類都可以獨立成一個單獨的控件,零耦合,每個控件一個頭文件和一個實現文件,不依賴其他文件,方便單個控件以源碼形式集成到項目中,較少代碼量。qwt的控件類環環相扣,高度耦合,想要使用其中一個控件,必須包含所有的代碼。
  3. 全部純Qt編寫,QWidget+QPainter繪制,支持Qt4.6到Qt5.13的任何Qt版本,支持mingw、msvc、gcc等編譯器,支持任意操作系統比如windows+linux+mac+嵌入式linux等,不亂碼,可直接集成到Qt Creator中,和自帶的控件一樣使用,大部分效果只要設置幾個屬性即可,極為方便。
  4. 每個控件都有一個對應的單獨的包含該控件源碼的DEMO,方便參考使用。同時還提供一個所有控件使用的集成的DEMO。
  5. 每個控件的源代碼都有詳細中文注釋,都按照統一設計規范編寫,方便學習自定義控件的編寫。
  6. 每個控件默認配色和demo對應的配色都非常精美。
  7. 超過130個可見控件,6個不可見控件。
  8. 部分控件提供多種樣式風格選擇,多種指示器樣式選擇。
  9. 所有控件自適應窗體拉伸變化。
  10. 集成自定義控件屬性設計器,支持拖曳設計,所見即所得,支持導入導出xml格式。
  11. 自帶activex控件demo,所有控件可以直接運行在ie瀏覽器中。
  12. 集成fontawesome圖形字體+阿里巴巴iconfont收藏的幾百個圖形字體,享受圖形字體帶來的樂趣。
  13. 所有控件最后生成一個動態庫文件(dll或者so等),可以直接集成到qtcreator中拖曳設計使用。
  14. 目前已經有qml版本,后期會考慮出pyqt版本,如果用戶需求量很大的話。
  15. 自定義控件插件開放動態庫使用(永久免費),無任何后門和限制,請放心使用。
  16. 目前已提供26個版本的dll,其中包括了qt5.12.3 msvc2017 32+64 mingw 32+64 的。
  17. 不定期增加控件和完善控件,不定期更新SDK,歡迎各位提出建議,謝謝!
  18. Qt入門書籍推薦霍亞飛的《Qt Creator快速入門》《Qt5編程入門》,Qt進階書籍推薦官方的《C++ GUI Qt4編程》。
  19. 強烈推薦程序員自我修養和規划系列書《大話程序員》《程序員的成長課》《解憂程序員》,受益匪淺,受益終生!
  20. SDK下載鏈接:https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ 提取碼:877p


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM