QTimer与QDateTime实战应用 - 从时钟到定时器的完整实现
·
QTimer与QDateTime实战应用 - 从时钟到定时器的完整实现
📌 前言
QTimer和QDateTime是Qt中处理时间相关功能的核心类。本文将深入讲解这两个类的使用方法,并通过实战示例展示如何实现时钟、倒计时、定时提醒等功能。
🎯 学习目标
- ✅ 掌握QTimer的基本使用和高级特性
- ✅ 理解QDateTime的时间处理方法
- ✅ 学会实现实时时钟
- ✅ 掌握倒计时功能实现
- ✅ 了解定时任务和周期性任务
- ✅ 掌握性能优化技巧
1️⃣ QTimer 核心概念
什么是QTimer?
QTimer 是Qt提供的定时器类,用于在特定时间间隔后执行代码。
基本工作原理
创建QTimer
↓
设置时间间隔 (ms)
↓
连接timeout信号到槽
↓
启动定时器
↓
每隔指定时间 → emit timeout()
↓
执行关联的槽函数
三种使用模式
模式1:单次触发(Single Shot)
// 3秒后执行一次
QTimer::singleShot(3000, this, [this]() {
qDebug() << "3秒后执行";
});
// 延迟执行任务
QTimer::singleShot(0, this, &MyClass::heavyTask); // 下一个事件循环执行
模式2:重复触发(Repeating)
QTimer *timer = new QTimer(this);
timer->setInterval(1000); // 每1秒触发
connect(timer, &QTimer::timeout, this, &MyClass::onTimeout);
timer->start();
模式3:精确定时(Precise Timer)
QTimer *timer = new QTimer(this);
timer->setInterval(1000);
timer->setTimerType(Qt::PreciseTimer); // 精确定时
timer->start();
2️⃣ 实战:实时时钟
完整实现
ClockModel.h
#ifndef CLOCKMODEL_H
#define CLOCKMODEL_H
#include <QObject>
#include <QTimer>
#include <QDateTime>
#include <QString>
class ClockModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QString currentTime READ currentTime NOTIFY timeChanged)
Q_PROPERTY(QString currentDate READ currentDate NOTIFY dateChanged)
Q_PROPERTY(QString currentWeekDay READ currentWeekDay NOTIFY weekDayChanged)
Q_PROPERTY(bool is24HourFormat READ is24HourFormat WRITE setIs24HourFormat NOTIFY formatChanged)
Q_PROPERTY(bool isRunning READ isRunning NOTIFY runningChanged)
public:
explicit ClockModel(QObject *parent = nullptr);
~ClockModel();
// 属性访问器
QString currentTime() const { return m_currentTime; }
QString currentDate() const { return m_currentDate; }
QString currentWeekDay() const { return m_currentWeekDay; }
bool is24HourFormat() const { return m_is24HourFormat; }
bool isRunning() const { return m_timer && m_timer->isActive(); }
// 属性设置器
void setIs24HourFormat(bool format);
// QML可调用方法
Q_INVOKABLE void start(); // 启动时钟
Q_INVOKABLE void stop(); // 停止时钟
Q_INVOKABLE void toggleFormat(); // 切换格式
signals:
void timeChanged();
void dateChanged();
void weekDayChanged();
void formatChanged();
void runningChanged();
private slots:
void updateTime(); // 定时器槽函数
private:
void formatTime();
void formatDate();
void formatWeekDay();
QTimer *m_timer;
QDateTime m_dateTime;
QString m_currentTime;
QString m_currentDate;
QString m_currentWeekDay;
bool m_is24HourFormat;
};
#endif // CLOCKMODEL_H
ClockModel.cpp
#include "ClockModel.h"
ClockModel::ClockModel(QObject *parent)
: QObject(parent)
, m_timer(new QTimer(this))
, m_is24HourFormat(true)
{
// 初始化时间
updateTime();
// 连接定时器信号
connect(m_timer, &QTimer::timeout, this, &ClockModel::updateTime);
// 配置定时器
m_timer->setInterval(1000); // 1秒
m_timer->setTimerType(Qt::PreciseTimer); // 精确定时
// 自动启动
start();
}
ClockModel::~ClockModel()
{
stop();
}
void ClockModel::start()
{
if (!m_timer->isActive()) {
m_timer->start();
emit runningChanged();
}
}
void ClockModel::stop()
{
if (m_timer->isActive()) {
m_timer->stop();
emit runningChanged();
}
}
void ClockModel::toggleFormat()
{
setIs24HourFormat(!m_is24HourFormat);
}
void ClockModel::setIs24HourFormat(bool format)
{
if (m_is24HourFormat != format) {
m_is24HourFormat = format;
formatTime(); // 立即更新时间显示
emit formatChanged();
}
}
void ClockModel::updateTime()
{
// 获取当前时间
m_dateTime = QDateTime::currentDateTime();
// 更新各部分
formatTime();
formatDate();
formatWeekDay();
}
void ClockModel::formatTime()
{
QString newTime;
if (m_is24HourFormat) {
// 24小时制:HH:mm:ss
newTime = m_dateTime.toString("HH:mm:ss");
} else {
// 12小时制:h:mm:ss AP
newTime = m_dateTime.toString("h:mm:ss AP");
}
// 只在值改变时发送信号
if (m_currentTime != newTime) {
m_currentTime = newTime;
emit timeChanged();
}
}
void ClockModel::formatDate()
{
// 日期格式:yyyy年MM月dd日
QString newDate = m_dateTime.toString("yyyy年MM月dd日");
if (m_currentDate != newDate) {
m_currentDate = newDate;
emit dateChanged();
}
}
void ClockModel::formatWeekDay()
{
// 获取星期几
int dayOfWeek = m_dateTime.date().dayOfWeek(); // 1-7 (Monday-Sunday)
static const QStringList weekDays = {
"星期一", "星期二", "星期三", "星期四",
"星期五", "星期六", "星期日"
};
QString newWeekDay = weekDays[dayOfWeek - 1];
if (m_currentWeekDay != newWeekDay) {
m_currentWeekDay = newWeekDay;
emit weekDayChanged();
}
}
QML界面
import QtQuick 2.15
Rectangle {
anchors.fill: parent
color: "#0F2027"
Column {
anchors.centerIn: parent
spacing: 20
// 时间显示
Text {
text: clockModel.currentTime
font.pixelSize: 120
font.bold: true
color: "#FFFFFF"
anchors.horizontalCenter: parent.horizontalCenter
}
// 日期和星期
Column {
spacing: 10
anchors.horizontalCenter: parent.horizontalCenter
Text {
text: clockModel.currentDate
font.pixelSize: 36
color: "#B0E0E6"
anchors.horizontalCenter: parent.horizontalCenter
}
Text {
text: clockModel.currentWeekDay
font.pixelSize: 28
color: "#87CEEB"
anchors.horizontalCenter: parent.horizontalCenter
}
}
// 控制按钮
Row {
spacing: 20
anchors.horizontalCenter: parent.horizontalCenter
Rectangle {
width: 100
height: 40
color: "#00D4FF"
radius: 5
Text {
text: clockModel.isRunning ? "暂停" : "启动"
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
if (clockModel.isRunning) {
clockModel.stop()
} else {
clockModel.start()
}
}
}
}
Rectangle {
width: 100
height: 40
color: "#00D4FF"
radius: 5
Text {
text: "切换格式"
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: clockModel.toggleFormat()
}
}
}
}
}
3️⃣ QDateTime 完全指南
创建QDateTime对象
// 方式1:当前时间
QDateTime now = QDateTime::currentDateTime();
// 方式2:指定日期和时间
QDateTime dt = QDateTime(QDate(2025, 11, 8), QTime(14, 30, 0));
// 方式3:从字符串解析
QDateTime dt = QDateTime::fromString("2025-11-08 14:30:00", "yyyy-MM-dd HH:mm:ss");
// 方式4:从时间戳
QDateTime dt = QDateTime::fromSecsSinceEpoch(1699437600);
时间格式化
QDateTime dt = QDateTime::currentDateTime();
// 标准格式
dt.toString("yyyy-MM-dd HH:mm:ss"); // 2025-11-08 14:30:25
dt.toString("yyyy年MM月dd日"); // 2025年11月08日
dt.toString("HH:mm:ss"); // 14:30:25
dt.toString("h:mm:ss AP"); // 2:30:25 PM
// 完整格式
dt.toString(Qt::ISODate); // 2025-11-08T14:30:25
dt.toString(Qt::TextDate); // Fri Nov 8 14:30:25 2025
dt.toString(Qt::RFC2822Date); // Fri, 08 Nov 2025 14:30:25 +0800
// 自定义格式
dt.toString("ddd MMM d yyyy"); // Fri Nov 8 2025
dt.toString("dddd, MMMM d, yyyy"); // Friday, November 8, 2025
格式化符号说明
| 符号 | 含义 | 示例 |
|---|---|---|
yyyy |
4位年份 | 2025 |
yy |
2位年份 | 25 |
MM |
月份(01-12) | 11 |
M |
月份(1-12) | 11 |
MMM |
月份简写 | Nov |
MMMM |
月份全名 | November |
dd |
日期(01-31) | 08 |
d |
日期(1-31) | 8 |
ddd |
星期简写 | Fri |
dddd |
星期全名 | Friday |
HH |
小时(00-23) | 14 |
H |
小时(0-23) | 14 |
hh |
小时(01-12) | 02 |
h |
小时(1-12) | 2 |
mm |
分钟(00-59) | 30 |
m |
分钟(0-59) | 30 |
ss |
秒(00-59) | 25 |
s |
秒(0-59) | 25 |
zzz |
毫秒 | 123 |
AP |
AM/PM | PM |
ap |
am/pm | pm |
时间计算
QDateTime now = QDateTime::currentDateTime();
// 加减时间
QDateTime tomorrow = now.addDays(1);
QDateTime nextWeek = now.addDays(7);
QDateTime nextMonth = now.addMonths(1);
QDateTime nextYear = now.addYears(1);
QDateTime later = now.addSecs(3600); // 1小时后
// 时间差
QDateTime startTime = QDateTime::currentDateTime();
// ... 执行某些操作 ...
QDateTime endTime = QDateTime::currentDateTime();
qint64 secondsDiff = startTime.secsTo(endTime);
qint64 daysDiff = startTime.daysTo(endTime);
qDebug() << "耗时:" << secondsDiff << "秒";
时间比较
QDateTime dt1 = QDateTime::currentDateTime();
QDateTime dt2 = dt1.addSecs(60);
if (dt1 < dt2) {
qDebug() << "dt1早于dt2";
}
if (dt1 == dt2) {
qDebug() << "时间相同";
}
// 判断是否为有效时间
if (dt1.isValid()) {
qDebug() << "时间有效";
}
4️⃣ 实战:倒计时功能
完整实现
class CountdownModel : public QObject
{
Q_OBJECT
Q_PROPERTY(int remainingSeconds READ remainingSeconds NOTIFY remainingChanged)
Q_PROPERTY(QString displayTime READ displayTime NOTIFY displayChanged)
Q_PROPERTY(bool isRunning READ isRunning NOTIFY runningChanged)
public:
explicit CountdownModel(QObject *parent = nullptr)
: QObject(parent)
, m_timer(new QTimer(this))
, m_remainingSeconds(0)
{
connect(m_timer, &QTimer::timeout, this, &CountdownModel::tick);
}
int remainingSeconds() const { return m_remainingSeconds; }
bool isRunning() const { return m_timer->isActive(); }
QString displayTime() const {
int hours = m_remainingSeconds / 3600;
int minutes = (m_remainingSeconds % 3600) / 60;
int seconds = m_remainingSeconds % 60;
return QString("%1:%2:%3")
.arg(hours, 2, 10, QChar('0'))
.arg(minutes, 2, 10, QChar('0'))
.arg(seconds, 2, 10, QChar('0'));
}
Q_INVOKABLE void start(int seconds) {
if (seconds > 0) {
m_remainingSeconds = seconds;
emit remainingChanged();
emit displayChanged();
m_timer->start(1000); // 每秒触发
emit runningChanged();
}
}
Q_INVOKABLE void stop() {
m_timer->stop();
emit runningChanged();
}
Q_INVOKABLE void reset() {
stop();
m_remainingSeconds = 0;
emit remainingChanged();
emit displayChanged();
}
signals:
void remainingChanged();
void displayChanged();
void runningChanged();
void finished(); // 倒计时结束
private slots:
void tick() {
if (m_remainingSeconds > 0) {
m_remainingSeconds--;
emit remainingChanged();
emit displayChanged();
if (m_remainingSeconds == 0) {
stop();
emit finished(); // 通知倒计时结束
}
}
}
private:
QTimer *m_timer;
int m_remainingSeconds;
};
QML界面
Column {
spacing: 20
// 倒计时显示
Text {
text: countdownModel.displayTime
font.pixelSize: 80
color: countdownModel.remainingSeconds < 10 ? "red" : "white"
}
// 控制按钮
Row {
spacing: 10
Button {
text: "5分钟"
onClicked: countdownModel.start(300)
}
Button {
text: "10分钟"
onClicked: countdownModel.start(600)
}
Button {
text: "停止"
onClicked: countdownModel.stop()
}
Button {
text: "重置"
onClicked: countdownModel.reset()
}
}
// 监听倒计时结束
Connections {
target: countdownModel
onFinished: {
console.log("倒计时结束!")
// 播放提示音、弹出通知等
}
}
}
5️⃣ 性能优化
1. 选择合适的定时器类型
// Qt::PreciseTimer - 精确定时(默认,1ms精度)
timer->setTimerType(Qt::PreciseTimer);
// Qt::CoarseTimer - 粗糙定时(5%误差,省电)
timer->setTimerType(Qt::CoarseTimer);
// Qt::VeryCoarseTimer - 非常粗糙(1秒误差,最省电)
timer->setTimerType(Qt::VeryCoarseTimer);
选择建议:
- 动画、游戏 →
PreciseTimer - 时钟显示 →
CoarseTimer(1秒误差可接受) - 后台任务 →
VeryCoarseTimer
2. 避免频繁启停
// ❌ 不好:频繁启停
void updateDisplay() {
m_timer->stop();
// 做一些事情
m_timer->start(1000);
}
// ✅ 好:保持运行
void updateDisplay() {
// 定时器持续运行
// 在timeout槽中处理更新
}
3. 批量更新
// ❌ 不好:每次都发信号
void tick() {
m_seconds--;
emit secondsChanged();
m_minutes = m_seconds / 60;
emit minutesChanged();
m_hours = m_seconds / 3600;
emit hoursChanged();
}
// ✅ 好:一次更新
void tick() {
m_seconds--;
updateTimeComponents(); // 内部更新所有值
emit timeChanged(); // 只发一次信号
}
🎓 总结
本文详细讲解了QTimer和QDateTime的使用:
- ✅ QTimer的三种使用模式
- ✅ 实时时钟的完整实现
- ✅ QDateTime的创建和格式化
- ✅ 时间计算和比较
- ✅ 倒计时功能实现
- ✅ 性能优化技巧
核心要点:
- QTimer是基于事件循环的定时器
- 使用精确定时器类型获得更好精度
- QDateTime提供丰富的时间处理方法
- 合理使用信号避免频繁更新
- 根据场景选择合适的定时器类型
作者: 坚果派
日期: 2025-11-08
系列: Qt for HarmonyOS 深度解析
更多推荐



所有评论(0)