Qt:自定义钟表组件

使用QWidget绘制两种钟表组件,效果如下:

源码下载链接:GitHub - DengYong1988/Clock-Widget: Qt 自定义钟表组件

https://download.csdn.net/download/ouyangxiaozi/89616407

主要代码如下:

ClockWgt.h

cpp 复制代码
#ifndef CLOCKWGT_H
#define CLOCKWGT_H

#include <QWidget>

class QTimer;

/************************ ClockWgt *************************/
class ClockWgt : public QWidget
{
    Q_OBJECT
public:
    explicit ClockWgt(QWidget *parent = nullptr);
    ~ClockWgt();
    
private:
    void initData();
    void resetGradient(QRadialGradient &grad, qreal radius);
    void updatePath();
    
protected:
    void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
    void drawBkg(QPainter &painter);        // 绘制背景
    void drawHand(QPainter &painter);       // 绘制时分秒
    
    void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
    
private:
    // 钟表的局部
    struct SPart {
        QRadialGradient     grad;       // 背景色
        QPainterPath        path;       // 路径
        int                 width;      // 宽度
        
        SPart();
    };

    SPart       m_outerFrame;           // 钟表的外边框
    SPart       m_innerFrame;           // 钟表内边框
    SPart       m_bkgPart;              // 钟表背景部分
    
    QTimer      *m_timer = nullptr;
    
    QColor      m_timescaleClr;         // 时间刻度颜色
    QColor      m_timeDigitClr;         // 时间数字颜色
    QFont       m_timeDigitFont;        // 时间数字字体
    
    QTransform      m_transform;        // 绘图时的坐标转换
    QRadialGradient m_needleGrad;       // 图针的背景
    int             m_needleRadius;     // 图针的半径
    QPainterPath    m_hourPath;         // 时钟路径
    QPainterPath    m_minutePath;       // 分钟路径
    QPainterPath    m_secondPath;       // 秒钟路径
};

#endif // CLOCKWGT_H

ClockWgt.cpp

cpp 复制代码
#include "ClockWgt.h"
#include <QPainter>
#include <QResizeEvent>
#include <QTime>
#include <QTimer>
#include <qmath.h>

/************************ ClockWgt *************************/
ClockWgt::ClockWgt(QWidget *parent)
    : QWidget(parent)
{
    initData();
}

ClockWgt::~ClockWgt()
{
    if (m_timer) {
        if (m_timer->isActive())
            m_timer->stop();
        
        m_timer->deleteLater();
        m_timer = nullptr;
    }
}

ClockWgt::SPart::SPart()
    : width(0)
{
    grad.setSpread(QGradient::PadSpread);
}

void ClockWgt::initData()
{
    m_outerFrame.grad.setColorAt(0.9, QColor(250, 36, 66));
    m_outerFrame.grad.setColorAt(0.95, QColor(250, 36, 66, 235));
    m_outerFrame.grad.setColorAt(1, QColor(250, 36, 66, 96));
    m_outerFrame.width = 20;
    
    m_innerFrame.grad.setColorAt(0.8, QColor(200, 200, 200));
    m_innerFrame.grad.setColorAt(1, QColor(235, 235, 245));
    m_innerFrame.width = 10;
    
    m_bkgPart.grad.setColorAt(0, QColor(223, 231, 254));
    m_bkgPart.grad.setColorAt(0.2, QColor(238, 238, 250));
    m_bkgPart.grad.setColorAt(0.8, QColor(238, 238, 250));
    m_bkgPart.grad.setColorAt(0.9, QColor(213, 218, 254));
    m_bkgPart.grad.setColorAt(1, QColor(213, 218, 254));
    
    m_needleRadius = 10;
    m_needleGrad.setSpread(QGradient::PadSpread);
    m_needleGrad.setRadius(20);
    m_needleGrad.setCenter(0, 0);
    m_needleGrad.setFocalPoint(0, 0);
    m_needleGrad.setColorAt(0, QColor(220, 220, 230));
    m_needleGrad.setColorAt(1, QColor(20, 20, 20));
    
    m_timescaleClr.setRgb(7, 7, 9);
    m_timeDigitClr.setRgb(7, 7, 9);
    
    m_timeDigitFont.setFamily("Arial");
    m_timeDigitFont.setPixelSize(44);
    m_timeDigitFont.setWeight(QFont::Bold);

    m_timer = new QTimer(this);
    m_timer->setInterval(1000);
    m_timer->start();
    
    connect(m_timer, &QTimer::timeout, this, [this] {
        this->update();
    });
}

void ClockWgt::resetGradient(QRadialGradient &grad, qreal radius)
{
    grad.setCenter(radius, radius);
    grad.setFocalPoint(radius, radius);
    grad.setCenterRadius(radius);    
}

void ClockWgt::updatePath()
{
    int diameter = qMin(width(), height());
    int offset = m_outerFrame.width;
    
    m_outerFrame.path.addEllipse(QRectF(0, 0, diameter, diameter));
    diameter -= 2 * m_outerFrame.width;
    m_outerFrame.path.addEllipse(QRectF(offset, offset, diameter, diameter));
    
    m_innerFrame.path.addEllipse(QRectF(offset, offset, diameter, diameter));
    offset += m_innerFrame.width;
    diameter -= 2 * m_innerFrame.width;
    m_innerFrame.path.addEllipse(QRectF(offset, offset, diameter, diameter));
    
    m_bkgPart.path.addEllipse(QRectF(offset, offset, diameter, diameter));
    
    m_hourPath.addRoundedRect(-20, -5, 140, 10, 4, 4);
    m_minutePath.addRoundedRect(-20, -4, 200, 8, 4, 4);
    
    m_secondPath.moveTo(-40, 0);
    m_secondPath.lineTo(-36, -4);
    m_secondPath.lineTo(0, -2);
    m_secondPath.lineTo(180, 0);
    m_secondPath.lineTo(0, 2);
    m_secondPath.lineTo(-36, 4);
    m_secondPath.lineTo(-40, 0);
}

void ClockWgt::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setRenderHint(QPainter::TextAntialiasing, true);
    
    drawBkg(painter);
    drawHand(painter);
}

void ClockWgt::drawBkg(QPainter &painter)
{
    painter.fillPath(m_outerFrame.path, m_outerFrame.grad);
    painter.fillPath(m_innerFrame.path, m_innerFrame.grad);
    painter.fillPath(m_bkgPart.path, m_bkgPart.grad);
    
    const qreal radius = qMin(0.5 * width(), 0.5 * height());
    QPen pen(m_timescaleClr);
    m_transform.reset();
    
    for (int i = 0; i < 60; ++i) {
        int len = 6;
        if (0 == (i % 5)) {
            pen.setWidthF(3.0);
        } else {
            pen.setWidthF(1.0);
        }
        
        painter.setPen(pen);
        
        qreal innerRadius = radius - m_outerFrame.width - m_innerFrame.width - 10 - len;
        qreal xPos = radius + innerRadius * qCos(2 * M_PI * 6 * i / 360);
        qreal yPos = radius - innerRadius * qSin(2 * M_PI * 6 * i / 360);
        m_transform.translate(xPos, yPos);
        m_transform.rotate(-6 * i);
        painter.setTransform(m_transform);
        painter.drawLine(QPoint(-len, 0), QPoint(len, 0));
        m_transform.reset();
    }
    
    pen.setColor(m_timeDigitClr);
    painter.setPen(pen);
    painter.setFont(m_timeDigitFont);
    
    for (int i = 1; i <= 12; ++i) {
        QFontMetrics fm(m_timeDigitFont);
        QString text = QString::number(i);
        
        qreal innerRadius = radius - m_outerFrame.width - m_innerFrame.width - 10 - 36;
        qreal angle = 30 * i - 90;
        qreal xPos = radius + innerRadius * qCos(2 * M_PI * angle / 360);
        qreal yPos = radius + innerRadius * qSin(2 * M_PI * angle / 360);

        m_transform.translate(xPos, yPos);
        painter.setTransform(m_transform);
        painter.drawText(-fm.horizontalAdvance(text) / 2, fm.height() / 2 - fm.descent(), text);
        m_transform.reset();
    }
}

void ClockWgt::drawHand(QPainter &painter)
{
    const qreal radius = qMin(0.5 * width(), 0.5 * height());
    const QTime &dtCurr = QTime::currentTime();
    
    m_transform.reset();
    m_transform.translate(radius, radius);
    
    int h = dtCurr.hour();
    int m = dtCurr.minute();
    int s = dtCurr.second();
    m_transform.rotate(30 * h - 90 + 0.5 * m);
    painter.setTransform(m_transform);
    painter.fillPath(m_hourPath, Qt::black);
    
    m_transform.reset();
    m_transform.translate(radius, radius);
    m_transform.rotate(6 * m - 90);
    painter.setTransform(m_transform);
    painter.fillPath(m_minutePath, Qt::black);
    
    m_transform.reset();
    m_transform.translate(radius, radius);
    m_transform.rotate(6 * s - 90);
    painter.setTransform(m_transform);
    painter.fillPath(m_secondPath, Qt::red);
    
    m_transform.reset();
    m_transform.translate(radius, radius);
    painter.setTransform(m_transform);
    m_transform.reset();
    
    painter.setBrush(m_needleGrad);
    painter.setPen(Qt::transparent);
    painter.drawEllipse(QPoint(0, 0), m_needleRadius, m_needleRadius);
}

void ClockWgt::resizeEvent(QResizeEvent *event)
{
    if (event) {
        const QSize &size = event->size();
        qreal radius = qMin(0.5 * size.width(), 0.5 * size.height());
        
        resetGradient(m_outerFrame.grad, radius);
        resetGradient(m_innerFrame.grad, radius);
        resetGradient(m_bkgPart.grad, radius);
        
        updatePath();
    }
    
    QWidget::resizeEvent(event);
}

DigitalWatchWgt.h

cpp 复制代码
#ifndef DIGITALWATCHWGT_H
#define DIGITALWATCHWGT_H

#include <QWidget>

const int kNumCount = 6;            // 时、分、秒数字数
const int kLineCount = 7;           // 数字8的线条数

class QTimer;

class DigitalWatchWgt : public QWidget
{
    Q_OBJECT
public:
    explicit DigitalWatchWgt(bool isShowSecond, QWidget *parent = nullptr);
    ~DigitalWatchWgt();
    
    void setFixedSize(const QSize &size);
    void setFixedSize(int w, int h);
    
    void setMargin(const QMargins &margin);
    void setNumSpacing(int spacing);
    void setColonSpacing(int spacing);
    
    // 设置组件边框
    void setBorder(qreal border);
    
    // 设置线条之间的偏移量
    void setLineOffset(qreal offset);
    
    // 设置边框颜色
    void setBorderColor(const QColor &borColor);
    
    // 设置组件圆角
    void setBorderRadius(qreal borRadius);
    
    // 设置背景色
    void setBackground(const QColor &bkg);
    
    // 设置数字显示的颜色
    void setNumColor(const QColor &lightColor, const QColor &darkColor);
    
    // 设置数字显示的尺寸
    void setNumSize(const QSizeF &size);
    
    // 设置数字边框粗细
    void setNumBorder(qreal border);
    
    // 设置冒号点宽度
    void setDotWidth(qreal dotWid);
    
private:
    void initData();
    void adaptSize();
    void adjustPos();
    void calcLinePath();
    
protected:
    void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
    
    void drawBackground(QPainter &painter);
    void drawNumber(QPainter &painter, const QChar &num);
    void fillLinePath(QPainter &painter, bool *isDarkColor);
    void drawColon(QPainter &painter, const QRectF &rf);
    
private:
    struct SNumber {
        QChar       m_text;
        qreal       m_topX;
        qreal       m_topY;
        
        explicit SNumber();
        explicit SNumber(const QChar &text);
    };
    
private:
    bool            m_isShowSecond;     // 是否显示秒数
    QMargins        m_margin;
    int             m_numSpacing;       // 数字之间的间距
    int             m_colonSpacing;     // 数字和冒号之间的间距
    qreal           m_border;           // 组件边框
    qreal           m_borRadius;        // 圆角
    qreal           m_lineOffset;       // 线条之间的偏移量
    
    QColor          m_bkgColor;         // 背景色
    QColor          m_borColor;         // 边框色
    QColor          m_numLightColor;    // 数字浅色
    QColor          m_numDarkColor;     // 数字深色
    QSizeF          m_numSize;          // 数字尺寸
    qreal           m_numBorder;        // 数字边框粗细
    qreal           m_dotWid;           // 冒号点宽度
    QRectF          m_rfColon[2];       // 冒号的位置
    
    QTimer          *m_timer = nullptr;
    SNumber         m_number[kNumCount];// 时分秒数字
    QPainterPath    m_linePath[kLineCount];
    QTransform      m_tfDrawing;
};

#endif // DIGITALWATCHWGT_H

DigitalWatchWgt.cpp

cpp 复制代码
#include "DigitalWatchWgt.h"
#include <QTimer>
#include <QTime>
#include <QPainter>

DigitalWatchWgt::DigitalWatchWgt(bool isShowSecond, QWidget *parent)
    : QWidget(parent), m_isShowSecond(isShowSecond)
{
    initData();
}

DigitalWatchWgt::~DigitalWatchWgt()
{
    if (m_timer && m_timer->isActive()) {
        m_timer->stop();
    }
}

void DigitalWatchWgt::setFixedSize(const QSize &size)
{
    this->setFixedSize(size.width(), size.height());
}

void DigitalWatchWgt::setFixedSize(int w, int h)
{
    qreal wid = 2 * m_border + m_margin.left() + m_margin.right();
    qreal hgt = m_margin.top() + m_margin.bottom() + 2 * m_border;
    
    if (m_isShowSecond) {
        wid += 3 * m_numSpacing + 4 * m_colonSpacing + 2 * m_dotWid;
    } else {
        wid += 2 * m_numSpacing + 2 * m_colonSpacing + m_dotWid;
    }
    
    if (w > wid && h > hgt) {
        if (m_isShowSecond) {
            m_numSize.rwidth() = (w - wid) / kNumCount;
        } else {
            m_numSize.rwidth() = (w - wid) / 4;
        }
        
        m_numSize.rheight() = h - hgt;        
        QWidget::setFixedSize(w, h);
        
        adjustPos();
        calcLinePath();
    }
}

void DigitalWatchWgt::setMargin(const QMargins &margin)
{
    m_margin = margin;
    adaptSize();
}

void DigitalWatchWgt::setNumSpacing(int spacing)
{
    m_numSpacing = spacing;
    adaptSize();
}

void DigitalWatchWgt::setColonSpacing(int spacing)
{
    m_colonSpacing = spacing;
    adaptSize();
}

// 设置组件边框
void DigitalWatchWgt::setBorder(qreal border)
{
    m_border = border;
    adaptSize();
}

// 设置线条之间的偏移量
void DigitalWatchWgt::setLineOffset(qreal offset)
{
    m_lineOffset = offset > 0 ? offset : 0;
}

// 设置边框颜色
void DigitalWatchWgt::setBorderColor(const QColor &borColor)
{
    m_borColor = borColor;
}

// 设置组件圆角
void DigitalWatchWgt::setBorderRadius(qreal borRadius)
{
    m_borRadius = borRadius;
}

// 设置背景色
void DigitalWatchWgt::setBackground(const QColor &bkg)
{
    m_bkgColor = bkg;
}

// 设置数字显示的颜色
void DigitalWatchWgt::setNumColor(const QColor &lightColor, const QColor &darkColor)
{
    m_numLightColor = lightColor;
    m_numDarkColor = darkColor;
}

// 设置数字显示的尺寸
void DigitalWatchWgt::setNumSize(const QSizeF &size)
{
    m_numSize = size;
    adaptSize();
    calcLinePath();
}

// 设置数字边框粗细
void DigitalWatchWgt::setNumBorder(qreal border)
{
    if (border < 0.5 * m_numSize.width() && border < 0.25 * m_numSize.height()) {
        m_numBorder = border;
    }
}

// 设置冒号点宽度
void DigitalWatchWgt::setDotWidth(qreal dotWid)
{
    m_dotWid = dotWid;
    adaptSize();
}

void DigitalWatchWgt::initData()
{
    m_margin = QMargins(12, 8, 12, 8);
    m_numSpacing = 12;
    m_colonSpacing = 12;
    m_border = 0;
    m_borRadius = 12;
    m_lineOffset = 3.0;
    
    m_bkgColor = Qt::transparent;
    m_numLightColor = QColor(255, 255, 255, 20);
    m_numDarkColor = QColor(12, 255, 12, 255);
    m_numSize = QSizeF(32.0, 64.0);
    m_numBorder = 8.0;
    m_dotWid = 8.0;
    
    m_timer = new QTimer(this);
    if (m_isShowSecond) {
        m_timer->setInterval(1000);
    } else {
        m_timer->setInterval(60000);
    }
    
    auto updateNumText = [this] {
        QString currTime = QTime::currentTime().toString("HHmmss");
        if (kNumCount == currTime.length()) {
            for (int i = 0; i < kNumCount; ++i) {
                m_number[i].m_text = currTime.at(i);
            }
        }
    };
    
    connect(m_timer, &QTimer::timeout, this, [=] {
        updateNumText();
        update();
    });
    
    updateNumText();
    m_timer->start();
}

void DigitalWatchWgt::adaptSize()
{
    int wid = m_margin.left() + m_margin.right() + static_cast<int>(2 * m_border);
    int hgt = m_margin.top() + m_margin.bottom() + m_numSize.height();
    hgt += static_cast<int>(2 * m_border);
    
    if (m_isShowSecond) {
        wid += static_cast<int>(kNumCount * m_numSize.width() + 2 * m_dotWid);
        wid += 3 * m_numSpacing + 4 * m_colonSpacing;
    } else {
        wid += static_cast<int>(4 * m_numSize.width() + m_dotWid);
        wid += 2 * m_numSpacing + 2 * m_colonSpacing;
    }
    
    QWidget::setFixedSize(wid, hgt);
    adjustPos();
}

void DigitalWatchWgt::adjustPos()
{
    qreal xPos = m_border + m_margin.left();
    qreal yPos = m_border + m_margin.top();
    
    m_number[0].m_topX = xPos;
    m_number[0].m_topY = yPos;
    
    xPos += m_numSize.width() + m_numSpacing;
    m_number[1].m_topX = xPos;
    m_number[1].m_topY = yPos;
    
    xPos += m_numSize.width() + m_colonSpacing;
    m_rfColon[0] = QRectF(QPointF(xPos, yPos), QSizeF(m_dotWid, m_numSize.height()));
    
    xPos += m_dotWid + m_colonSpacing;
    m_number[2].m_topX = xPos;
    m_number[2].m_topY = yPos;
    
    xPos += m_numSize.width() + m_numSpacing;
    m_number[3].m_topX = xPos;
    m_number[3].m_topY = yPos;
    
    if (m_isShowSecond) {
        xPos += m_numSize.width() + m_colonSpacing;
        m_rfColon[1] = QRectF(xPos, yPos, m_dotWid, m_numSize.height());
        
        xPos += m_dotWid + m_colonSpacing;
        m_number[4].m_topX = xPos;
        m_number[4].m_topY = yPos;
        
        xPos += m_numSize.width() + m_numSpacing;
        m_number[5].m_topX = xPos;
        m_number[5].m_topY = yPos;
    }
}

void DigitalWatchWgt::calcLinePath()
{
    qreal tempWid = 0.5 * m_numBorder;
    QPointF ptf(0, 0);
    QPainterPath path[kLineCount];
    
    ptf.rx() += m_numBorder + m_lineOffset;
    path[0].moveTo(ptf);
    ptf.rx() = m_numSize.width() - m_numBorder - m_lineOffset;
    path[0].lineTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() += tempWid;
    path[0].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() += tempWid;
    path[0].lineTo(ptf);
    ptf.rx() = m_numBorder + m_lineOffset;
    path[0].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() -= tempWid;
    path[0].lineTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() -= tempWid;
    path[0].lineTo(ptf);
    
    ptf.setX(0);
    ptf.setY(m_numBorder + m_lineOffset);
    path[1].moveTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() -= tempWid;
    path[1].lineTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() += tempWid;
    path[1].lineTo(ptf);
    ptf.ry() = 0.5 * (m_numSize.height() - m_numBorder) - m_lineOffset;
    path[1].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() += tempWid;
    path[1].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() -= tempWid;
    path[1].lineTo(ptf);
    ptf.ry() = m_numBorder + m_lineOffset;
    path[1].lineTo(ptf);
    
    ptf.setX(m_numSize.width() - m_numBorder);
    ptf.setY(m_numBorder + m_lineOffset);
    path[2].moveTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() -= tempWid;
    path[2].lineTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() += tempWid;
    path[2].lineTo(ptf);
    ptf.ry() = 0.5 * (m_numSize.height() - m_numBorder) - m_lineOffset;
    path[2].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() += tempWid;
    path[2].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() -= tempWid;
    path[2].lineTo(ptf);
    ptf.ry() = m_numBorder + m_lineOffset;
    path[2].lineTo(ptf);
    
    ptf.setX(m_numBorder + m_lineOffset);
    ptf.setY(0.5 * (m_numSize.height() - m_numBorder));
    path[3].moveTo(ptf);
    ptf.rx() = m_numSize.width() - m_numBorder - m_lineOffset;
    path[3].lineTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() += tempWid;
    path[3].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() += tempWid;
    path[3].lineTo(ptf);
    ptf.rx() = m_numBorder + m_lineOffset;
    path[3].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() -= tempWid;
    path[3].lineTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() -= tempWid;
    path[3].lineTo(ptf);
    
    ptf.setX(0);
    ptf.ry() = 0.5 * (m_numSize.height() + m_numBorder) + m_lineOffset;
    path[4].moveTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() -= tempWid;
    path[4].lineTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() += tempWid;
    path[4].lineTo(ptf);
    ptf.ry() = m_numSize.height() - m_numBorder - m_lineOffset;
    path[4].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() += tempWid;
    path[4].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() -= tempWid;
    path[4].lineTo(ptf);
    ptf.ry() = 0.5 * (m_numSize.height() + m_numBorder) + m_lineOffset;
    path[4].lineTo(ptf);
    
    ptf.setX(m_numSize.width() - m_numBorder);
    ptf.ry() = 0.5 * (m_numSize.height() + m_numBorder) + m_lineOffset;
    path[5].moveTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() -= tempWid;
    path[5].lineTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() += tempWid;
    path[5].lineTo(ptf);
    ptf.ry() = m_numSize.height() - m_numBorder - m_lineOffset;
    path[5].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() += tempWid;
    path[5].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() -= tempWid;
    path[5].lineTo(ptf);
    ptf.ry() = 0.5 * (m_numSize.height() + m_numBorder) + m_lineOffset;
    path[5].lineTo(ptf);
    
    ptf.rx() = m_numBorder + m_lineOffset;
    ptf.ry() = m_numSize.height() - m_numBorder;
    path[6].moveTo(ptf);
    ptf.rx() = m_numSize.width() - m_numBorder - m_lineOffset;
    path[6].lineTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() += tempWid;
    path[6].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() += tempWid;
    path[6].lineTo(ptf);
    ptf.rx() = m_numBorder + m_lineOffset;
    path[6].lineTo(ptf);
    ptf.rx() -= tempWid;
    ptf.ry() -= tempWid;
    path[6].lineTo(ptf);
    ptf.rx() += tempWid;
    ptf.ry() -= tempWid;
    path[6].lineTo(ptf);
    
    for (int i = 0; i < kLineCount; ++i) {
        m_linePath[i] = path[i];
    }
}

void DigitalWatchWgt::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    
    drawBackground(painter);    
    painter.save();
    int numCnt = m_isShowSecond ? kNumCount : 4;
    
    for (int i = 0; i < numCnt; ++i) {
        m_tfDrawing.translate(m_number[i].m_topX, m_number[i].m_topY);
        painter.setTransform(m_tfDrawing);
        drawNumber(painter, m_number[i].m_text);
        
        m_tfDrawing.reset();
    }
    
    painter.restore();    
    drawColon(painter, m_rfColon[0]);
    
    if (m_isShowSecond) {
        drawColon(painter, m_rfColon[1]);
    }
}

void DigitalWatchWgt::drawBackground(QPainter &painter)
{
    QPainterPath path;
    path.addRoundedRect(this->rect(), m_borRadius, m_borRadius);
    
    if (m_border > 0) {
        painter.setPen(QPen(QBrush(m_borColor), m_border));
        painter.setBrush(QBrush(m_bkgColor));
        painter.drawPath(path);
    } else {
        painter.fillPath(path, QBrush(m_bkgColor));
    }
}

void DigitalWatchWgt::drawNumber(QPainter &painter, const QChar &num)
{
    if ('0' == num) {
        bool isDarkClr[kLineCount] = {true, true, true, false, true, true, true};
        fillLinePath(painter, isDarkClr);
        
    } else if ('1' == num) {
        bool isDarkClr[kLineCount] = {false, false, true, false, false, true, false};
        fillLinePath(painter, isDarkClr);
        
    } else if ('2' == num) {
        bool isDarkClr[kLineCount] = {true, false, true, true, true, false, true};
        fillLinePath(painter, isDarkClr);
        
    } else if ('3' == num) {
        bool isDarkClr[kLineCount] = {true, false, true, true, false, true, true};
        fillLinePath(painter, isDarkClr);
        
    } else if ('4' == num) {
        bool isDarkClr[kLineCount] = {false, true, true, true, false, true, false};
        fillLinePath(painter, isDarkClr);
        
    } else if ('5' == num) {
        bool isDarkClr[kLineCount] = {true, true, false, true, false, true, true};
        fillLinePath(painter, isDarkClr);
        
    } else if ('6' == num) {
        bool isDarkClr[kLineCount] = {true, true, false, true, true, true, true};
        fillLinePath(painter, isDarkClr);
        
    } else if ('7' == num) {
        bool isDarkClr[kLineCount] = {true, false, true, false, false, true, false};
        fillLinePath(painter, isDarkClr);
        
    } else if ('8' == num) {
        bool isDarkClr[kLineCount] = {true, true, true, true, true, true, true};
        fillLinePath(painter, isDarkClr);
        
    } else if ('9' == num) {
        bool isDarkClr[kLineCount] = {true, true, true, true, false, true, true};
        fillLinePath(painter, isDarkClr);
    }
}

void DigitalWatchWgt::fillLinePath(QPainter &painter, bool *isDarkColor)
{
    for (int i = 0; i < kLineCount; ++i) {
        painter.fillPath(m_linePath[i], isDarkColor[i] ? m_numDarkColor : m_numLightColor);
    }
}

void DigitalWatchWgt::drawColon(QPainter &painter, const QRectF &rf)
{
    qreal vSpace = (rf.height() - 2 * m_dotWid) / 3;
    QRectF rf1(QPointF(rf.left(), rf.top() + vSpace), QSizeF(m_dotWid, m_dotWid));
    QRectF rf2(QPointF(rf.left(), rf.top() + 2 * vSpace + m_dotWid), QSizeF(m_dotWid, m_dotWid));
    
    painter.fillRect(rf1, m_numDarkColor);
    painter.fillRect(rf2, m_numDarkColor);
}

/*********************************** SNumber ************************************/
DigitalWatchWgt::SNumber::SNumber()
    : SNumber(QChar(0))
{
}

DigitalWatchWgt::SNumber::SNumber(const QChar &text)
    : m_text(text)
    , m_topX(0)
    , m_topY(0)
{
}
相关推荐
ever_up97337 分钟前
EasyExcel的导入与导出及在实际项目生产场景的一下应用例子
java·开发语言·数据库
吴天德少侠1 小时前
c++返回一个pair类型
开发语言·c++
ok!ko2 小时前
设计模式之工厂模式(通俗易懂--代码辅助理解【Java版】)
java·开发语言·设计模式
学地理的小胖砸2 小时前
【GEE的Python API】
大数据·开发语言·前端·python·遥感·地图学·地理信息科学
qq_317060953 小时前
java之http client工具类
java·开发语言·http
robot_大菜鸟3 小时前
python_openCV_计算图片中的区域的黑色比例
开发语言·python·opencv
Pandaconda4 小时前
【C++ 面试 - 新特性】每日 3 题(六)
开发语言·c++·经验分享·笔记·后端·面试·职场和发展
chanTwo_004 小时前
go--知识点
开发语言·后端·golang
悟空丶1234 小时前
go基础知识归纳总结
开发语言·后端·golang
北南京海4 小时前
【C++入门(5)】类和对象(初始类、默认成员函数)
开发语言·数据结构·c++