Qt Creator 4.4.1 Based on Qt 5.9.3 (MSVC 2015, 32 bit)
1)鼠标滚轮放大缩小
2)时钟走动音效
3)右键菜单
4)托盘菜单
#ifndef CLOCK_H #define CLOCK_H #include
#include #include #include #include #include #include #include #include #include class Clock : public QWidget { Q_OBJECT public: 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
#include "clock.h" #include
#include #include #include #include #include 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::Bold painter.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) ); } }//if else // 分钟刻度 { 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); // 设置toolTip double 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; } }
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) |
提供组合各图层的功能图 |
时钟的时针、分针、秒针位置每秒都在更新,故我们需要一个定时器来定时重绘。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 时钟走时流程图
(一)绘制时钟窗口背景图
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();
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类型。
(一)时针、分针、秒针图形的坐标设定
设定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)
有了指针的图案坐标和旋转角度,接下来了就可以很方便绘制出指针了。具体步骤如下(以绘制时针为例):
(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”。
表盘一共要绘制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小时数字算法流程图
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