一、Qt版本:

Qt Creator 4.4.1 Based on Qt 5.9.3 (MSVC 2015, 32 bit)

二、效果图:

  

三、功能简介:

1)鼠标滚轮放大缩小

2)时钟走动音效

3)右键菜单

4)托盘菜单

四、上代码:

1) 头文件 clock.h

#ifndef CLOCK_H
#define CLOCK_H#include <QWidget>#include <QPaintEvent>
#include <QPainter>
#include <QPen>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QMenu>
#include <QSoundEffect>
#include <QToolTip>
#include <QSystemTrayIcon>class Clock : public QWidget
{Q_OBJECTpublic:Clock(QWidget *parent = 0);~Clock();private slots:void slot_showMaxiNormal();void slot_EffectControl();private:static const QPoint hourHand[4];static const QPoint minuteHand[4];static const QPoint secondHand[4];QPen mHourHandPen;QPen mMinuteHandPen;QPen mSecondHandPen;QPoint mPos;// 右键菜单QMenu *m_pRBMenu;QAction *m_pCloseAct;QAction *m_pMaxiMinimizeAct;// 音效控制菜单QMenu *m_pSDMenu;QAction *m_pSoundOffAct;QAction *m_pSoundOnAct;QSoundEffect *m_pEffect;QStringList m_fontList;QSystemTrayIcon *systemTray;protected:void paintEvent(QPaintEvent *event);void drawHourHand(QPainter *painter);void drawMinuteHand(QPainter *painter);void drawSecondHand(QPainter *painter);void drawLcdNumber(QPainter *painter);void drawClockDial(QPainter *painter);void mousePressEvent(QMouseEvent *event);void mouseMoveEvent(QMouseEvent *event);void wheelEvent(QWheelEvent *event);void createMenu();void createTray();void contextMenuEvent(QContextMenuEvent *event);};#endif // CLOCK_H

2) 核心代码 clock.cpp

#include "clock.h"#include <QTimer>
#include <QIcon>
#include <QTime>
#include <QFont>
#include <QCoreApplication>
#include <QFontDatabase>const QPoint Clock::hourHand[4] = {QPoint(3, 5),QPoint(0, 13),QPoint(-3, 5),QPoint(0, -40)
}; // 时针绘图区域
const QPoint Clock::minuteHand[4] = {QPoint(3, 5),QPoint(0, 16),QPoint(-3, 5),QPoint(0, -68)
}; // 分针绘图区域
const QPoint Clock::secondHand[4] = {QPoint(3, 5),QPoint(0, 18),QPoint(-3, 5),QPoint(0, -85)
}; // 秒针绘图区域Clock::Clock(QWidget *parent): QWidget(parent)
{this->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint); // 去掉标题栏,去掉任务栏显示,窗口置顶this->setWindowIcon( QIcon(":/ico/clock.ico") );this->setWindowTitle( tr("桌面时钟") );this->resize(200, 200);this->setAttribute(Qt::WA_TranslucentBackground, true); // 窗口透明,去掉标题栏后方生效
//    this->setWindowOpacity(0.7); // 窗口透明度设置,其控件或绘图也透明,且达不到圆形窗口的效果/* 加载外部字体文件 */m_fontList.clear();int lcdFontId = QFontDatabase::addApplicationFont(":/lcd/DS-DIGI.ttf"); // 从source资源文件if (lcdFontId != -1){m_fontList << QFontDatabase::applicationFontFamilies(lcdFontId);}/* 画笔设置 */mHourHandPen = QPen(palette().foreground(), 2.0);mMinuteHandPen = QPen(palette().foreground(), 1.0);QTimer *pTimer = new QTimer(this);pTimer->start(1000);connect( pTimer, SIGNAL(timeout()), this, SLOT(update()) );/* 音效控制 */
//    QString dir = QCoreApplication::applicationDirPath();
//    QString filename(dir + "/sounds/clockMoveSound.wav");m_pEffect = new QSoundEffect(this);m_pEffect->setLoopCount(QSoundEffect::Infinite); // 循环播放
//    m_pEffect->setSource( QUrl::fromLocalFile(filename) );m_pEffect->setSource( QUrl::fromLocalFile(":/sound/clockMoveSound.wav") );m_pEffect->setVolume(1.0); // 音量控制:0.0-1.0
//    m_pEffect->play(); // 播放
//    m_pEffect->stop(); // 停止/* 创建右键菜单 */createMenu();/* 创建系统托盘项 */createTray();
}Clock::~Clock()
{delete m_pRBMenu;delete m_pCloseAct;delete m_pMaxiMinimizeAct;delete m_pSoundOnAct;delete m_pSoundOffAct;delete m_pEffect;
}/* 重写绘图事件 */
void Clock::paintEvent(QPaintEvent *e)
{QPainter painter(this);QFont font("Microsoft Yahei", 10, 75); // 字体,大小,加粗等同于QFont::Boldpainter.setFont(font);painter.setRenderHint(QPainter::Antialiasing, true); //反锯齿
//    painter.setWindow(0, 0, 200, 200);int side = qMin(this->width(), this->height());/* 圆形背景的绘制 */painter.setPen(Qt::NoPen); // 去掉外圈线painter.setBrush(QColor(255, 255, 255, 125));              // 背景颜色以及透明度painter.drawEllipse( QPoint(width()/2, height()/2), side/2, side/2 ); // 绘制背景painter.setPen(QPen( QColor(233, 233, 216 ), 4 )); // 外边框颜色以及大小painter.drawEllipse(QPoint(width()/2, height()/2), side/2 - 3, side/2 - 3); //外边框绘制painter.translate(width() / 2, height() / 2); // 设置坐标原点painter.scale(side / 200.0, side / 200.0); // 缩放比例/* 时针、分针、秒针、表盘、Lcd */drawHourHand(&painter);drawMinuteHand(&painter);drawSecondHand(&painter);drawClockDial(&painter);drawLcdNumber(&painter);/* 中心点 */painter.setBrush(Qt::black);painter.drawEllipse(QPoint(0, 0), 2, 2);
}void Clock::drawHourHand(QPainter *painter)
{QTime time = QTime::currentTime();painter->setBrush(Qt::black);painter->setPen(Qt::black);painter->save();painter->rotate( 30.0 * (time.hour() + time.minute()/60.0) ); //坐标轴旋转painter->drawConvexPolygon(hourHand, 4); // 绘制凸多边形,由n个点控制,此处由4个点控制painter->restore(); //复位坐标
}void Clock::drawMinuteHand(QPainter *painter)
{QTime time = QTime::currentTime();painter->setBrush(Qt::blue);painter->setPen(Qt::blue);painter->save();painter->rotate( 6.0 * (time.minute() + time.second()/60.0) );painter->drawConvexPolygon(minuteHand, 4);painter->restore(); //复位坐标
}void Clock::drawSecondHand(QPainter *painter)
{QTime time = QTime::currentTime();painter->setBrush(Qt::red);painter->setPen(Qt::red);painter->save();painter->rotate( 6.0 * time.second() );painter->drawConvexPolygon(secondHand, 4);painter->restore();
}/* Lcd */
void Clock::drawLcdNumber(QPainter *painter)
{if (!m_fontList.isEmpty()){QFont font;font.setFamily(m_fontList.at(0));font.setPointSize(15);// font.setStretch(side / 200.0);painter->setFont(font);}painter->setPen( QColor(0, 0, 0) );painter->drawText( -40, 34, 80, 22, Qt::AlignCenter,QTime::currentTime().toString("hh:mm:ss") );//    painter->setBrush(Qt::NoBrush);
//    painter->drawRect(-40, 34, 80, 22);
//     坐标系统:向右为X轴正方向,向下为Y轴正方向
}// 表盘和数字
void Clock::drawClockDial(QPainter *painter)
{for (int i = 1; i <= 60; i++){painter->save();painter->rotate(6*i); // 坐标轴旋转6*i度if ( (i % 5 == 0) && (i <= 15 || i >= 45) ) // 小时刻度和数字{painter->setPen(mHourHandPen);painter->drawLine(0, -95, 0, -80);painter->drawText(-20, -82, 40, 40,Qt::AlignHCenter | Qt::AlignTop,QString::number(i/5) );if (i < 15 || i > 45) // 解决下半部分数字倒转问题{painter->drawLine(0, 80, 0, 95);painter->drawText( -20, 41, 40, 40,Qt::AlignHCenter | Qt::AlignBottom,QString::number(i<15 ? i/5+6 : i/5-6) );}}//ifelse // 分钟刻度{painter->setPen(mMinuteHandPen);painter->drawLine(0, 95, 0, 90);}painter->restore();}//for
}/* 实现窗口拖动 */
void Clock::mousePressEvent(QMouseEvent *event)
{mPos = (event->globalPos()) - (this->pos()); //按下点 - 未按下时的点
}
void Clock::mouseMoveEvent(QMouseEvent *event)
{if (this->isFullScreen() == false){this->move(event->globalPos() - mPos );}
}/* 重写滚轮事件,实现放大缩小 */
void Clock::wheelEvent(QWheelEvent *event)
{QRect tmp = this->geometry();QPoint centerPoint = tmp.center(); // 储存中心点坐标static int adjustSize = 20;if (event->delta() > 0) // 放大{tmp.setWidth(tmp.width() + adjustSize);tmp.setHeight(tmp.height() + adjustSize);}else // 缩小{tmp.setWidth(tmp.width() - adjustSize);tmp.setHeight(tmp.height() - adjustSize);}if (tmp.width() > 20) // 限制最小尺寸{tmp.moveCenter(centerPoint); // 从中心缩放而非左上角处this->setGeometry(tmp);// 设置toolTipdouble percent = (double)tmp.width() / 200.0;QString percentStr = QString::number(percent*100) + "%";QToolTip::showText(QCursor::pos(), percentStr, this, QRect(), 500);}
}/* 创建右键菜单 */
void Clock::createMenu()
{m_pRBMenu = new QMenu(this);m_pCloseAct = new QAction(this);m_pCloseAct->setIcon( QIcon(":/ico/closeBt.ico") );m_pCloseAct->setText( tr("关闭") );m_pMaxiMinimizeAct = new QAction(this);m_pMaxiMinimizeAct->setText( tr("全屏") );m_pMaxiMinimizeAct->setIcon( QIcon(":/ico/fullscreen.ico") );m_pRBMenu->addAction(m_pCloseAct);m_pRBMenu->addSeparator();m_pRBMenu->addAction(m_pMaxiMinimizeAct);connect (m_pCloseAct, SIGNAL(triggered(bool)), qApp, SLOT(quit()) );connect( m_pMaxiMinimizeAct, SIGNAL(triggered(bool)),this, SLOT( slot_showMaxiNormal() ) );/* 二级菜单 */m_pRBMenu->addSeparator();m_pSDMenu = m_pRBMenu->addMenu( QIcon(":/ico/sound.ico"), tr("音效控制") );m_pSoundOnAct = new QAction(this);m_pSoundOnAct->setText( tr("音效开") );m_pSoundOnAct->setIcon( QIcon(":/ico/nocheck.ico") );m_pSoundOffAct = new QAction(this);m_pSoundOffAct->setText( tr("音效关") );m_pSoundOffAct->setIcon( QIcon(":/ico/check.ico") );m_pSDMenu->addAction(m_pSoundOnAct);m_pSDMenu->addAction(m_pSoundOffAct);connect (m_pSoundOnAct, SIGNAL(triggered(bool)),this, SLOT( slot_EffectControl() ) );connect( m_pSoundOffAct, SIGNAL(triggered(bool)),this, SLOT( slot_EffectControl() ) );
}/* 重写右键菜单响应事件 */
void Clock::contextMenuEvent(QContextMenuEvent *event)
{m_pRBMenu->exec(QCursor::pos()); // 在光标处弹出右键菜单event->accept();
}/* 创建系统托盘 */
void Clock::createTray()
{/* 托盘图标 */systemTray = new QSystemTrayIcon(this);systemTray->setToolTip( tr("桌面时钟") );systemTray->setIcon(QIcon(":/ico/clock.ico"));systemTray->show();/* 托盘菜单 */systemTray->setContextMenu(m_pRBMenu); // 与右键菜单类似,QMenu类/* 托盘消息 */
//    systemTray->showMessage(tr("TiTle"), tr("msg"), QIcon("://msgIco.ico"), 1000); // 标题,消息内容,消息图标,持续时间
}/* 右键菜单槽函数 */
void Clock::slot_showMaxiNormal()
{if (this->isFullScreen()){this->showNormal();m_pMaxiMinimizeAct->setText( tr("全屏") );m_pMaxiMinimizeAct->setIcon( QIcon(":/ico/fullscreen.ico") );return;}else{this->showFullScreen();m_pMaxiMinimizeAct->setText( tr("还原") );m_pMaxiMinimizeAct->setIcon( QIcon(":/ico/exitfullscreen.ico") );return;}
}/* 音效控制槽函数 */
void Clock::slot_EffectControl()
{if ( m_pEffect->isPlaying() ){m_pEffect->stop();m_pSoundOffAct->setIcon( QIcon(":/ico/check.ico") );m_pSoundOnAct->setIcon( QIcon(":/ico/nocheck.ico") );return;}else{m_pSoundOnAct->setIcon( QIcon(":/ico/check.ico") );m_pSoundOffAct->setIcon( QIcon(":/ico/nocheck.ico") );QTime now;do{now = QTime::currentTime();}while(now.msec() >= 50 && now.msec() <= 950); // 音效对时m_pEffect->play();return;}
}

五 相关说明

3.1  Qt5 2D绘图简介

Qt5中QPainter类提供的API在GUI或QImage、QOpenGLPaintDevice、QWidget和QPaintDevice显示图形(线、形状、渐变等)、文本和图像。

QPaintDevice不直接绘制物理显示画面,而利用逻辑界面的中间媒介。例如,绘制矩形图形时,为了将对象绘制到QWidget、QGLPixelBuffer、QImage、QPixmap、QPicture等多种界面中间,必须使用QPaintDevice。

QPainter为了在GUI上显示图形,利用光栅化(rasterizer)显示图形,并可以使用OpenGL和OpenGL ES的Back-end系统。基于软件的光栅化通过点显示到屏幕,而OPenGL和OpenGL ES方式则通过点表现图形[2]

Qt5绘图系统中由QPainter完成具体的绘制操作,其中,提供了大量高度优化的函数来完成GUI编程所需要的大部分绘制工作。QPainter可以绘制一切想要的图形,从最简单的一条直线到其他任何复杂的图形。QPainter可以在继承自QPaintDevice类的任何对象上进行绘制操作[3]

表3.1  使用QPainter的绘制方式

类 型

说 明

QImage

通过与硬件无关的绘制方式,直接访问像素以显示图形。QPainter利用QImage显示图形时,QImage实例使用基于软件的光栅化方式

QPixmap

在屏幕上显示图像时,提供优化。使用基于软件的光栅化方式显示图像

QOpenGLPaintDevice

使用OpenGL和OpenGL ES等基于硬件的加速器显示图形

QBackingStore

QWindow类,QBackingStore用于在顶层窗口的制图区域显示图形。QBackingStore不仅可以使用基于软件的光栅化方式,还可以使用基于OpenGL的硬件加速器

QWidget

QWidget类在控件区域显示图形

表3.2  QPainter类基本操作

操作内容

说 明

QPainter的基本绘图

可以绘制基本图形(点、线等)的QPen和填充图形内部颜色的QBrush

渐变(Gradients)

使用QBrush显示指定斜率方向的渐变图

转换(Transformation)

扩大和缩小(Scaling)、旋转(Rotation)、远近(Perspective)

组合(Composition)

提供组合各图层的功能图

3.2  时钟实现的原理

时钟的时针、分针、秒针位置每秒都在更新,故我们需要一个定时器来定时重绘。Qt5中提供了很方便的QTimer类,Qtimer类中有一非常重要的信号:timeout(),Qt5帮助手册是这样描述这一信号的:

[signal] void QTimer::timeout()

This signal is emitted when the timer times out.

Note: This is a private signal. It can be used in signal connections but cannot be emitted by the user.

可知,当设定时间结束后,timer就会立即发出timeout信号。连接信号与槽后,即可立刻响应槽函数,Qt5重绘有一重要的API:update(),将其设置为响应的槽函数。

1  timer = new QTimer(this);

2  connect( timer, SIGNAL(timeout()), this, SLOT(update()) );

3  timer->start(1000);

第1行代码为定时器timer申请空间,类型指定为QTimer类。第2行代码连接timeout()信号与update()槽函数。第3行代码以1000毫秒间隔启动定时器。

图3.1描述了时钟实现的原理。

图3.1  时钟走时流程图

3.3  绘制背景与外边框

(一)绘制时钟窗口背景图

Qt提供了4个类来处理图像数据:QImage、QPixmap、QBitmap和QPicture,都是常用的绘图设备。其中,QImage主要用来进行I/O处理,它对I/O处理操作进行了优化,而且也可以用来直接访问和操作像素;QPixmap主要用来在屏幕上显示图像,它对屏幕上显示图像进行了优化;QBitmap是QPixmap的子类,用来处理颜色深度为1的图像,即只能显示黑白两种颜色;QPicture用来记录并重演QPainter命令。

这里需要的是在屏幕上显示背景图像,故我们选择QPixmap类来绘制时钟窗口背景图像。QPixmap中的像素在内部底层的窗口系统进行管理,因为QPixmap是QPaintDevice的子类,所以QPainter也可以直接在它上面进行绘制[3]

首先,新建一个QPixmap类对象,图片资源由资源文件加载。再使用QPixmap类的“scaled()”方法将图像大小缩放至屏幕大小,得到一个缩放后的QPixmap类对象。

1  QPixmap *tmp = new QPixmap(":/clockUI/clockUI.jpg");

2  pixmap = tmp->scaled(this->width(),

3                     this->height(),

4                     Qt::IgnoreAspectRatio);

然后,通过重写QWidget的“void paintevent(QPaintevent *event);”函数,调用QPainter类的“drawPixmap()”函数进行图像的绘制。

1  void Clock::paintEvent(QPaintEvent *e)

2  {

3    QPainter painter(this);

4    painter.drawPixmap(pixmap.rect(), pixmap);

5  }

(二) 绘制时钟表盘背景及外边框

时钟表盘背景为圆形带填充,外边框为圆形不填充。Qt对于绘制圆和椭圆的API是基于QPainter类的“drawEllipse()”方法,填充与否在于QPainter是否设置了笔刷(QBrush)。由于外边框应在表盘背景上层显示,故先绘制表盘背景,再绘制外边框。

1、绘制表盘背景:

1  int side = qMin(this->width(), this->height());

2  painter.save();

3  painter.setPen(Qt::NoPen);

4  painter.setBrush(QColor(112, 128, 144, 100));

5  painter.drawEllipse( QPoint(width()/2, height()/2), side/2, side/2 );

6  painter.restore();

2、绘制外边框:

1  painter.save();

2  painter.setPen(QPen( QColor(244, 164, 96, 130), 4 ));

3  painter.drawEllipse(QPoint(width()/2, height()/2), side/2 - 3, side/2 - 3);

4  painter.restore();

3.4  绘制时针、分针、秒针

3.4.1  QPainter对坐标系统的操作

Qt对于窗口坐标的设定是:左上角处为坐标原点(0,0),左为X轴正方向,下为Y轴正方向。

(1)对于坐标轴原点移动,Qt的QPainter类提供了“translate()”方法,Qt帮助手册对于此函数的描述为:

void QPainter::translate(const QPointF &offset)

Translates the coordinate system by the given offset; i.e. the given offset is added to points.

那么,给QPainter类的“translate()”函数传入中心点坐标,即可移动坐标轴。

(2)对于坐标轴旋转,QPainter类提供了“rotate()”方法,Qt5帮助手册描述为:

void QPainter::rotate(qreal angle)

Rotates the coordinate system clockwise. The given angle parameter is in degrees.

数据类型qreal是double类型数据的重命名,所以将旋转角度转换为double类型,传入参数,即可将坐标轴旋转。Qt中坐标轴旋转默认是顺时针旋转。

(3)对于坐标轴缩放,QPainter类提供了“scaled()”方法,Qt5帮助手册描述为:

void QPainter::scale(qreal sx, qreal sy)

Scales the coordinate system by (sx, sy).

第一个参数代表X轴缩放比例,第二个参数代表Y轴缩放比例,都为qreal类型。

3.4.2  指针图形坐标设定与角度计算

(一)时针、分针、秒针图形的坐标设定

设定200x200像素为时钟基础长宽,将坐标原点移动至屏幕中央,时针图案、分针图案、秒针图案各由四个点组成,由QPoint数组表示。后面每秒都要重绘,而图案形状不改变,故将数组设定为static const类型,将之存储到寄存器中,提高访问速度[4]

(1)时针图案坐标点:

1  const QPoint Clock::hourHand[4] = {

2    QPoint(3, 5),

3    QPoint(0, 13),

4    QPoint(-3, 5),

5    QPoint(0, -40) };

图案效果如图3.2(a)所示。

(2)分针图案坐标点:

1  const QPoint Clock::minuteHand[4] = {

2    QPoint(3, 5),

3    QPoint(0, 16),

4    QPoint(-3, 5),

5    QPoint(0, -60) };

图案效果如图3.2(b)所示。

(3)秒针图案坐标点:

1  const QPoint Clock::secondHand[4] = {

2    QPoint(3, 5),

3    QPoint(0, 18),

4    QPoint(-3, 5),

5    QPoint(0, -80) };

图案效果如图3.2(c)所示。

3.2(a)

3.2(b)

3.2(c)

(二)时针、分针、秒针旋转角度计算

图3.3是一个典型的时钟钟面图,如图3.3所示,指针刻度将圆周分割成60份,相邻刻度线所形成的夹角为6°。时针1小时走过的角度为30°;分针1分钟所走过的角度为60°;秒针同分针。三者的等量关系可以用如下式子来表示:

1h = 60min = 3600sec                          (3.1)

图3.3  时钟钟面

因12小时是指针行走的最大周期,故考虑这一范围内的情形。若某一瞬时时间记为a:b:c(例如:01:18:36),其中a、b、c为整数且,,。显然不能单考虑a的值作为计算时针的行走角度,分针亦然,只有秒针可以根据c值来计算。为方便计算,将时间值统一化到单位秒来计算,则有:

a:b:c→3600a+60b+c         (3.2)

(1)时针走过的角度为:

(3600a+60b+c)×(1/120)h° = (30a + b/2 + c/120)h°             (3.3)

(2)分针走过的角度为:

(3600a+60b-c)×(1/10)min° = (360a + 6b + c/10)min°         (3.4)

(3)秒针走过的角度为:

(3600a+60b+c)×6sec° = (21600a + 360b + 6c)sec°              (3.5)

基于上述计算,忽略掉秒对时针角度的影响,假设时间为a:b:c,记时针旋转角度为h,分针旋转角度为m,秒针旋转角度为s。其中a、b、c为整数且,,;h、y、m为大于0的小数,单位为度(°)。那么有:

h = [30.0 × (a + b/60.0)]°                   (3.6)

m = [6.0 × (b + c/60.0)]°                    (3.7)

s = (6.0 × c)°                                       (3.8)

3.4.3  绘制时针、分针、秒针

有了指针的图案坐标和旋转角度,接下来了就可以很方便绘制出指针了。具体步骤如下(以绘制时针为例):

(1)得到当前系统时间:

1  QTime time = QTime::currentTime();

(2)设置画笔和笔刷颜色:

1  painter->setPen(Qt::NoPen);

2  painter->setBrush(Qt::black);

(3)坐标轴旋转(角度参考3.6式):

1  painter->rotate( 30.0 * (time.hour() + time.minute()/60.0) );

(4)绘制凸多边形:

1  painter->drawConvexPolygon(hourHand, 4);

(5)还原坐标轴状态:

1  painter->restore();

分针、秒针绘制步骤类似。不同点在于:

(1)绘制分针画刷颜色设置为蓝色(Qt::blue),坐标点传入“minuteHand”。

(2)绘制秒针画刷颜色为红色(Qt::red),坐标点传入“secondHand”。

3.5  绘制表盘刻度和12小时数字

表盘一共要绘制60条刻度线,其中,从0°开始,每6°应绘制分钟刻度线,每30°应绘制区别于分钟刻度线的小时刻度线。设定一个起始数i,i为整型(int)数据且,每绘制一条刻度线i自增1。那么可以设定每次的旋转角度为,当i能够整除5时,即绘制小时刻度线,否则绘制分钟刻度线。

但是坐标轴旋转会导致时钟下半表盘数字颠倒,要解决此问题,加入一个判断,当坐标轴旋转角度在0°至90°或者270°至360°之间,即i<15或者i>45时,同时绘制上半部分和下半部分数字即可。

代码如下:

1  void Clock::drawClockDial(QPainter *painter)

2  {

3    for (int i = 1; i <= 60; i++)

4    {

5      painter->save();

6      painter->rotate(6*i);

7      if ( (i % 5 == 0) && (i <= 15 || i >= 45) )

8      {

9         painter->setPen(QPen(palette().foreground(), 2.0));

10        painter->drawLine(0, -95, 0, -80);

11        painter->drawText(-20, -82, 40, 40,

12                          Qt::AlignHCenter | Qt::AlignTop,

13                          QString::number(i/5) );

14        if (i < 15 || i > 45)

15        {

16          painter->drawLine(0, 80, 0, 95);

17          painter->drawText( -20, 41, 40, 40,

18                               Qt::AlignHCenter | Qt::AlignBottom,

19                               QString::number(i<15 ? i/5+6 : i/5-6) );

20         }

21      }//if

22      else

23      {

24         painter->setPen(QPen(palette().foreground(), 1.0));

25         painter->drawLine(0, 95, 0, 90);

26      }

27      painter->restore();

28      }//for

29  }

算法流程如图3.4所示。

图3.4  绘制表盘刻度和12小时数字算法流程图

3.6  绘制LCD风格的数字时间

Qt5字体库并没有LCD风格的字体,为了是受那个更加地形象生动,加载字体文件无疑是最好的选择。Qt提供了QFontDatabase::addApplicationFont来加载字体文件至字体族中,从字体族中可以直接使用加载的外部字体,然后使用QPainter类的drawText方法绘制LCD风格的数字。具体步骤如下:

(1)从资源文件加载LCD字体,并将之存储到QstringList数据中:

1  int lcdFontId = QFontDatabase::addApplicationFont(":/lcdFont/DS-DIGI.ttf");

2  if (lcdFontId != -1)

3  {

4     m_fontList << QFontDatabase::applicationFontFamilies(lcdFontId);

5  }

(2)新建QFont类对象,使用“setfamily()”方法设置字体,并给QPainter类对象(painter)设置字体:

1  if (!m_fontList.isEmpty())

2  {

3    QFont font;

4    font.setFamily(m_fontList.at(0));

5    font.setPointSize(15);

6    painter->setFont(font);

7  }

(3)在相应位置绘制当前时间(格式为hh:mm:ss):

1  painter->drawText( -40, 34, 80, 22, Qt::AlignCenter,

2                  QTime::currentTime().toString("hh:mm:ss") );

效果如下图(图3.5)所示:

图3.5  LCD风格数字时间绘制示例

源代码下载: http://download.csdn.net/download/wu9797/10196816

Qt5 实战No.01 桌面时钟相关推荐

  1. 凌祯excel课程_【课程介绍】Excel高效实战:提高桌面生产力.pdf

    提高桌面生产力 H xcel R k Wing Excel高效实战 提高桌面生产力 孙伟 凌祯 匠心至诚 联合出品 Excel高效实战 :提高桌面生产力 * 北京大学法学学士.管理学硕士,人力资源管理 ...

  2. 非等高cell实战(01)-- 实现微博页面

    非等高cell实战(01)-- 实现微博页面 学习过UITableView.AutoLayout以及MVC的相关知识,接下来通过一个微博页面实战来整合一下. 首先看一下效果图: 需求分析 此页面为非等 ...

  3. 桌面时钟代码_iOS 14 制作自己的桌面 Widget

    在上一篇文章中, 我和大家介绍了 iOS 14 Widget 的基本内容, 了解了组成 Widget 的主要几个组件. 这篇文章开始, 我会和大家一起对 Xcode 自带的默认项目做一些优化, 让大家 ...

  4. 手机有一个时钟的标志_手机桌面时钟有这几款就够了

    最近一直在研究怎么把家里闲置吃灰的旧手机拿出来透透气.就在苦苦寻找了几款桌面时钟APP拯救我吃灰的闲置手机没错!就是把旧手机做成一个全屏钟表,虽然我是一个没有时间观念的人,但是桌子上缺一个时钟来装饰一 ...

  5. android studio app显示红叉_发现这个 APP 后,感觉可以放弃桌面时钟了

    天气 App 的种类不少,风格也很多,有人喜欢简洁干净的,比如 Holi.我的天气.雨时等:有人喜欢酷炫有趣的,像 CARROT.知趣.Umbrella 这些:也有人喜欢数据全面且复杂的,那彩云天气则 ...

  6. 安卓 java 视频_安卓实战项目-动态桌面-rxjava实现搜索本地所有视频

    前言:上一篇文章已经实现了将assets文件中设置成动态壁纸:安卓实战项目-动态桌面-简单实现 需求:既然assets文件能用于动态桌面,那么手机中的视频也可以吧,有没有大胆的想法? 上效果图: 分析 ...

  7. 使用RT-Thread Studio DIY 迷你桌面时钟(一)| 基于STM32芯片创建HelloWorld工程

    寻求更清爽的阅读体验,请移步:Mculover666的个人博客. 1. RT-Thread Studio RT-Thread Studio 是一站式的 RT-Thread 开发工具,通过简单易用的图形 ...

  8. 使用RT-Thread Studio DIY 迷你桌面时钟(二)| 获取温湿度传感器数据(I2C设备驱动+SHT3x软件包)

    寻求更清爽的阅读体验,请移步:Mculover666的个人博客. 1. 项目进度 桌面Mini时钟项目用来演示如何使用RT-Thread Stduio开发项目,整个项目的架构如下: 在上一篇博文中简单 ...

  9. 使用RT-Thread Studio DIY 迷你桌面时钟| 获取温湿度传感器数据(I2C设备驱动+SHT3x软件包)...

    1. 项目进度 桌面Mini时钟项目用来演示如何使用RT-Thread Stduio开发项目,整个项目的架构如下: 在上一篇博文中简单的介绍了RT-ThreadStudio一站式工具,基于STM32L ...

最新文章

  1. React 开发环境搭建
  2. 北大女生拿下阿里数学预赛第一名!决赛入围率不到1%,最小晋级选手只有14岁...
  3. r语言 整理、处理数据步骤_R语言万能数据清洗整理包Tidyverse(一)
  4. Java开发规范01 - 集合篇_Arrays.asList 坑
  5. Java对MySQL数据库进行连接、查询和修改【转载】
  6. 管理全局包、缓存和临时文件夹
  7. 山东鲁能轨道智能巡检机器人_温湿度传感器在轨道巡检机器人中的应用
  8. 如何设置VSCode以提高生产力
  9. python---(10) python模块的使用
  10. 基于JAVA+Swing+MYSQL的学生选课系统
  11. C语言丨格式化屏幕输出(二)——日历
  12. Azure上七层负载均衡APP Gateway
  13. Atitit 存储引擎核心技术 总结目录1. 表的存储有三个文件:结构+数据+索引 12. 页式管理
  14. 英特尔nuc能代替主机吗_拆了拆了!Intel NUC装机!小机箱退烧器啊!主机显示器合体...
  15. GitHup使用指南——安装及上传
  16. CH579 以太网转串口 串口服务器代码
  17. iOS开发:如何修改app名称
  18. var模型的建模步骤python_Python语言之概述建模步骤
  19. 计算机英语 book,book是什么意思_book在线翻译_英语_读音_用法_例句_海词词典
  20. 上古卷轴5json文件修改_改进名称的新Tempering名称定制SSE

热门文章

  1. windows中手工调整活动路由表的简单方法
  2. 贪吃蛇游戏实践(附源码),链表的应用!
  3. BZOJ 4338 BJOI2015 糖果
  4. 新老主播怎么做?需要注意的那几点直播内容和技巧分析问题
  5. 如何使用AE来制作烟雾粒子特效
  6. css导航栏跟随,改良版 导航栏自动跟随(示例代码)
  7. c交叉编译成可执行文件在android上运行
  8. arcgis图层数据查询
  9. 【虹科新品】HK-MR660系列:风力涡轮机的叶片加速度监测
  10. 【目标检测论文解读复现NO.25】基于改进Yolov5的地铁隧道附属设施与衬砌表观病害检测方法