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

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...