【开源解析】基于Python+Qt打造智能应用时长统计工具 - 你的数字生活分析师

发布于:2025-06-19 ⋅ 阅读:(19) ⋅ 点赞:(0)

📊 【开源解析】基于Python+Qt打造智能应用时长统计工具 - 你的数字生活分析师

在这里插入图片描述
请添加图片描述

🌈 个人主页:创客白泽 - CSDN博客
🔥 系列专栏:🐍《Python开源项目实战》
💡 热爱不止于代码,热情源自每一个灵感闪现的夜晚。愿以开源之火,点亮前行之路。
🐋 希望大家多多支持,我们一起进步!
👍 🎉如果文章对你有帮助的话,欢迎 点赞 👍🏻 评论 💬 收藏 ⭐️ 加关注+💗分享给更多人哦

请添加图片描述

在这里插入图片描述

🌟 概述:数字时代的时间管理者

在数字化生活日益普及的今天,我们每天与各种应用程序的交互时间越来越长。但你是否真正了解自己的数字生活习惯?哪些应用占用了你最多的时间?时间都花在了哪里?

今天我将介绍一款自主研发的应用时长统计工具,它能够:

  • 实时监控应用使用情况
  • 可视化展示时间分配
  • 分析每周使用趋势
  • 最小化到系统托盘后台运行

这款工具采用Python+Qt开发,结合matplotlib实现专业级数据可视化,是程序员和普通用户都能轻松使用的效率工具。

🛠️ 功能全景图

核心功能矩阵

功能模块 技术实现 数据维度
实时监控 psutil+win32api跨平台采集 秒级精度
数据持久化 JSON序列化+按日期存储 历史数据可追溯
可视化分析 Matplotlib+Qt5嵌入式图表 多维数据呈现
系统托盘 QSystemTrayIcon 无感后台运行
周趋势分析 时间序列聚合+堆叠柱状图 七日对比

技术栈亮点

  • 应用识别:Windows/MacOS/Linux三平台兼容
  • 性能优化:定时器精准控制1秒采集间隔
  • 数据安全:双重备份机制(实时+每日)
  • 交互设计:标签页自动刷新+表格高亮交互

🖥️ 效果展示

1. 实时数据看板

在这里插入图片描述

特点说明:

  • 当前运行应用蓝色高亮
  • 使用时长TOP3金色标识
  • 实时刷新排名变化

2. 时长占比分析

在这里插入图片描述

智能处理:

  • 自动合并<5%的小项为"其他"
  • 中心显示总时长
  • 响应式标签防重叠

3. 周趋势图谱

在这里插入图片描述

分析维度:

  • Top5应用每日对比
  • 小时为单位直观显示
  • 颜色编码区分应用

🛠️ 部署与使用指南

环境准备

# 基础依赖
pip install pyqt5 psutil matplotlib

# 平台特定依赖
# Windows
pip install pywin32

使用教程

python app_usage_tracker.py
  1. 最小化到托盘:关闭窗口自动后台运行

  2. 数据查看

    • 实时数据页:查看当前会话统计
    • 图表页:点击标签自动刷新
  3. 数据存储

    • app_usage_data/目录下查看历史数据
    • 每日数据自动归档

自定义配置

# 修改监控频率(毫秒)
self.timer.start(1000)  # 默认1秒

# 修改数据存储路径
self.data_dir = "custom_data_path"

🔍 核心代码解析

1. 应用进程监控引擎

def get_current_app(self):
    """跨平台应用识别核心方法"""
    try:
        if platform.system() == "Windows":
            import win32gui
            window = win32gui.GetForegroundWindow()
            _, pid = win32gui.GetWindowThreadProcessId(window)
            return psutil.Process(pid).name()
        # 其他平台处理...
    except Exception as e:
        print(f"应用识别异常: {e}")
    return "Unknown"

技术要点:

  • Windows使用win32gui获取前台窗口
  • Linux依赖xdotool工具链
  • MacOS通过AppKit接口

2. 数据可视化引擎

def update_weekly_chart(self):
    """周趋势图生成逻辑"""
    # 1. 数据准备
    dates = [datetime.now().date() - timedelta(days=i) for i in range(6, -1, -1)]
    
    # 2. Top5应用筛选
    app_total_time = defaultdict(float)
    for date in dates:
        daily_data = self.load_daily_data(date.strftime("%Y-%m-%d"))
        for app, secs in (daily_data or {}).items():
            app_total_time[app] += secs
    
    # 3. 柱状图绘制
    fig, ax = plt.subplots(figsize=(12,7))
    for i, (app, _) in enumerate(sorted(app_total_time.items(), key=lambda x: x[1], reverse=True)[:5]):
        daily_usage = [
            self.load_daily_data(d.strftime("%Y-%m-%d")).get(app, 0)/3600 
            for d in dates
        ]
        ax.bar(x + i*width, daily_usage, width, label=app)
    
    # 4. 图表美化...

设计亮点:

  • 动态数据聚合
  • 自动响应式布局
  • 视觉层次分明

3. 系统托盘集成

def init_system_tray(self):
    """托盘图标管理系统"""
    self.tray_icon = QSystemTrayIcon(self)
    menu = QMenu()
    menu.addAction("显示主界面", self.show)
    menu.addAction("退出", self.close_app)
    self.tray_icon.setContextMenu(menu)
    self.tray_icon.show()

交互设计:

  • 右键菜单快速操作
  • 双击恢复窗口
  • 气泡消息提示

📥 源码下载

import sys
import time
from datetime import datetime, timedelta
import json
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QWidget, 
                            QTableWidget, QTableWidgetItem, QSystemTrayIcon, 
                            QMenu, QAction, QMessageBox, QTabWidget, QHeaderView,
                            QLabel)
from PyQt5.QtCore import QTimer, Qt
from PyQt5.QtGui import QIcon, QFont, QColor
import psutil
import platform
import os
import numpy as np
from matplotlib import cm
from matplotlib.font_manager import FontProperties

# 设置matplotlib支持中文显示
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']  # 使用微软雅黑
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

class AppUsageTracker(QMainWindow):
    def __init__(self):
        super().__init__()
        
        # 初始化数据
        self.app_data = {}
        self.current_app = None
        self.last_update_time = time.time()
        self.data_dir = "app_usage_data"
        self.data_file = os.path.join(self.data_dir, "current_usage.json")
        
        # 创建数据目录
        os.makedirs(self.data_dir, exist_ok=True)
        
        # 加载历史数据
        self.load_data()
        
        # 初始化UI
        self.init_ui()
        
        # 设置系统托盘
        self.init_system_tray()
        
        # 设置定时器
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_app_usage)
        self.timer.start(1000)  # 每秒更新一次
        
        # 每周数据定时保存
        self.weekly_save_timer = QTimer()
        self.weekly_save_timer.timeout.connect(self.save_weekly_data)
        self.weekly_save_timer.start(3600000)  # 每小时检查一次
        
    def init_ui(self):
        """初始化用户界面"""
        self.setWindowTitle("📊 应用使用时长统计")
        self.setWindowIcon(QIcon(self.get_emoji_icon("📊")))
        self.setGeometry(100, 100, 1200, 800)  # 增大窗口尺寸
        
        # 主布局
        main_widget = QWidget()
        self.setCentralWidget(main_widget)
        layout = QVBoxLayout(main_widget)
        
        # 创建标签页
        self.tabs = QTabWidget()
        self.tabs.currentChanged.connect(self.on_tab_changed)
        layout.addWidget(self.tabs)
        
        # 初始化各标签页
        self.init_realtime_tab()
        self.init_bar_chart_tab()
        self.init_pie_chart_tab()
        self.init_weekly_chart_tab()  # 修改为周统计图表页
        
        # 添加工具栏
        self.init_toolbar()
        
    def on_tab_changed(self, index):
        """标签页切换时自动刷新图表"""
        if index == 1:  # 使用时长排行标签页
            self.update_bar_chart()
        elif index == 2:  # 使用时长占比标签页
            self.update_pie_chart()
        elif index == 3:  # 周统计数据标签页
            self.update_weekly_chart()
        
    def init_realtime_tab(self):
        """初始化实时数据标签页"""
        self.realtime_tab = QWidget()
        self.tabs.addTab(self.realtime_tab, "⏱️ 实时数据")
        
        layout = QVBoxLayout(self.realtime_tab)
        
        # 添加标题
        title_label = QLabel("应用使用时长实时统计")
        title_label.setFont(QFont("Microsoft YaHei", 12, QFont.Bold))
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setStyleSheet("padding: 10px;")
        layout.addWidget(title_label)
        
        # 创建表格
        self.table = QTableWidget()
        self.table.setColumnCount(3)
        self.table.setHorizontalHeaderLabels(["排名", "应用名称", "使用时长"])
        
        # 设置表格样式
        self.table.setStyleSheet(
            "QTableWidget { border: 1px solid #e0e0e0; }"
            "QTableWidget::item { padding: 5px; }"
            "QHeaderView::section { background-color: #f0f0f0; padding: 5px; }"
        )
        
        self.table.setColumnWidth(0, 60)
        self.table.setColumnWidth(1, 300)
        self.table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.table.setEditTriggers(QTableWidget.NoEditTriggers)
        self.table.setSortingEnabled(False)
        self.table.setAlternatingRowColors(True)
        
        layout.addWidget(self.table)
        
    def init_bar_chart_tab(self):
        """初始化条形图标签页"""
        self.bar_chart_tab = QWidget()
        self.tabs.addTab(self.bar_chart_tab, "📈 使用时长排行")
        
        layout = QVBoxLayout(self.bar_chart_tab)
        
        # 添加标题
        title_label = QLabel("应用使用时长排行榜")
        title_label.setFont(QFont("Microsoft YaHei", 12, QFont.Bold))
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setStyleSheet("padding: 10px;")
        layout.addWidget(title_label)
        
        # 创建图表
        self.bar_figure = plt.figure(figsize=(10, 6), dpi=100, facecolor='white')
        self.bar_canvas = FigureCanvas(self.bar_figure)
        layout.addWidget(self.bar_canvas)
        
    def init_pie_chart_tab(self):
        """初始化饼图标签页"""
        self.pie_chart_tab = QWidget()
        self.tabs.addTab(self.pie_chart_tab, "🍰 使用时长占比")
        
        layout = QVBoxLayout(self.pie_chart_tab)
        
        # 添加标题
        title_label = QLabel("应用使用时长占比")
        title_label.setFont(QFont("Microsoft YaHei", 12, QFont.Bold))
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setStyleSheet("padding: 10px;")
        layout.addWidget(title_label)
        
        # 创建图表
        self.pie_figure = plt.figure(figsize=(10, 6), dpi=100, facecolor='white')
        self.pie_canvas = FigureCanvas(self.pie_figure)
        layout.addWidget(self.pie_canvas)
        
    def init_weekly_chart_tab(self):
        """初始化周统计图表标签页"""
        self.weekly_chart_tab = QWidget()
        self.tabs.addTab(self.weekly_chart_tab, "📅 周使用趋势")
        
        layout = QVBoxLayout(self.weekly_chart_tab)
        
        # 添加标题
        title_label = QLabel("近七日应用使用时长趋势")
        title_label.setFont(QFont("Microsoft YaHei", 12, QFont.Bold))
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setStyleSheet("padding: 10px;")
        layout.addWidget(title_label)
        
        # 创建图表
        self.weekly_figure = plt.figure(figsize=(12, 7), dpi=100, facecolor='white')
        self.weekly_canvas = FigureCanvas(self.weekly_figure)
        layout.addWidget(self.weekly_canvas)
        
    def init_toolbar(self):
        """初始化工具栏"""
        self.refresh_button = QAction("🔄 刷新图表", self)
        self.refresh_button.triggered.connect(self.update_all_charts)
        
        self.toolbar = self.addToolBar("工具栏")
        self.toolbar.addAction(self.refresh_button)
        
    def init_system_tray(self):
        """初始化系统托盘"""
        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(QIcon(self.get_emoji_icon("⏱️")))
        
        tray_menu = QMenu()
        show_action = QAction("👀 显示窗口", self)
        show_action.triggered.connect(self.show)
        tray_menu.addAction(show_action)
        
        exit_action = QAction("🚪 退出", self)
        exit_action.triggered.connect(self.close_app)
        tray_menu.addAction(exit_action)
        
        self.tray_icon.setContextMenu(tray_menu)
        self.tray_icon.show()
        self.tray_icon.activated.connect(self.tray_icon_clicked)
        
    def tray_icon_clicked(self, reason):
        """托盘图标点击事件处理"""
        if reason == QSystemTrayIcon.DoubleClick:
            self.show()
            self.activateWindow()
            
    def close_app(self):
        """退出应用程序"""
        self.save_data()
        self.tray_icon.hide()
        QApplication.quit()
        
    def closeEvent(self, event):
        """重写关闭事件,最小化到托盘"""
        event.ignore()
        self.hide()
        self.tray_icon.showMessage(
            "应用使用时长统计",
            "程序已最小化到系统托盘",
            QSystemTrayIcon.Information,
            2000
        )
        
    def get_emoji_icon(self, emoji):
        """将emoji转换为图标"""
        return emoji
        
    def get_current_app(self):
        """获取当前活动窗口的应用"""
        try:
            current_app = "Unknown"
            
            if platform.system() == "Windows":
                import win32gui
                import win32process
                
                window = win32gui.GetForegroundWindow()
                _, pid = win32process.GetWindowThreadProcessId(window)
                
                try:
                    process = psutil.Process(pid)
                    current_app = process.name()
                    current_app = os.path.splitext(current_app)[0]
                except (psutil.NoSuchProcess, psutil.AccessDenied):
                    current_app = "Unknown"
                    
            elif platform.system() == "Darwin":
                from AppKit import NSWorkspace
                current_app = NSWorkspace.sharedWorkspace().frontmostApplication().localizedName()
                
            else:  # Linux
                import subprocess
                try:
                    window_id = subprocess.check_output(["xdotool", "getactivewindow"]).decode().strip()
                    pid = subprocess.check_output(["xdotool", "getwindowpid", window_id]).decode().strip()
                    process = psutil.Process(int(pid))
                    current_app = process.name()
                    current_app = os.path.splitext(current_app)[0]
                except:
                    current_app = "Unknown"
                    
            # 清理应用名称
            for suffix in ['.exe', '.bin', '.app']:
                if current_app.endswith(suffix):
                    current_app = current_app[:-len(suffix)]
                    
            return current_app
            
        except Exception as e:
            print(f"获取应用名称出错: {e}")
            return "Unknown"
        
    def update_app_usage(self):
        """更新应用使用时长"""
        current_app = self.get_current_app()
        current_time = time.time()
        time_elapsed = current_time - self.last_update_time
        
        if self.current_app is not None:
            if self.current_app in self.app_data:
                self.app_data[self.current_app] += time_elapsed
            else:
                self.app_data[self.current_app] = time_elapsed
        
        self.current_app = current_app
        self.last_update_time = current_time
        
        self.update_table()
        
        if current_time % 3600 < 1:  # 大约每小时保存一次
            self.save_data()
            
    def update_table(self):
        """更新表格数据"""
        sorted_data = sorted(self.app_data.items(), key=lambda x: x[1], reverse=True)
        self.table.setRowCount(len(sorted_data))
        
        for row, (app, seconds) in enumerate(sorted_data):
            # 排名
            rank_item = QTableWidgetItem(str(row + 1))
            rank_item.setTextAlignment(Qt.AlignCenter)
            
            # 应用名称
            app_item = QTableWidgetItem(app)
            
            # 使用时长
            time_item = QTableWidgetItem(self.format_time(seconds))
            time_item.setTextAlignment(Qt.AlignRight)
            
            # 设置数据
            for item in [rank_item, app_item, time_item]:
                item.setData(Qt.UserRole, seconds)
            
            self.table.setItem(row, 0, rank_item)
            self.table.setItem(row, 1, app_item)
            self.table.setItem(row, 2, time_item)
            
            # 高亮显示当前运行应用
            if app == self.current_app:
                for col in range(3):
                    item = self.table.item(row, col)
                    item.setBackground(QColor(220, 240, 255))
                    item.setFont(QFont("Microsoft YaHei", 9, QFont.Bold))
            
            # 设置前三名样式
            if row < 3:
                for col in range(3):
                    item = self.table.item(row, col)
                    item.setBackground(QColor(255, 240, 200))
                    item.setFont(QFont("Microsoft YaHei", 9, QFont.Bold))
            
    def update_all_charts(self):
        """更新所有图表"""
        self.update_bar_chart()
        self.update_pie_chart()
        self.update_weekly_chart()
        
    def update_bar_chart(self):
        """更新条形图"""
        self.bar_figure.clear()
        ax = self.bar_figure.add_subplot(111)
        
        if not self.app_data:
            ax.text(0.5, 0.5, "暂无数据", ha='center', va='center', fontsize=12)
            self.bar_canvas.draw()
            return
        
        # 准备数据
        sorted_data = sorted(self.app_data.items(), key=lambda x: x[1], reverse=True)
        apps = [app[:15] + '...' if len(app) > 15 else app for app, _ in sorted_data]
        times = [secs / 3600 for _, secs in sorted_data]
        
        # 创建条形图
        colors = cm.viridis(np.linspace(0.2, 0.8, len(apps)))
        bars = ax.barh(np.arange(len(apps)), times, color=colors, edgecolor='none')
        
        # 设置标签
        ax.set_yticks(np.arange(len(apps)))
        ax.set_yticklabels(apps)
        
        # 添加数据标签
        for bar in bars:
            width = bar.get_width()
            ax.text(width, bar.get_y() + bar.get_height()/2,
                    f' {width:.1f}h', va='center', ha='left', fontsize=9)
        
        # 美化图表
        ax.set_xlabel('使用时长 (小时)', fontsize=11)
        ax.set_title('应用使用时长统计', fontsize=13, pad=15)
        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)
        ax.grid(True, axis='x', color='#e0e0e0', linestyle='--', alpha=0.7)
        ax.invert_yaxis()
        
        self.bar_figure.tight_layout()
        self.bar_canvas.draw()
        
    def update_pie_chart(self):
        """更新饼图"""
        self.pie_figure.clear()
        ax = self.pie_figure.add_subplot(111)
        
        if not self.app_data:
            ax.text(0.5, 0.5, "暂无数据", ha='center', va='center', fontsize=12)
            self.pie_canvas.draw()
            return
        
        # 准备数据
        sorted_data = sorted(self.app_data.items(), key=lambda x: x[1], reverse=True)
        total_time = sum(secs for _, secs in sorted_data)
        app_percentages = [(app, (secs/total_time)*100) for app, secs in sorted_data]
        
        # 分离主要应用和其他应用
        main_apps = [item for item in app_percentages if item[1] >= 5]
        other_apps = [item for item in app_percentages if item[1] < 5]
        other_time = sum(secs for _, secs in sorted_data if (secs/total_time)*100 < 5)
        
        if other_apps:
            labels = [app for app, _ in main_apps] + ["其他"]
            sizes = [secs for _, secs in sorted_data if (secs/total_time)*100 >= 5] + [other_time]
        else:
            labels = [app for app, _ in main_apps]
            sizes = [secs for _, secs in sorted_data]
        
        # 限制标签长度
        labels = [label[:12] + '...' if len(label) > 12 else label for label in labels]
        percentages = [(size/total_time)*100 for size in sizes]
        
        # 创建饼图
        colors = cm.plasma(np.linspace(0.2, 0.8, len(labels)))
        font = FontProperties(size=9)
        
        wedges, texts, autotexts = ax.pie(
            sizes,
            labels=labels,
            colors=colors,
            autopct=lambda p: f'{p:.1f}%' if p >= 5 else '',
            startangle=90,
            wedgeprops={'linewidth': 1, 'edgecolor': 'white'},
            textprops={'fontproperties': font},
            pctdistance=0.85,
            labeldistance=1.05
        )
        
        # 添加中心总时长
        ax.text(0, 0, f"总时长\n{self.format_time(total_time)}", 
                ha='center', va='center', fontsize=11)
        
        # 添加图例和标题
        ax.set_title('应用使用时长占比 (≥5%显示)', fontsize=13, pad=15)
        legend_labels = [f"{label} ({p:.1f}%)" for label, p in zip(labels, percentages)]
        ax.legend(wedges, legend_labels,
                 title="应用列表",
                 loc="center left",
                 bbox_to_anchor=(1, 0, 0.5, 1),
                 frameon=False,
                 prop=font)
        
        self.pie_figure.tight_layout()
        self.pie_canvas.draw()
        
    def update_weekly_chart(self):
        """更新周统计柱状图"""
        self.weekly_figure.clear()
        ax = self.weekly_figure.add_subplot(111)
        
        # 获取最近7天的日期
        today = datetime.now().date()
        dates = [(today - timedelta(days=i)).strftime("%m-%d") for i in range(6, -1, -1)]
        full_dates = [(today - timedelta(days=i)).strftime("%Y-%m-%d") for i in range(6, -1, -1)]
        
        # 收集所有应用名称
        all_apps = set()
        weekly_data = {}
        for date in full_dates:
            daily_data = self.load_daily_data(date)
            if daily_data:
                weekly_data[date] = daily_data
                all_apps.update(daily_data.keys())
        
        if not all_apps:
            ax.text(0.5, 0.5, "暂无周数据", ha='center', va='center', fontsize=12)
            self.weekly_canvas.draw()
            return
        
        # 选择前5个最常用的应用
        app_total_time = {app: 0 for app in all_apps}
        for date in full_dates:
            if date in weekly_data:
                for app, secs in weekly_data[date].items():
                    app_total_time[app] += secs
        
        top_apps = sorted(app_total_time.items(), key=lambda x: x[1], reverse=True)[:5]
        top_apps = [app for app, _ in top_apps]
        
        # 准备柱状图数据
        bar_width = 0.15
        x = np.arange(len(dates))
        
        # 创建颜色映射
        colors = cm.viridis(np.linspace(0.2, 0.8, len(top_apps)))
        
        # 绘制每个应用的柱状图
        for i, app in enumerate(top_apps):
            app_times = []
            for date in full_dates:
                if date in weekly_data and app in weekly_data[date]:
                    app_times.append(weekly_data[date][app] / 3600)  # 转换为小时
                else:
                    app_times.append(0)
            
            ax.bar(x + i*bar_width, app_times, bar_width, 
                  label=app[:12] + '...' if len(app) > 12 else app,
                  color=colors[i])
        
        # 设置x轴标签
        ax.set_xticks(x + bar_width * (len(top_apps)-1)/2)
        ax.set_xticklabels(dates)
        
        # 美化图表
        ax.set_xlabel('日期', fontsize=11)
        ax.set_ylabel('使用时长 (小时)', fontsize=11)
        ax.set_title('近七日应用使用时长趋势 (Top 5应用)', fontsize=13, pad=15)
        ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
        ax.grid(True, axis='y', color='#e0e0e0', linestyle='--', alpha=0.7)
        
        self.weekly_figure.tight_layout()
        self.weekly_canvas.draw()
        
    def format_time(self, seconds):
        """将秒数格式化为 HH:MM:SS"""
        hours = int(seconds // 3600)
        minutes = int((seconds % 3600) // 60)
        seconds = int(seconds % 60)
        return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
        
    def load_data(self):
        """加载保存的数据"""
        try:
            if os.path.exists(self.data_file):
                with open(self.data_file, "r", encoding='utf-8') as f:
                    self.app_data = {k: float(v) for k, v in json.load(f).items()}
        except (FileNotFoundError, json.JSONDecodeError, ValueError) as e:
            print(f"加载数据出错: {e}")
            self.app_data = {}
            
    def save_data(self):
        """保存当前数据"""
        try:
            with open(self.data_file, "w", encoding='utf-8') as f:
                json.dump(self.app_data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            print(f"保存数据出错: {e}")
            
    def load_daily_data(self, date):
        """加载指定日期的数据"""
        filename = os.path.join(self.data_dir, f"app_usage_{date}.json")
        try:
            if os.path.exists(filename):
                with open(filename, "r", encoding='utf-8') as f:
                    return json.load(f)
        except (FileNotFoundError, json.JSONDecodeError) as e:
            print(f"加载每日数据出错: {e}")
        return None
            
    def save_weekly_data(self):
        """每周数据保存"""
        today = datetime.now().date().strftime("%Y-%m-%d")
        filename = os.path.join(self.data_dir, f"app_usage_{today}.json")
        
        try:
            with open(filename, "w", encoding='utf-8') as f:
                json.dump(self.app_data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            print(f"保存每周数据出错: {e}")
        
        self.app_data = {}
        self.current_app = self.get_current_app()
        self.last_update_time = time.time()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setApplicationName("应用使用时长统计")
    app.setApplicationDisplayName("📊 应用使用时长统计")
    
    tracker = AppUsageTracker()
    tracker.show()
    sys.exit(app.exec_())


## 🎯 深度优化建议

### 性能提升方向

1. **数据压缩**:对长期存储的JSON数据进行gzip压缩
2. **增量更新**:改用SQLite替代JSON文件存储
3. **采样优化**:动态调整监控频率(活跃时高频,闲置时低频)

### 功能扩展

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/fdaac986aa20466b90e19ba6cc70a781.png)


### 用户体验改进

- 添加主题切换功能
- 支持导出CSV/PDF报告
- 增加数据筛选功能

## 💡 总结与展望

这款应用时长统计工具通过:

1. **精准监控**:秒级采集精度
2. **直观可视化**:专业级图表呈现
3. **无感运行**:完善的托盘管理
4. **数据持久化**:双重备份机制

实现了对数字生活习惯的全方位分析。特别适合:

- 自由职业者时间管理
- 家长监控儿童设备使用
- 程序员分析开发效率

**未来演进路线**:

- 移动端配套应用
- 浏览器插件集成
- AI使用建议功能

------

> 📌 **版权声明**:本文代码采用MIT开源协议,转载请注明出处。如需商业使用请联系作者授权。
>
> **互动区**:你的数字生活时间分配合理吗?欢迎在评论区分享你的使用体验和改进建议!

网站公告

今日签到

点亮在社区的每一天
去签到