吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 152|回复: 6
上一主题 下一主题
收起左侧

[Python 原创] 久用电脑必备,定时提醒护航健康!

[复制链接]
跳转到指定楼层
楼主
skywalker0123 发表于 2026-7-9 19:56 回帖奖励
本帖最后由 skywalker0123 于 2026-7-9 22:38 编辑

先声明:代码由本人编写,但是由于本人代码编写不太规范,为了方便理解,所以让AI添加注释并且修改函数名如题,我写了个定时提醒功能,具体功能:可以提醒喝水,放松等等内容,特别是经常使用电脑的朋友们,可以设置定时提醒,保护眼睛!可在windows上运行,目前自带有三项,也可以点击”管理提醒“自定义增删改提醒内容。提醒模式:Windows系统右下角消息提醒。可以自定义间隔,但是输入完自定义时间要点击更新。配置会保存在当前目录下的json文件。点击“开始”开始计时,“暂停”暂停计时。“重置”复位计时。模式单一:只提醒一次,旁边设置的次数只在循环模式下有效果。备注:因为我设置了无控制台(就是没有黑窗),所以360不知道为啥就报毒,各位不放心可以看看源码,或者自己反编译。
问题修复等内容
如果遇到问题或者bug可以打开该文件所在目录,底下会有log.txt文件,将日志文件和你的问题或bug发给我,我看到会处理。如果有其他想要的功能也可以私信我哦!
成品及源代码(蓝奏云不接收py格式文件,所以我用的是.txt):
https://starrailfirefly.lanzoul.com/b01d72ks4h密码:9801



[Python] 纯文本查看 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import json
import os
import logging
import time
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QPushButton, QFrame, QSystemTrayIcon, QMenu, QAction,
    QMessageBox, QSpinBox, QComboBox, QDialog, QListWidget, QListWidgetItem,
    QFormLayout, QLineEdit, QTextEdit, QDialogButtonBox, QScrollArea,
    QSizePolicy
)
from PyQt5.QtCore import Qt, QTimer, QRect, pyqtSignal
from PyQt5.QtGui import QFont, QIcon, QPainter, QBrush, QPen, QColor, QPixmap

# ====================== 日志配置 ======================
def setup_logging():
    """配置日志:追加模式,写入 log.txt"""
    log_file = "log.txt"
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(levelname)s - %(message)s',
        handlers=[
            logging.FileHandler(log_file, mode='a', encoding='utf-8'),
        ]
    )
    logging.info("========== 程序启动 ==========")

# ======================= 默认配置 =======================
DEFAULT_INTERVAL = 30 * 60

DEFAULT_REMINDERS = [
    {
        "id": "water",
        "title": "💧 喝水",
        "message": "站起来倒杯水,补充水分吧!",
        "interval": 30 * 60,
        "mode": "single",
        "loop_count": 3
    },
    {
        "id": "break",
        "title": "🚶 休息",
        "message": "久坐伤身,起来活动5分钟!",
        "interval": 45 * 60,
        "mode": "single",
        "loop_count": 3
    },
    {
        "id": "eye",
        "title": "👀 眼保健操",
        "message": "闭上眼睛,做一套眼保健操。",
        "interval": 90 * 60,
        "mode": "single",
        "loop_count": 3
    }
]

CONFIG_FILE = "config.json"
# =========================================================

class ReminderItem:
    def __init__(self, data):
        self.id = data.get("id", self.generate_id())
        self.title = data.get("title", "新提醒")
        self.message = data.get("message", "")
        self.interval = data.get("interval", DEFAULT_INTERVAL)
        self.mode = data.get("mode", "single")
        self.loop_count = data.get("loop_count", 3)

    def to_dict(self):
        return {
            "id": self.id,
            "title": self.title,
            "message": self.message,
            "interval": self.interval,
            "mode": self.mode,
            "loop_count": self.loop_count
        }

    @staticmethod
    def generate_id():
        import time
        return f"reminder_{int(time.time()*1000)}"

class ConfigManager:
    @staticmethod
    def load():
        try:
            if os.path.exists(CONFIG_FILE):
                with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                if isinstance(data, dict) and "water" in data:
                    # 旧版格式迁移
                    new_list = []
                    for key, val in data.items():
                        new_list.append({
                            "id": key,
                            "title": val.get("title", key),
                            "message": val.get("message", ""),
                            "interval": DEFAULT_INTERVAL,
                            "mode": "single",
                            "loop_count": 3
                        })
                    logging.info("从旧版配置迁移数据")
                    items = [ReminderItem(item) for item in new_list]
                    ConfigManager.save(items)
                    return items
                elif isinstance(data, list):
                    logging.info(f"加载配置成功,共 {len(data)} 个提醒项")
                    return [ReminderItem(item) for item in data]
                else:
                    logging.warning("配置格式未知,使用默认配置并重新生成")
                    items = [ReminderItem(item) for item in DEFAULT_REMINDERS]
                    ConfigManager.save(items)
                    return items
            else:
                logging.info("配置文件不存在,创建默认配置")
                items = [ReminderItem(item) for item in DEFAULT_REMINDERS]
                ConfigManager.save(items)
                return items
        except Exception as e:
            logging.exception(f"加载配置时发生异常: {e}")
            items = [ReminderItem(item) for item in DEFAULT_REMINDERS]
            ConfigManager.save(items)
            return items

    @staticmethod
    def save(items):
        try:
            data = [item.to_dict() for item in items]
            with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=4)
            logging.info(f"配置保存成功,共 {len(items)} 个提醒项")
            return True
        except Exception as e:
            logging.exception(f"保存配置时发生异常: {e}")
            return False


class NewReminderDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("新建提醒")
        self.setMinimumWidth(350)
        layout = QFormLayout(self)

        self.title_edit = QLineEdit()
        self.title_edit.setPlaceholderText("输入标题,如 '💧 喝水'")
        self.msg_edit = QTextEdit()
        self.msg_edit.setPlaceholderText("输入提醒消息")
        self.msg_edit.setMaximumHeight(80)

        layout.addRow("标题:", self.title_edit)
        layout.addRow("消息:", self.msg_edit)

        btn_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        btn_box.accepted.connect(self.accept)
        btn_box.rejected.connect(self.reject)
        layout.addRow(btn_box)

    def get_data(self):
        return {
            "title": self.title_edit.text().strip(),
            "message": self.msg_edit.toPlainText().strip()
        }


class EditReminderDialog(QDialog):
    def __init__(self, title, message, parent=None):
        super().__init__(parent)
        self.setWindowTitle("编辑提醒")
        self.setMinimumWidth(350)
        layout = QFormLayout(self)

        self.title_edit = QLineEdit(title)
        self.msg_edit = QTextEdit(message)
        self.msg_edit.setMaximumHeight(80)

        layout.addRow("标题:", self.title_edit)
        layout.addRow("消息:", self.msg_edit)

        btn_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        btn_box.accepted.connect(self.accept)
        btn_box.rejected.connect(self.reject)
        layout.addRow(btn_box)

    def get_data(self):
        return {
            "title": self.title_edit.text().strip(),
            "message": self.msg_edit.toPlainText().strip()
        }


class SettingsDialog(QDialog):
    def __init__(self, config_items, parent=None):
        super().__init__(parent)
        self.config_items = config_items
        self.setWindowTitle("提醒项管理")
        self.setMinimumSize(450, 400)
        self.setModal(True)

        layout = QVBoxLayout(self)

        self.list_widget = QListWidget()
        self.refresh_list()
        layout.addWidget(self.list_widget)

        btn_layout = QHBoxLayout()
        self.new_btn = QPushButton("➕ 新建")
        self.new_btn.clicked.connect(self.new_reminder)
        self.edit_btn = QPushButton("✏️ 编辑")
        self.edit_btn.clicked.connect(self.edit_reminder)
        self.delete_btn = QPushButton("🗑️ 删除")
        self.delete_btn.clicked.connect(self.delete_reminder)

        btn_layout.addWidget(self.new_btn)
        btn_layout.addWidget(self.edit_btn)
        btn_layout.addWidget(self.delete_btn)
        btn_layout.addStretch()

        btn_box = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Cancel)
        btn_box.accepted.connect(self.save_and_close)
        btn_box.rejected.connect(self.reject)

        layout.addLayout(btn_layout)
        layout.addWidget(btn_box)

        self.list_widget.itemDoubleClicked.connect(self.edit_reminder)

    def refresh_list(self):
        self.list_widget.clear()
        for item in self.config_items:
            self.list_widget.addItem(f"{item.title} ({item.id})")

    def new_reminder(self):
        dialog = NewReminderDialog(self)
        if dialog.exec_() == QDialog.Accepted:
            data = dialog.get_data()
            if not data["title"]:
                QMessageBox.warning(self, "错误", "标题不能为空")
                return
            new_item = ReminderItem({
                "id": ReminderItem.generate_id(),
                "title": data["title"],
                "message": data["message"],
                "interval": DEFAULT_INTERVAL,
                "mode": "single",
                "loop_count": 3
            })
            self.config_items.append(new_item)
            self.refresh_list()
            logging.info(f"新建提醒项: {new_item.title}")

    def edit_reminder(self):
        current = self.list_widget.currentRow()
        if current < 0:
            QMessageBox.warning(self, "提示", "请先选择一个提醒项")
            return
        item = self.config_items[current]
        dialog = EditReminderDialog(item.title, item.message, self)
        if dialog.exec_() == QDialog.Accepted:
            data = dialog.get_data()
            if not data["title"]:
                QMessageBox.warning(self, "错误", "标题不能为空")
                return
            old_title = item.title
            item.title = data["title"]
            item.message = data["message"]
            self.refresh_list()
            logging.info(f"编辑提醒项: {old_title} -> {item.title}")

    def delete_reminder(self):
        if len(self.config_items) <= 1:
            QMessageBox.warning(self, "提示", "至少保留一个提醒项")
            return
        current = self.list_widget.currentRow()
        if current < 0:
            QMessageBox.warning(self, "提示", "请先选择一个提醒项")
            return
        reply = QMessageBox.question(self, "确认删除", f"确定要删除“{self.config_items[current].title}”吗?",
                                     QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            deleted = self.config_items.pop(current)
            self.refresh_list()
            logging.info(f"删除提醒项: {deleted.title}")

    def save_and_close(self):
        if ConfigManager.save(self.config_items):
            logging.info("设置窗口保存配置")
            self.accept()
        else:
            QMessageBox.warning(self, "保存失败", "无法写入配置文件")


class TimerCard(QFrame):
    def __init__(self, reminder_item, parent=None):
        super().__init__(parent)
        self.item = reminder_item
        self.remaining = reminder_item.interval
        self.running = False
        self.parent_window = parent

        self.mode = reminder_item.mode
        self.loop_total = reminder_item.loop_count
        self.loop_remaining = reminder_item.loop_count

        self.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        self.setObjectName("timerCard")
        self.setMinimumWidth(240)

        layout = QVBoxLayout(self)
        layout.setSpacing(6)
        layout.setContentsMargins(12, 12, 12, 12)

        self.title_label = QLabel(reminder_item.title)
        self.title_label.setAlignment(Qt.AlignCenter)
        self.title_label.setObjectName("cardTitle")
        layout.addWidget(self.title_label)

        self.time_label = QLabel(self.format_time(self.remaining))
        self.time_label.setAlignment(Qt.AlignCenter)
        self.time_label.setObjectName("timeDisplay")
        layout.addWidget(self.time_label)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(6)

        self.start_btn = QPushButton("&#9654; 开始")
        self.start_btn.setMinimumWidth(70)
        self.start_btn.clicked.connect(self.start_timer)

        self.pause_btn = QPushButton("&#9208; 暂停")
        self.pause_btn.setMinimumWidth(70)
        self.pause_btn.clicked.connect(self.pause_timer)
        self.pause_btn.setEnabled(False)

        self.reset_btn = QPushButton("&#128260; 重置")
        self.reset_btn.setMinimumWidth(70)
        self.reset_btn.clicked.connect(self.reset_timer)

        btn_layout.addWidget(self.start_btn)
        btn_layout.addWidget(self.pause_btn)
        btn_layout.addWidget(self.reset_btn)
        layout.addLayout(btn_layout)

        interval_layout = QHBoxLayout()
        interval_layout.setSpacing(4)
        interval_label = QLabel("间隔(分钟):")
        interval_label.setStyleSheet("font-size: 9pt; color: #2c3e50;")
        self.interval_spin = QSpinBox()
        self.interval_spin.setRange(1, 999)
        self.interval_spin.setValue(reminder_item.interval // 60)
        self.interval_spin.setMinimumWidth(60)
        self.interval_spin.setStyleSheet("font-size: 9pt;")
        self.update_interval_btn = QPushButton("更新")
        self.update_interval_btn.setMinimumWidth(50)
        self.update_interval_btn.clicked.connect(self.update_interval)
        self.update_interval_btn.setStyleSheet("""
            QPushButton { background-color: #3498db; color: white; font-size: 9pt; border-radius: 4px; padding: 2px 6px; }
            QPushButton:hover { background-color: #2980b9; }
        """)
        interval_layout.addWidget(interval_label)
        interval_layout.addWidget(self.interval_spin)
        interval_layout.addWidget(self.update_interval_btn)
        interval_layout.addStretch()
        layout.addLayout(interval_layout)

        mode_layout = QHBoxLayout()
        mode_layout.setSpacing(4)
        mode_label = QLabel("模式:")
        mode_label.setStyleSheet("font-size: 9pt; color: #2c3e50;")
        self.mode_combo = QComboBox()
        self.mode_combo.addItems(["单一", "循环", "无限"])
        self.mode_combo.setCurrentIndex(["single","loop","infinite"].index(self.mode))
        self.mode_combo.currentIndexChanged.connect(self.on_mode_changed)
        self.mode_combo.setMinimumWidth(70)
        self.mode_combo.setStyleSheet("font-size: 9pt;")

        self.loop_label = QLabel("次数:")
        self.loop_label.setStyleSheet("font-size: 9pt; color: #2c3e50;")
        self.loop_spin = QSpinBox()
        self.loop_spin.setRange(1, 99)
        self.loop_spin.setValue(self.loop_total)
        self.loop_spin.setMinimumWidth(50)
        self.loop_spin.setStyleSheet("font-size: 9pt;")
        self.loop_spin.valueChanged.connect(self.on_loop_count_changed)

        mode_layout.addWidget(mode_label)
        mode_layout.addWidget(self.mode_combo)
        mode_layout.addWidget(self.loop_label)
        mode_layout.addWidget(self.loop_spin)
        mode_layout.addStretch()
        layout.addLayout(mode_layout)

        self.apply_mode_to_ui()

        self.setStyleSheet("""
            QFrame#timerCard {
                background-color: rgba(255, 255, 255, 0.85);
                border-radius: 12px;
                padding: 8px;
            }
            QLabel#cardTitle {
                font-size: 14pt;
                font-weight: bold;
                color: #2c3e50;
            }
            QLabel#timeDisplay {
                font-size: 24pt;
                font-weight: bold;
                color: #2980b9;
                font-family: 'Consolas', monospace;
            }
            QPushButton {
                background-color: #ecf0f1;
                border: none;
                border-radius: 6px;
                padding: 4px 6px;
                font-size: 9pt;
                font-weight: bold;
                color: #2c3e50;
            }
            QPushButton:hover { background-color: #d0d7db; }
            QPushButton:pressed { background-color: #b0b8be; }
            QPushButton:disabled { color: #b0b8be; background-color: #e0e4e8; }
            QComboBox, QSpinBox { background-color: white; border: 1px solid #ccc; border-radius: 4px; padding: 1px 3px; font-size: 9pt; }
        """)

    def format_time(self, seconds):
        if seconds < 0: seconds = 0
        mins, secs = divmod(int(seconds), 60)
        return f"{mins:02d}:{secs:02d}"

    def update_time(self):
        if self.running and self.remaining > 0:
            self.remaining -= 1
            self.time_label.setText(self.format_time(self.remaining))
            if self.remaining <= 0:
                self.on_timeout()

    def on_timeout(self):
        title = self.item.title
        message = self.item.message
        self.parent_window.show_notification(title, message)
        logging.info(f"提醒触发: {title} - {message}")

        if self.mode == "single":
            self.running = False
            self.start_btn.setEnabled(True)
            self.pause_btn.setEnabled(False)
        elif self.mode == "loop":
            self.loop_remaining -= 1
            self.loop_spin.setValue(self.loop_remaining)
            if self.loop_remaining > 0:
                self.remaining = self.item.interval
                self.time_label.setText(self.format_time(self.remaining))
                self.running = True
                self.start_btn.setEnabled(False)
                self.pause_btn.setEnabled(True)
            else:
                self.running = False
                self.start_btn.setEnabled(True)
                self.pause_btn.setEnabled(False)
        else:  # infinite
            self.remaining = self.item.interval
            self.time_label.setText(self.format_time(self.remaining))
            self.running = True
            self.start_btn.setEnabled(False)
            self.pause_btn.setEnabled(True)

    def start_timer(self):
        if self.remaining <= 0:
            self.remaining = self.item.interval
            self.time_label.setText(self.format_time(self.remaining))
            if self.mode == "loop" and self.loop_remaining <= 0:
                self.loop_remaining = self.loop_total
                self.loop_spin.setValue(self.loop_remaining)
        self.running = True
        self.start_btn.setEnabled(False)
        self.pause_btn.setEnabled(True)
        logging.info(f"开始计时: {self.item.title}")

    def pause_timer(self):
        self.running = False
        self.start_btn.setEnabled(True)
        self.pause_btn.setEnabled(False)
        logging.info(f"暂停计时: {self.item.title}")

    def reset_timer(self):
        self.remaining = self.item.interval
        self.time_label.setText(self.format_time(self.remaining))
        self.running = False
        self.start_btn.setEnabled(True)
        self.pause_btn.setEnabled(False)
        if self.mode == "loop":
            self.loop_remaining = self.loop_total
            self.loop_spin.setValue(self.loop_remaining)
        logging.info(f"重置计时: {self.item.title}")

    def on_mode_changed(self, index):
        mode_text = self.mode_combo.currentText()
        if mode_text == "单一":
            self.mode = "single"
            self.loop_label.setEnabled(False)
            self.loop_spin.setEnabled(False)
        elif mode_text == "循环":
            self.mode = "loop"
            self.loop_label.setEnabled(True)
            self.loop_spin.setEnabled(True)
            self.loop_total = self.loop_spin.value()
            self.loop_remaining = self.loop_total
        else:
            self.mode = "infinite"
            self.loop_label.setEnabled(False)
            self.loop_spin.setEnabled(False)
        self.item.mode = self.mode
        self.item.loop_count = self.loop_total
        self.reset_timer()
        logging.info(f"{self.item.title} 切换模式为 {mode_text}")

    def on_loop_count_changed(self, value):
        if self.mode == "loop":
            self.loop_total = value
            self.item.loop_count = value
            if not self.running:
                self.loop_remaining = value

    def update_interval(self):
        new_minutes = self.interval_spin.value()
        new_interval = new_minutes * 60
        if new_interval != self.item.interval:
            self.item.interval = new_interval
            self.reset_timer()
            ConfigManager.save(self.parent_window.config_items)
            logging.info(f"{self.item.title} 间隔更新为 {new_minutes} 分钟")
            if self.parent_window.tray_icon:
                self.parent_window.tray_icon.showMessage(
                    "间隔已更新",
                    f"{self.item.title} 间隔改为 {new_minutes} 分钟",
                    QSystemTrayIcon.Information,
                    1500
                )

    def apply_mode_to_ui(self):
        if self.mode == "single":
            self.loop_label.setEnabled(False)
            self.loop_spin.setEnabled(False)
        elif self.mode == "loop":
            self.loop_label.setEnabled(True)
            self.loop_spin.setEnabled(True)
        else:
            self.loop_label.setEnabled(False)
            self.loop_spin.setEnabled(False)

    def update_title(self, new_title):
        self.title_label.setText(new_title)


class HealthReminder(QMainWindow):
    def __init__(self):
        super().__init__()
        logging.info("初始化主窗口")
        self.config_items = ConfigManager.load()
        self.card_widgets = []

        self.setWindowTitle("定时守护")
        self.setWindowIcon(self.create_icon())
        self.resize(1000, 600)
        self.setMinimumSize(800, 400)

        screen_rect = QApplication.primaryScreen().availableGeometry()
        center = screen_rect.center()
        self.move(center.x() - self.width()//2, center.y() - self.height()//2)

        self.tray_icon = None
        self.init_tray()

        central = QWidget()
        self.setCentralWidget(central)
        main_layout = QVBoxLayout(central)
        main_layout.setContentsMargins(15, 10, 15, 10)
        main_layout.setSpacing(10)

        top_layout = QHBoxLayout()
        title_label = QLabel("&#9201; 定时守护")
        title_label.setStyleSheet("font-size: 18pt; font-weight: bold; color: white;")
        top_layout.addWidget(title_label)
        top_layout.addStretch()
        main_layout.addLayout(top_layout)

        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setStyleSheet("QScrollArea { border: none; background: transparent; }")
        self.card_container = QWidget()
        self.card_container.setStyleSheet("background: transparent;")
        self.card_layout = QHBoxLayout(self.card_container)
        self.card_layout.setSpacing(15)
        self.card_layout.setContentsMargins(5, 5, 5, 5)
        self.card_layout.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        scroll.setWidget(self.card_container)
        main_layout.addWidget(scroll, 1)

        bottom_layout = QHBoxLayout()
        bottom_layout.setSpacing(10)

        self.reset_all_btn = QPushButton("&#128260; 重置所有")
        self.reset_all_btn.setMinimumWidth(100)
        self.reset_all_btn.clicked.connect(self.reset_all)

        self.start_all_btn = QPushButton("&#9654; 一键开始所有")
        self.start_all_btn.setMinimumWidth(100)
        self.start_all_btn.clicked.connect(self.start_all)

        bottom_layout.addWidget(self.reset_all_btn)
        bottom_layout.addWidget(self.start_all_btn)
        bottom_layout.addStretch()

        self.settings_btn = QPushButton("&#9881;&#65039; 管理提醒")
        self.settings_btn.setMinimumWidth(100)
        self.settings_btn.clicked.connect(self.open_settings)
        self.settings_btn.setStyleSheet("background-color: #8e44ad; color: white;")
        bottom_layout.addWidget(self.settings_btn)

        self.hide_btn = QPushButton("&#9209; 隐藏到后台")
        self.hide_btn.setMinimumWidth(100)
        self.hide_btn.clicked.connect(self.hide_to_tray)
        self.hide_btn.setStyleSheet("background-color: #3498db; color: white;")
        bottom_layout.addWidget(self.hide_btn)

        main_layout.addLayout(bottom_layout)

        self.setStyleSheet("""
            QMainWindow {
                background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                                            stop:0 #74ebd5, stop:1 #9face6);
            }
            QPushButton {
                background-color: #ecf0f1;
                border: none;
                border-radius: 8px;
                padding: 6px 12px;
                font-size: 10pt;
                font-weight: bold;
                color: #2c3e50;
            }
            QPushButton:hover { background-color: #d0d7db; }
            QPushButton:pressed { background-color: #b0b8be; }
            QPushButton#resetAllBtn { background-color: #e74c3c; color: white; }
            QPushButton#resetAllBtn:hover { background-color: #c0392b; }
            QPushButton#startAllBtn { background-color: #27ae60; color: white; }
            QPushButton#startAllBtn:hover { background-color: #229954; }
        """)
        self.reset_all_btn.setObjectName("resetAllBtn")
        self.start_all_btn.setObjectName("startAllBtn")

        self.rebuild_cards()

        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update_all_timers)
        self.timer.start(1000)
        logging.info("主窗口初始化完成")

    def rebuild_cards(self):
        for card in self.card_widgets:
            self.card_layout.removeWidget(card)
            card.deleteLater()
        self.card_widgets.clear()

        for item in self.config_items:
            card = TimerCard(item, self)
            self.card_layout.addWidget(card)
            self.card_widgets.append(card)
        logging.info(f"重建卡片,共 {len(self.card_widgets)} 个")

    def open_settings(self):
        dialog = SettingsDialog(self.config_items, self)
        if dialog.exec_() == QDialog.Accepted:
            self.config_items = ConfigManager.load()
            self.rebuild_cards()
            if self.tray_icon:
                self.tray_icon.showMessage("设置已更新", "提醒项已修改", QSystemTrayIcon.Information, 1500)
            logging.info("设置窗口关闭,配置已更新")

    def create_icon(self):
        pixmap = QPixmap(64, 64)
        pixmap.fill(Qt.transparent)
        painter = QPainter(pixmap)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setBrush(QBrush(QColor("#2196F3")))
        painter.setPen(QPen(QColor("#0D47A1"), 2))
        painter.drawEllipse(8, 8, 48, 48)
        painter.setPen(QColor("white"))
        painter.setFont(QFont("Segoe UI Emoji", 24))
        painter.drawText(QRect(8, 8, 48, 48), Qt.AlignCenter, "&#9201;")
        painter.end()
        return QIcon(pixmap)

    def init_tray(self):
        if not QSystemTrayIcon.isSystemTrayAvailable():
            logging.warning("系统托盘不可用")
            return
        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(self.create_icon())
        self.tray_icon.setToolTip("定时守护")

        tray_menu = QMenu()
        show_action = QAction("显示主窗口", self)
        show_action.triggered.connect(self.show_window)
        tray_menu.addAction(show_action)

        reset_action = QAction("重置所有计时器", self)
        reset_action.triggered.connect(self.reset_all)
        tray_menu.addAction(reset_action)

        start_action = QAction("一键开始所有", self)
        start_action.triggered.connect(self.start_all)
        tray_menu.addAction(start_action)

        tray_menu.addSeparator()
        quit_action = QAction("退出", self)
        quit_action.triggered.connect(self.quit_app)
        tray_menu.addAction(quit_action)

        self.tray_icon.setContextMenu(tray_menu)
        self.tray_icon.activated.connect(self.tray_activated)
        self.tray_icon.show()
        logging.info("系统托盘已初始化")

    def tray_activated(self, reason):
        if reason == QSystemTrayIcon.DoubleClick:
            self.show_window()

    def show_window(self):
        self.showNormal()
        self.raise_()
        self.activateWindow()
        logging.info("显示主窗口")

    def hide_to_tray(self):
        self.hide()
        if self.tray_icon and self.tray_icon.isVisible():
            self.tray_icon.showMessage("定时守护", "程序已隐藏到后台,双击图标恢复", QSystemTrayIcon.Information, 2000)
        logging.info("隐藏到系统托盘")

    def closeEvent(self, event):
        self.quit_app()
        event.accept()

    def quit_app(self):
        logging.info("程序退出")
        self.timer.stop()
        if self.tray_icon:
            self.tray_icon.hide()
        QApplication.quit()

    def show_notification(self, title, message):
        if self.tray_icon and self.tray_icon.isVisible():
            self.tray_icon.showMessage(title, message, QSystemTrayIcon.Information, 5000)
        else:
            QMessageBox.information(self, title, message)

    def update_all_timers(self):
        for card in self.card_widgets:
            card.update_time()

    def reset_all(self):
        for card in self.card_widgets:
            card.reset_timer()
        if self.tray_icon:
            self.tray_icon.showMessage("重置成功", "所有计时器已重置并暂停", QSystemTrayIcon.Information, 1000)
        logging.info("重置所有计时器")

    def start_all(self):
        for card in self.card_widgets:
            if not card.running:
                card.start_timer()
        if self.tray_icon:
            self.tray_icon.showMessage("已启动", "所有计时器已开始倒计时", QSystemTrayIcon.Information, 1000)
        logging.info("一键启动所有计时器")


def main():
    setup_logging()
    try:
        app = QApplication(sys.argv)
        app.setQuitOnLastWindowClosed(False)
        window = HealthReminder()
        window.show()
        sys.exit(app.exec_())
    except Exception as e:
        logging.exception(f"程序运行异常: {e}")
        raise

if __name__ == "__main__":
    main()

屏幕截图 2026-07-09 194108.png (77.31 KB, 下载次数: 0)

屏幕截图 2026-07-09 194108.png

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
苏紫方璇 发表于 2026-7-9 22:21
请在帖子中插入部分关键代码
本版块仅限分享编程技术和源码相关内容,发布帖子必须带上关键代码和具体功能介绍
3#
LAOYAO2021 发表于 2026-7-9 22:35
4#
 楼主| skywalker0123 发表于 2026-7-9 22:35 |楼主
苏紫方璇 发表于 2026-7-9 22:21
请在帖子中插入部分关键代码
本版块仅限分享编程技术和源码相关内容,发布帖子必须带上关键代码和具体功能 ...

收到,已添加关键代码
5#
haihailove521 发表于 2026-7-10 15:14
很实用 ,谢谢了   
6#
hankv 发表于 2026-7-11 08:08
很新奇,多谢了
7#
jrjmusic 发表于 2026-7-11 19:37
功能是不错,就是有点……大……
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-7-12 09:01

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表