当前位置: 首页 > news >正文

Qt:自定义钟表组件

使用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)
{
}

相关文章:

Qt:自定义钟表组件

使用QWidget绘制两种钟表组件&#xff0c;效果如下&#xff1a; 源码下载链接&#xff1a;GitHub - DengYong1988/Clock-Widget: Qt 自定义钟表组件 https://download.csdn.net/download/ouyangxiaozi/89616407 主要代码如下&#xff1a; ClockWgt.h #ifndef CLOCKWGT_H #d…...

前端性能优化-web资源加载优先级

前言 资源加载优先级是指在页面渲染的过程中&#xff0c;浏览器决定加载哪些资源并优先加载它们的一种机制。正确配置资源加载的优先级可以显著改善页面加载性能&#xff0c;确保关键资源优先加载&#xff0c;提高用户感知的加载速度。 Web 资源加载方式 同步加载 同步加载…...

Docker-数据卷指令

数据卷挂载修改内容...

Elasticsearch VS Typesense! Elasticsearch未来会被其它搜索引擎取代吗?

近期网上流行一批新的搜索引擎&#xff0c;动不动就大言不惭&#xff0c;要跟龙头老大Elasticsearch比&#xff0c;想把Elasticsearch击败。 1. Typesense 太猖狂了&#xff0c;对Elasticsearch极为不敬 如近期炒作很猖狂的Typesense开源搜索引擎&#xff0c;一出来就急着挑战…...

usb摄像头 按钮 静止按钮

usb摄像头 按钮 静止按钮 来分析一个UVC的摄像头的枚举信息 UVC学习&#xff1a;UVC中断端点介绍 https://www.eet-china.com/mp/a269529.html 输入命令lsusb -d 0c45:62f1 -v https://www.miaokee.com/705548.html >Video Class-Specific VS Video Input Header Descrip…...

SAP MM学习笔记 - 豆知识03 - 安全在库和最小安全在库,扩张物料的保管场所的几种方法,定义生产订单的默认入库保管场所,受注票中设定禁止贩卖某个物料

上一章讲了一些MM模块的豆知识。 - MR21 修改物料原价 - MM02 修改基本数量单位/评价Class - MMAM 修改物料类型/评价Class SAP MM学习笔记 - 豆知识02 - MR21 修改物料原价&#xff0c;MM02 修改基本数量单位/评价Class&#xff0c;MMAM 修改物料类型/评价Class-CSDN博客 …...

激光导航AGV叉车那么多,究竟该怎么选?一篇文章讲明白~

AGV叉车 随着经济的快速发展&#xff0c;大部分企业的物料搬运开始脱离人工劳作&#xff0c;取而代之的是以叉车为主的机械化搬运。AGV叉车是工业搬运车辆&#xff0c;是指对成件托盘货物进行装卸、堆垛和短距离运输作业的各种轮式搬运车辆&#xff0c;主要应用于货场、工厂车间…...

redis面试(七)初识lua加锁脚本

redisson redisson如何来进行redis分布式锁实现的源码&#xff0c;基于redis实现各种各样的分布式锁的原理 https://redisson.org/ 这是官网 https://github.com/redisson/redisson/wiki/Table-of-Content 这是官方文档 开始 demo 建一个普通的工程在pom.xml里引入依赖 <…...

企元数智百年营销史的精粹:借鉴历史创造未来商机

随着时代的发展和科技的进步&#xff0c;传统营销方式正在经历前所未有的颠覆和改变。在这个数字化时代&#xff0c;企业需要不断创新&#xff0c;同时借鉴百年营销史的精粹&#xff0c;汲取历史经验&#xff0c;创造未来商机。而"企元数智"作为现代营销的代表&#…...

Java @SpringBootTest注解用法

SpringBootTest 是 Spring Framework 中的一个注解&#xff0c;用于指示 Spring Boot 应用程序的测试类。当你在测试类上使用 SpringBootTest 注解时&#xff0c;Spring Boot 会启动一个 Spring 应用程序上下文&#xff0c;并且加载应用程序的 application.properties 或 appli…...

构建智能招聘平台:人才招聘系统源码开发指南

本篇文章&#xff0c;小编将详细探讨如何基于人才招聘系统源码开发一个智能招聘平台&#xff0c;为企业的人才战略提供支持。 一、智能招聘平台的核心功能 智能招聘平台的核心在于提高招聘效率和匹配度&#xff0c;这需要集成多个关键功能模块&#xff1a; 1.职位发布与管理…...

Docker + Nacos + Spring Cloud Gateway 实现简单的动态路由配置修改和动态路由发现

1.环境准备 1.1 拉取Nacos Docker镜像 从Docker Hub拉取Nacos镜像&#xff1a; docker pull nacos/nacos-server:v2.4.01.2 生成密钥 你可以使用命令行工具生成一个不少于32位的密钥。以下是使用 OpenSSL 生成 32 字节密钥的示例&#xff1a; openssl rand -base64 321.3 …...

Linux中多线程压缩软件 | Mingz

原文链接&#xff1a;Linux中多线程压缩软件 本期教程 软件网址&#xff1a; https://github.com/hewm2008/MingZ安装&#xff1a; git clone https://github.com/hewm2008/MingZ.git cd MingZ make cd bin ./mingz -h使用源码安装&#xff1a; 若是你的git无法使用安装&am…...

【JavaEE精炼宝库】网络原理基础——UDP详解

文章目录 一、应用层二、传输层2.1 端口号&#xff1a;2.2 UDP 协议&#xff1a;2.2.1 UDP 协议端格式&#xff1a;2.2.2 UDP 存在的问题&#xff1a; 2.3 UDP 特点&#xff1a;2.4 基于 UDP 的应用层协议&#xff1a; 一、应用层 我们 Java 程序员在日常开发中&#xff0c;最…...

【回眸】周中WLB-个人

生活 计划 苏州or杭州or舟山 负负得正 烟火 鲜芋仙 办上海银行的银行卡 申请表材料准备好 个人博客提现签约变现 个人提升 yas补直播笔记&#xff08;听、口&#xff09;1~3课 *2倍 dy学堂 —— 3课时输出博客 个人笔记本搭建环境 副业探索 收集信息差 目前已…...

基于Spring boot + Vue的灾难救援系统

作者的B站地址&#xff1a;程序员云翼的个人空间-程序员云翼个人主页-哔哩哔哩视频 csdn地址&#xff1a;程序员云翼-CSDN博客 1.项目技术栈&#xff1a; 前后端分离的项目 后端&#xff1a;Springboot MybatisPlus 前端&#xff1a;Vue ElementUI 数据库&#xff1a; …...

C#进阶:轻量级ORM框架Dapper详解

C#进阶&#xff1a;轻量级ORM框架Dapper详解 在C#开发中&#xff0c;ORM&#xff08;对象关系映射&#xff09;框架是处理数据库交互的重要工具。Dapper作为一个轻量级的ORM框架&#xff0c;专为.NET平台设计&#xff0c;因其高性能和易用性而备受开发者青睐。本文将详细介绍D…...

【python015】常见成熟AI-图像识别场景算法清单(已更新)

1.欢迎点赞、关注、批评、指正&#xff0c;互三走起来&#xff0c;小手动起来&#xff01; 【python015】常见成熟AI-图像识别场景算法清单及代码【python015】常见成熟AI-图像识别场景算法清单及代码【python015】常见成熟AI-图像识别场景算法清单及代码 文章目录 1.背景介绍2…...

删除有序数组中的重复项(LeetCode)

题目 给你一个 升序排列 的数组 &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 中唯一元素的个数。 考虑 的唯一元素的数量为 &#xff0c;你需要做以下事情确…...

【算法 03】雇佣问题

“雇用问题”及其算法优化 在日常生活和工作中&#xff0c;我们经常会遇到需要从多个选项中做出选择的情况&#xff0c;而“雇用问题”正是这样一个典型的例子。在这个问题中&#xff0c;我们不仅要考虑如何高效地找到最佳候选人&#xff0c;还要关注整个过程中的成本。今天&a…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

Qt的学习(二)

1. 创建Hello Word 两种方式&#xff0c;实现helloworld&#xff1a; 1.通过图形化的方式&#xff0c;在界面上创建出一个控件&#xff0c;显示helloworld 2.通过纯代码的方式&#xff0c;通过编写代码&#xff0c;在界面上创建控件&#xff0c; 显示hello world&#xff1b; …...