Qt:自定义钟表组件

news2024/12/25 1:57:56

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

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

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

主要代码如下:

ClockWgt.h

#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

#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

#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

#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)
{
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1983673.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

spring源码阅读-推断构造方法

如何构造一个对象&#xff1f; 1、默认情况下&#xff0c;或者只有一个构造方法的情况下&#xff0c;就会使用默认构造方法或者唯一的一个构造方法 2、由程序员指定构造方法入参值&#xff0c;通过getBean()的方式获取&#xff0c;可以指定参数类型以及个数&#xff0c;但是该…

【康复学习--LeetCode每日一题】572. 另一棵树的子树

题目&#xff1a; 给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree …

SpringBoot3里的文件上传

需求分析&#xff1a; 在用户更换头像或者添加文章时&#xff0c;都需要携带一个图片的URL访问地址。当用户访问文件上传接口将图片的数据上传成功后&#xff0c;服务器会返回一个地址。我们后台需要提供一个文件上传的接口&#xff0c;用来接收前端提交的文件的数据并且返回文…

C++入门基础(完整版)含下卷

C入门基础 hello 各位未来的程序员大佬们&#xff0c;这一篇是详细介绍入门基础&#xff0c;和上一篇不同的是这一篇补完了引用的知识和inline&#xff0c;nullptr的知识&#xff0c;希望大家有所收获 namespace的价值 在C/C中&#xff0c;变量、函数和后⾯要学到的类都是⼤…

【w门大学】云计算与大数据零基础特训班视频教程合辑

提取地址 云计算与大数据零基础特训班 课程目录

“数据要素×”大赛江西分赛官网正式上线 共设置12个赛道

7月17日&#xff0c;2024年“数据要素”大赛江西分赛在南昌市拉开帷幕。作为全国“数据要素”大赛的地方分赛&#xff0c;江西分赛由国家数据局、江西省人民政府指导&#xff0c;江西省发展改革委&#xff08;省数据局&#xff09;联合18家省级单位共同主办&#xff0c;江西分赛…

CCRC-DSA数据安全评估师:ISC.AI2024数字安全峰会:安全大模型引领安全行业革命

7月31日&#xff0c;以“构建先进的安全模型&#xff0c;引领安全产业变革”为主题&#xff0c;ISC.AI 2024数字安全峰会在北京国家会议中心成功举办。 本次峰会旨在鼓励行业通过大规模模型重构安全框架&#xff0c;确保数字经济的稳健前进。 会上&#xff0c;众多院士级专家…

【pytorch】全连接网络简单二次函数拟合

下面是一个使用PyTorch实现全连接网络来拟合简单二次函数 y x 2 y x^2 yx2 的示例。我们将创建一个简单的神经网络&#xff0c;定义损失函数和优化器&#xff0c;并进行训练。 下面是完整的代码示例&#xff1a; import torch import torch.nn as nn import torch.optim …

Linux笔记(1)

在敲出 文件 &#xff0f; 目录 &#xff0f; 命令 的前几个字母之后&#xff0c;按下 tab 键 如果输入的没有歧义&#xff0c;系统会自动补全 如果还存在其他 文件 &#xff0f; 目录 &#xff0f; 命令 &#xff0c;再按一下 tab 键&#xff0c;系统会提示可能存在的命令 小…

【算法速刷(5/100)】LeetCode —— 20.有效的括号

题目要求比较明晰简洁&#xff0c;编码难度并不算高 下面贴出代码和思路 bool isValid(string s) {stack<char> stk;for(const char& c : s){if(stk.empty()){stk.push(c);continue;}if(c ( || c [ || c {){stk.push(c);continue;}else{char top stk.top();boo…

Java Lambda表达式总结(快速上手图解)

Java Lambda表达式总结&#xff08;快速上手详解&#xff09;-CSDN博客https://blog.csdn.net/m0_66070037/article/details/140912566?spm1001.2014.3001.5501

idea 设置自动移除多余 的import (或整个项目删除)

1、开发的时候&#xff0c;直接自动去除多余的引入 2、如果想把整个项目的移除可以如下操作

Linux 异常 sh: /usr/bin/xauth: not found

异常原因&#xff1a; 远程连接时出现错误&#xff0c;由于 Omega 上没有 X 环境&#xff0c;因此在尝试交换凭据以设置转发时会失败 解决办法&#xff1a; 进入高级 SHH 设置&#xff0c;并勾选了 X11 转发。取消勾选该框。

Studying-代码随想录训练营day59| dijkstra(堆优化版)精讲、Bellman_ford 算法精讲

第59天&#xff0c;dijkstra算法的优化版本&#xff0c;以及Bellman_ford 算法&#x1f4aa;&#x1f4aa;(ง •_•)ง&#xff0c;编程语言&#xff1a;C 目录 dijkstra&#xff08;堆优化版&#xff09;精讲 思路 图的存储 邻接矩阵 邻接表 本题图的存储 堆优化细节…

x86 8086 CPU 寄存器详解

8086 寄存器及其地址详细介绍 8086 微处理器是 Intel 在 1978 年推出的一款 16 位微处理器&#xff0c;它在计算机体系结构的发展中占有重要地位。8086 处理器拥有 14 个 16 位寄存器&#xff0c;这些寄存器被分为几类&#xff1a;通用寄存器、段寄存器、指令指针寄存器和标志…

力扣第五十四题——螺旋矩阵

内容介绍 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5]示例 2&#xff1a; 输入&#xff1a;matrix …

【好用的个人工具】部署Dokcer容器速查表工具

【好用的个人工具】部署Dokcer容器速查表工具 一、getting-started介绍1.1 getting-started简介1.2 getting-started内容 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载ge…

文心智能体平台:食尚小助,提供美食推荐和烹饪指导

文章目录 前言文心智能体平台介绍创建自己的智能体我的文心智能体体验地址总结 前言 在快节奏的现代生活中&#xff0c;许多人都希望能够享受美味的食物&#xff0c;但往往缺乏时间和精力来自己动手烹饪。为了解决这一问题&#xff0c;文心智能体平台推出了“食尚小助”智能体…

计算机网络基础之网络套接字socket编程(初步认识UDP、TCP协议)

绪论​ “宿命论是那些缺乏意志力的弱者的借口。 ——罗曼&#xff0e;罗兰”&#xff0c;本章是为应用层打基础&#xff0c;因为在写应用层时将直接通过文本和代码的形式来更加可视化的理解网络&#xff0c;本章主要写的是如何使用网络套接字和udp、tcp初步认识。 话不多说安…

“论负载均衡技术在Web系统中的应用”写作框架软考高级论文系统架构设计师论文

论文真题 负载均衡技术是提升Web系统性能的重要方法。利用负载均衡技术&#xff0c; 可将负载(工作任务) 进行平衡、分摊到多个操作单元上执行&#xff0c; 从而协同完成工作任务&#xff0c; 达到提升Web系统性能的目的。 请围绕“负载均衡技术在Web系统中的应用”论题&…