全屏定时提醒工具
全屏定时提醒工具
本文档详细介绍了全屏定时提醒工具的代码实现过程,从项目架构到具体功能的逐步实现。
📋 目录
- 项目架构设计
- 环境配置与项目创建
- 核心数据结构设计
- 主窗口实现
- 提醒对话框实现
- 系统托盘功能
- 数据持久化
- 高级功能实现
- UI美化与用户体验
- 调试与优化
1. 项目架构设计
1.1 整体架构
ReminderTool/
├── main.cpp # 程序入口点
├── mainwindow.h/.cpp/.ui # 主窗口 - 提醒管理界面
├── reminderdialog.h/.cpp/.ui # 提醒对话框 - 全屏提醒显示
├── ReminderTool.pro # Qt项目配置
└── res.qrc # 资源文件
1.2 设计模式
- MVC模式:UI界面与业务逻辑分离
- 单例模式:密码管理使用静态成员
- 观察者模式:Qt信号槽机制
1.3 核心组件
- MainWindow:主控制器,负责提醒管理
- ReminderDialog:全屏提醒显示窗口
- Reminder结构体:提醒数据模型
- QTimer:定时检查和倒计时功能
2. 环境配置与项目创建
2.1 创建Qt项目
// ReminderTool.pro 配置文件
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11SOURCES += \main.cpp \mainwindow.cpp \reminderdialog.cppHEADERS += \mainwindow.h \reminderdialog.hFORMS += \mainwindow.ui \reminderdialog.uiRESOURCES += res.qrc
2.2 程序入口点设计
// main.cpp - 关键配置
int main(int argc, char *argv[])
{QApplication a(argc, argv);// 🔑 关键设置:程序不会在最后窗口关闭时退出// 这样可以在系统托盘中继续运行a.setQuitOnLastWindowClosed(false);// 设置应用程序图标a.setWindowIcon(QIcon(":/avatar.jpg"));MainWindow w;w.show();return a.exec();
}
实现要点:
setQuitOnLastWindowClosed(false)是实现托盘功能的关键- 应用程序图标设置提升用户体验
3. 核心数据结构设计
3.1 提醒数据结构
// mainwindow.h - 提醒数据模型
struct Reminder {QDateTime time; // 提醒时间QString message; // 提醒内容bool triggered = false; // 是否已触发bool isRecurring = false; // 是否为周期性任务int recurringType = 0; // 周期类型:0=一次性,1=每天重复
};
设计考虑:
- 使用
QDateTime处理时间,支持日期和时间 triggered标志避免重复触发isRecurring和recurringType支持周期性提醒
3.2 主窗口类设计
class MainWindow : public QMainWindow
{Q_OBJECTprivate:Ui::MainWindow *ui;QTimer *m_timer; // 定时检查器QList<Reminder> m_reminders; // 提醒列表// 系统托盘相关QSystemTrayIcon *m_trayIcon;QMenu *m_trayMenu;// 免打扰功能QDateTime m_doNotDisturbEndTime;// 核心功能函数void setupTimer(); // 设置定时器void setupTrayIcon(); // 设置系统托盘void checkReminders(); // 检查提醒void saveReminders(); // 保存数据void loadReminders(); // 加载数据
};
4. 主窗口实现
4.1 构造函数 - 初始化流程
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow), m_timer(new QTimer(this)), m_trayIcon(nullptr), m_trayMenu(nullptr)
{// 步骤1:基础UI设置ui->setupUi(this);setWindowTitle("全屏定时提醒工具");setFixedSize(900, 700);// 步骤2:字体和样式设置setupFontAndStyle();// 步骤3:初始化控件默认值initializeControls();// 步骤4:连接信号槽connectSignals();// 步骤5:设置核心功能setupTimer(); // 定时检查setupTrayIcon(); // 系统托盘// 步骤6:加载数据loadReminders(); // 加载保存的提醒loadSettings(); // 加载设置
}
4.2 字体和样式设置
void MainWindow::setupFontAndStyle()
{// 设置全局字体抗锯齿QFont font = this->font();font.setFamily("Microsoft YaHei UI, Segoe UI, Arial, sans-serif");font.setHintingPreference(QFont::PreferFullHinting);font.setStyleStrategy(QFont::PreferAntialias);this->setFont(font);// 应用全局样式this->setStyleSheet(this->styleSheet() + "* { font-family: 'Microsoft YaHei UI', 'Segoe UI', Arial, sans-serif; }");
}
4.3 控件初始化
void MainWindow::initializeControls()
{// 日期控件设置ui->dateEdit->setDate(QDate::currentDate());ui->dateEdit->setMinimumDate(QDate::currentDate());ui->dateEdit->setMaximumDate(QDate::currentDate().addYears(1));// 时间控件设置为当前时间QTime currentTime = QTime::currentTime();ui->hourSpinBox->setValue(currentTime.hour());ui->minuteSpinBox->setValue(currentTime.minute());// 列表控件设置ui->reminderListWidget->setFocusPolicy(Qt::StrongFocus);ui->reminderListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
}
4.4 信号槽连接
void MainWindow::connectSignals()
{// 基础功能连接connect(ui->setPasswordButton, &QPushButton::clicked, this, &MainWindow::setPassword);// 周期性选择connect(ui->recurringComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::onRecurringChanged);// 列表双击删除connect(ui->reminderListWidget, &QListWidget::itemDoubleClicked, this, &MainWindow::onReminderItemDoubleClicked);// 开机自启connect(ui->autoStartCheckBox, &QCheckBox::toggled, this, &MainWindow::onAutoStartToggled);// 快捷时间按钮connectQuickTimeButtons();
}
4.5 定时器设置
void MainWindow::setupTimer()
{// 连接定时器信号connect(m_timer, &QTimer::timeout, this, &MainWindow::checkReminders);// 每秒检查一次 - 这是核心功能m_timer->start(1000);
}
关键点:
- 1秒间隔确保及时触发提醒
- 使用
QTimer::timeout信号进行周期性检查
5. 提醒检查与触发机制
5.1 核心检查逻辑
void MainWindow::checkReminders()
{// 检查是否在免打扰时间if (isDoNotDisturbActive()) {return;}QDateTime currentTime = QDateTime::currentDateTime();bool hasTriggered = false;for (int i = 0; i < m_reminders.size(); ++i) {Reminder &reminder = m_reminders[i];// 检查是否到达提醒时间且未触发if (!reminder.triggered && currentTime >= reminder.time) {// 触发提醒triggerReminder(reminder);hasTriggered = true;// 处理周期性任务if (reminder.isRecurring && reminder.recurringType == 1) {// 每天重复:设置为明天同一时间reminder.time = reminder.time.addDays(1);reminder.triggered = false;} else {// 一次性任务:标记为已触发reminder.triggered = true;}}}if (hasTriggered) {// 清理已完成的一次性任务cleanupTriggeredReminders();// 更新显示和保存数据updateReminderListDisplay();saveReminders();}
}
5.2 提醒触发
void MainWindow::triggerReminder(const Reminder &reminder)
{// 获取倒计时设置int countdownSeconds = ui->countdownSpinBox->value();// 创建并显示全屏提醒对话框ReminderDialog *dialog = new ReminderDialog(reminder.message, countdownSeconds, this);// 模态显示,阻塞其他操作dialog->exec();// 对话框关闭后自动删除dialog->deleteLater();
}
6. 提醒对话框实现
6.1 全屏对话框设计
ReminderDialog::ReminderDialog(const QString &message, int countdownSeconds, QWidget *parent) :QDialog(parent),ui(new Ui::ReminderDialog),m_countdownTimer(new QTimer(this)),m_remainingSeconds(countdownSeconds)
{ui->setupUi(this);// 🔑 关键:设置窗口为无边框全屏置顶setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Tool);setWindowState(Qt::WindowFullScreen);// 设置背景和样式setStyleSheet("background-color: #2E8B57; color: white;");// 强制获取焦点setAttribute(Qt::WA_ShowWithoutActivating, false);setModal(true);// 设置UI和启动倒计时setupUI(message);startCountdown(countdownSeconds);// 确保窗口置顶(Windows特定)ensureTopmost();
}
6.2 UI布局设计
void ReminderDialog::setupUI(const QString &message)
{QVBoxLayout *layout = new QVBoxLayout(this);// 主要提醒消息m_messageLabel = new QLabel(message, this);m_messageLabel->setAlignment(Qt::AlignCenter);m_messageLabel->setWordWrap(true);m_messageLabel->setStyleSheet("font-size: 48px; ""font-weight: bold; ""margin: 50px; ""font-family: 'Microsoft YaHei UI', 'Segoe UI', Arial, sans-serif;");// 倒计时标签m_countdownLabel = new QLabel(this);m_countdownLabel->setAlignment(Qt::AlignCenter);m_countdownLabel->setStyleSheet("font-size: 36px; ""font-weight: bold; ""margin: 20px; ""color: #FFD700; ""background-color: rgba(255, 255, 255, 0.1); ""border-radius: 10px; ""padding: 15px;");// 密码输入区域setupPasswordInput();// 添加到布局layout->addWidget(m_messageLabel);layout->addWidget(m_countdownLabel);layout->addWidget(m_passwordLabel);layout->addLayout(createPasswordLayout());layout->addWidget(m_closeButton, 0, Qt::AlignCenter);setLayout(layout);// 添加背景闪烁效果setupBlinkEffect();
}
6.3 倒计时功能
void ReminderDialog::startCountdown(int seconds)
{m_remainingSeconds = seconds;updateCountdown();// 连接倒计时定时器connect(m_countdownTimer, &QTimer::timeout, this, &ReminderDialog::updateCountdown);m_countdownTimer->start(1000);
}void ReminderDialog::updateCountdown()
{if (m_remainingSeconds > 0) {// 显示剩余时间m_countdownLabel->setText(QString("倒计时: %1 秒").arg(m_remainingSeconds));m_remainingSeconds--;} else {// 倒计时结束,启用密码输入m_countdownTimer->stop();enablePasswordInput();}
}
6.4 屏幕闪烁效果
void ReminderDialog::setupBlinkEffect()
{// 创建闪烁定时器QTimer *blinkTimer = new QTimer(this);connect(blinkTimer, &QTimer::timeout, this, [this]() {static bool isOriginalColor = true;if (isOriginalColor) {// 切换到闪烁颜色setStyleSheet("background-color: #32CD32; color: white;");} else {// 恢复原始颜色setStyleSheet("background-color: #2E8B57; color: white;");}isOriginalColor = !isOriginalColor;});blinkTimer->start(500); // 每500毫秒闪烁一次// 🔑 关键改进:闪烁时长与倒计时同步QTimer::singleShot(m_remainingSeconds * 1000, this, [this, blinkTimer]() {blinkTimer->stop();setStyleSheet("background-color: #2E8B57; color: white;");});
}
7. 系统托盘功能
7.1 托盘图标设置
void MainWindow::setupTrayIcon()
{// 检查系统支持if (!QSystemTrayIcon::isSystemTrayAvailable()) {QMessageBox::critical(this, "系统托盘", "系统不支持托盘功能");return;}// 创建托盘图标m_trayIcon = new QSystemTrayIcon(this);m_trayIcon->setIcon(QIcon(":/avatar.jpg"));m_trayIcon->setToolTip("定时提醒工具");// 创建托盘菜单createTrayMenu();// 连接信号connect(m_trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivated);// 显示托盘图标m_trayIcon->show();
}
7.2 托盘菜单创建
void MainWindow::createTrayMenu()
{m_trayMenu = new QMenu(this);// 显示主窗口m_showAction = new QAction("显示主窗口", this);connect(m_showAction, &QAction::triggered, this, &MainWindow::showWindow);// 开机自启m_autoStartAction = new QAction("开机自启", this);m_autoStartAction->setCheckable(true);m_autoStartAction->setChecked(isAutoStartEnabled());connect(m_autoStartAction, &QAction::triggered, this, &MainWindow::toggleAutoStart);// 免打扰选项createDoNotDisturbMenu();// 退出程序m_quitAction = new QAction("退出程序", this);connect(m_quitAction, &QAction::triggered, this, &MainWindow::quitApplication);// 添加到菜单m_trayMenu->addAction(m_showAction);m_trayMenu->addSeparator();m_trayMenu->addAction(m_autoStartAction);m_trayMenu->addSeparator();addDoNotDisturbActions();m_trayMenu->addSeparator();m_trayMenu->addAction(m_quitAction);m_trayIcon->setContextMenu(m_trayMenu);
}
7.3 窗口关闭处理
void MainWindow::closeEvent(QCloseEvent *event)
{if (m_trayIcon && m_trayIcon->isVisible()) {// 最小化到托盘而不是退出hide();event->ignore();// 首次提示用户static bool firstTime = true;if (firstTime) {m_trayIcon->showMessage("定时提醒工具", "程序已最小化到系统托盘", QSystemTrayIcon::Information, 2000);firstTime = false;}} else {event->accept();}
}
8. 数据持久化
8.1 保存提醒数据
void MainWindow::saveReminders()
{QSettings settings("ReminderTool", "Reminders");// 使用数组方式保存settings.beginWriteArray("reminders");for (int i = 0; i < m_reminders.size(); ++i) {settings.setArrayIndex(i);settings.setValue("time", m_reminders[i].time);settings.setValue("message", m_reminders[i].message);settings.setValue("triggered", m_reminders[i].triggered);settings.setValue("isRecurring", m_reminders[i].isRecurring);settings.setValue("recurringType", m_reminders[i].recurringType);}settings.endArray();// 保存其他设置settings.setValue("countdownSeconds", ui->countdownSpinBox->value());
}
8.2 加载提醒数据
void MainWindow::loadReminders()
{QSettings settings("ReminderTool", "Reminders");int size = settings.beginReadArray("reminders");m_reminders.clear();for (int i = 0; i < size; ++i) {settings.setArrayIndex(i);Reminder reminder;reminder.time = settings.value("time").toDateTime();reminder.message = settings.value("message").toString();reminder.triggered = settings.value("triggered").toBool();reminder.isRecurring = settings.value("isRecurring", false).toBool();reminder.recurringType = settings.value("recurringType", 0).toInt();// 处理周期性任务的时间调整if (reminder.isRecurring && reminder.triggered) {adjustRecurringTime(reminder);}m_reminders.append(reminder);}settings.endArray();// 加载其他设置int countdownSeconds = settings.value("countdownSeconds", 10).toInt();ui->countdownSpinBox->setValue(countdownSeconds);// 更新显示updateReminderListDisplay();
}
9. 高级功能实现
9.1 开机自启功能
bool MainWindow::isAutoStartEnabled()
{// 检查Windows注册表QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);return settings.contains("ReminderTool");
}void MainWindow::setAutoStart(bool enabled)
{QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);if (enabled) {// 添加到启动项QString appPath = QCoreApplication::applicationFilePath();appPath = QDir::toNativeSeparators(appPath);settings.setValue("ReminderTool", appPath);} else {// 从启动项移除settings.remove("ReminderTool");}
}
9.2 免打扰模式
bool MainWindow::isDoNotDisturbActive()
{if (!m_doNotDisturbEndTime.isValid()) {return false;}QDateTime currentTime = QDateTime::currentDateTime();if (currentTime >= m_doNotDisturbEndTime) {// 免打扰时间已过,自动关闭m_doNotDisturbEndTime = QDateTime();updateDoNotDisturbMenu();return false;}return true;
}void MainWindow::toggleDoNotDisturb2Hours()
{m_doNotDisturbEndTime = QDateTime::currentDateTime().addSecs(2 * 3600);updateDoNotDisturbMenu();if (m_trayIcon) {m_trayIcon->showMessage("免打扰", "已启用2小时免打扰模式", QSystemTrayIcon::Information, 2000);}
}
9.3 快捷时间设置
void MainWindow::setQuickTime5Min()
{QDateTime quickTime = QDateTime::currentDateTime().addSecs(5 * 60);ui->dateEdit->setDate(quickTime.date());ui->hourSpinBox->setValue(quickTime.time().hour());ui->minuteSpinBox->setValue(quickTime.time().minute());
}void MainWindow::setQuickTimeTomorrow()
{QDateTime tomorrow = QDateTime::currentDateTime().addDays(1);ui->dateEdit->setDate(tomorrow.date());// 时间保持当前设置不变
}
10. UI美化与用户体验
10.1 倒计时结束界面美化
void ReminderDialog::enablePasswordInput()
{// 美化倒计时结束提示m_countdownLabel->setText("🎉 倒计时结束!现在可以输入密码了 🎉");// 渐变背景样式m_countdownLabel->setStyleSheet("font-size: 32px; ""font-weight: bold; ""margin: 20px; ""color: #FFFFFF; ""background: qlineargradient(x1:0, y1:0, x2:1, y2:1, ""stop:0 #00FF7F, stop:0.5 #32CD32, stop:1 #228B22); ""border: 3px solid #FFD700; ""border-radius: 15px; ""padding: 20px; ""text-shadow: 2px 2px 4px rgba(0,0,0,0.5);");// 美化密码输入框beautifyPasswordInput();// 美化按钮beautifyCloseButton();// 添加动画效果addInputAnimation();// 启用输入控件m_passwordEdit->setEnabled(true);m_closeButton->setEnabled(true);m_passwordEdit->setFocus();
}
10.2 动画效果
void ReminderDialog::addInputAnimation()
{// 为密码输入框添加"呼吸"动画QPropertyAnimation *animation = new QPropertyAnimation(m_passwordEdit, "geometry");animation->setDuration(1000);animation->setLoopCount(3);QRect originalGeometry = m_passwordEdit->geometry();QRect expandedGeometry = originalGeometry.adjusted(-5, -2, 5, 2);animation->setKeyValueAt(0, originalGeometry);animation->setKeyValueAt(0.5, expandedGeometry);animation->setKeyValueAt(1, originalGeometry);animation->start(QAbstractAnimation::DeleteWhenStopped);
}
10.3 按钮悬停效果
void ReminderDialog::beautifyCloseButton()
{m_closeButton->setStyleSheet("QPushButton {""font-size: 24px; ""padding: 18px 30px; ""background: qlineargradient(x1:0, y1:0, x2:0, y2:1, ""stop:0 #98FB98, stop:0.5 #90EE90, stop:1 #7CFC00); ""color: #2E8B57; ""border: 2px solid #32CD32; ""border-radius: 12px; ""font-weight: bold;""} ""QPushButton:hover {""background: qlineargradient(x1:0, y1:0, x2:0, y2:1, ""stop:0 #ADFF2F, stop:0.5 #9AFF9A, stop:1 #90EE90); ""border: 2px solid #228B22; ""transform: scale(1.05);""} ""QPushButton:pressed {""background: qlineargradient(x1:0, y1:0, x2:0, y2:1, ""stop:0 #7CFC00, stop:0.5 #90EE90, stop:1 #98FB98);""}");
}
11. 调试与优化
11.1 常见问题解决
问题1:窗口无法置顶
// 解决方案:Windows特定API
#ifdef Q_OS_WIN
void ReminderDialog::ensureTopmost()
{QTimer::singleShot(100, this, [this]() {SetWindowPos((HWND)winId(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);});
}
#endif
问题2:变量作用域错误
// 错误:使用局部变量
QTimer::singleShot(countdownSeconds * 1000, ...);// 正确:使用成员变量
QTimer::singleShot(m_remainingSeconds * 1000, ...);
问题3:内存泄漏
// 确保对话框自动删除
ReminderDialog *dialog = new ReminderDialog(...);
dialog->exec();
dialog->deleteLater(); // 重要:自动删除
这个实现指南展示了从零开始构建一个功能完整的桌面应用程序的完整过程,涵盖了Qt开发的核心技术和最佳实践。
源码仓库https://gitee.com/dream-cometrue/reminder-tool
