当前位置: 首页 > 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…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...