Python+Qt實現(xiàn)智能應(yīng)用時長統(tǒng)計工具
概述:數(shù)字時代的時間管理者
在數(shù)字化生活日益普及的今天,我們每天與各種應(yīng)用程序的交互時間越來越長。但你是否真正了解自己的數(shù)字生活習(xí)慣?哪些應(yīng)用占用了你最多的時間?時間都花在了哪里?
今天我將介紹一款自主研發(fā)的應(yīng)用時長統(tǒng)計工具,它能夠:
- 實時監(jiān)控應(yīng)用使用情況
- 可視化展示時間分配
- 分析每周使用趨勢
- 最小化到系統(tǒng)托盤后臺運行
這款工具采用Python+Qt開發(fā),結(jié)合matplotlib實現(xiàn)專業(yè)級數(shù)據(jù)可視化,是程序員和普通用戶都能輕松使用的效率工具。

功能全景圖
核心功能矩陣
| 功能模塊 | 技術(shù)實現(xiàn) | 數(shù)據(jù)維度 |
|---|---|---|
| 實時監(jiān)控 | psutil+win32api跨平臺采集 | 秒級精度 |
| 數(shù)據(jù)持久化 | JSON序列化+按日期存儲 | 歷史數(shù)據(jù)可追溯 |
| 可視化分析 | Matplotlib+Qt5嵌入式圖表 | 多維數(shù)據(jù)呈現(xiàn) |
| 系統(tǒng)托盤 | QSystemTrayIcon | 無感后臺運行 |
| 周趨勢分析 | 時間序列聚合+堆疊柱狀圖 | 七日對比 |
技術(shù)棧亮點
- 應(yīng)用識別:Windows/MacOS/Linux三平臺兼容
- 性能優(yōu)化:定時器精準(zhǔn)控制1秒采集間隔
- 數(shù)據(jù)安全:雙重備份機制(實時+每日)
- 交互設(shè)計:標(biāo)簽頁自動刷新+表格高亮交互
效果展示
1. 實時數(shù)據(jù)看板

特點說明:
- 當(dāng)前運行應(yīng)用藍(lán)色高亮
- 使用時長TOP3金色標(biāo)識
- 實時刷新排名變化
2. 時長占比分析

智能處理:
- 自動合并<5%的小項為"其他"
- 中心顯示總時長
- 響應(yīng)式標(biāo)簽防重疊
3. 周趨勢圖譜

分析維度:
- Top5應(yīng)用每日對比
- 小時為單位直觀顯示
- 顏色編碼區(qū)分應(yīng)用
部署與使用指南
環(huán)境準(zhǔn)備
# 基礎(chǔ)依賴 pip install pyqt5 psutil matplotlib # 平臺特定依賴 # Windows pip install pywin32
使用教程
python app_usage_tracker.py
最小化到托盤:關(guān)閉窗口自動后臺運行
數(shù)據(jù)查看:
- 實時數(shù)據(jù)頁:查看當(dāng)前會話統(tǒng)計
- 圖表頁:點擊標(biāo)簽自動刷新
數(shù)據(jù)存儲:
- app_usage_data/目錄下查看歷史數(shù)據(jù)
- 每日數(shù)據(jù)自動歸檔
自定義配置
# 修改監(jiān)控頻率(毫秒) self.timer.start(1000) # 默認(rèn)1秒 # 修改數(shù)據(jù)存儲路徑 self.data_dir = "custom_data_path"
核心代碼解析
1. 應(yīng)用進(jìn)程監(jiān)控引擎
def get_current_app(self):
"""跨平臺應(yīng)用識別核心方法"""
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"應(yīng)用識別異常: {e}")
return "Unknown"
技術(shù)要點:
Windows使用win32gui獲取前臺窗口
Linux依賴xdotool工具鏈
MacOS通過AppKit接口
2. 數(shù)據(jù)可視化引擎
def update_weekly_chart(self):
"""周趨勢圖生成邏輯"""
# 1. 數(shù)據(jù)準(zhǔn)備
dates = [datetime.now().date() - timedelta(days=i) for i in range(6, -1, -1)]
# 2. Top5應(yīng)用篩選
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. 圖表美化...設(shè)計亮點:
動態(tài)數(shù)據(jù)聚合
自動響應(yīng)式布局
視覺層次分明
3. 系統(tǒng)托盤集成
def init_system_tray(self):
"""托盤圖標(biāo)管理系統(tǒng)"""
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()
交互設(shè)計:
右鍵菜單快速操作
雙擊恢復(fù)窗口
氣泡消息提示
源碼下載
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
# 設(shè)置matplotlib支持中文顯示
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 使用微軟雅黑
plt.rcParams['axes.unicode_minus'] = False # 用來正常顯示負(fù)號
class AppUsageTracker(QMainWindow):
def __init__(self):
super().__init__()
# 初始化數(shù)據(jù)
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")
# 創(chuàng)建數(shù)據(jù)目錄
os.makedirs(self.data_dir, exist_ok=True)
# 加載歷史數(shù)據(jù)
self.load_data()
# 初始化UI
self.init_ui()
# 設(shè)置系統(tǒng)托盤
self.init_system_tray()
# 設(shè)置定時器
self.timer = QTimer()
self.timer.timeout.connect(self.update_app_usage)
self.timer.start(1000) # 每秒更新一次
# 每周數(shù)據(jù)定時保存
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("?? 應(yīng)用使用時長統(tǒng)計")
self.setWindowIcon(QIcon(self.get_emoji_icon("??")))
self.setGeometry(100, 100, 1200, 800) # 增大窗口尺寸
# 主布局
main_widget = QWidget()
self.setCentralWidget(main_widget)
layout = QVBoxLayout(main_widget)
# 創(chuàng)建標(biāo)簽頁
self.tabs = QTabWidget()
self.tabs.currentChanged.connect(self.on_tab_changed)
layout.addWidget(self.tabs)
# 初始化各標(biāo)簽頁
self.init_realtime_tab()
self.init_bar_chart_tab()
self.init_pie_chart_tab()
self.init_weekly_chart_tab() # 修改為周統(tǒng)計圖表頁
# 添加工具欄
self.init_toolbar()
def on_tab_changed(self, index):
"""標(biāo)簽頁切換時自動刷新圖表"""
if index == 1: # 使用時長排行標(biāo)簽頁
self.update_bar_chart()
elif index == 2: # 使用時長占比標(biāo)簽頁
self.update_pie_chart()
elif index == 3: # 周統(tǒng)計數(shù)據(jù)標(biāo)簽頁
self.update_weekly_chart()
def init_realtime_tab(self):
"""初始化實時數(shù)據(jù)標(biāo)簽頁"""
self.realtime_tab = QWidget()
self.tabs.addTab(self.realtime_tab, "?? 實時數(shù)據(jù)")
layout = QVBoxLayout(self.realtime_tab)
# 添加標(biāo)題
title_label = QLabel("應(yīng)用使用時長實時統(tǒng)計")
title_label.setFont(QFont("Microsoft YaHei", 12, QFont.Bold))
title_label.setAlignment(Qt.AlignCenter)
title_label.setStyleSheet("padding: 10px;")
layout.addWidget(title_label)
# 創(chuàng)建表格
self.table = QTableWidget()
self.table.setColumnCount(3)
self.table.setHorizontalHeaderLabels(["排名", "應(yīng)用名稱", "使用時長"])
# 設(shè)置表格樣式
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):
"""初始化條形圖標(biāo)簽頁"""
self.bar_chart_tab = QWidget()
self.tabs.addTab(self.bar_chart_tab, "?? 使用時長排行")
layout = QVBoxLayout(self.bar_chart_tab)
# 添加標(biāo)題
title_label = QLabel("應(yīng)用使用時長排行榜")
title_label.setFont(QFont("Microsoft YaHei", 12, QFont.Bold))
title_label.setAlignment(Qt.AlignCenter)
title_label.setStyleSheet("padding: 10px;")
layout.addWidget(title_label)
# 創(chuàng)建圖表
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):
"""初始化餅圖標(biāo)簽頁"""
self.pie_chart_tab = QWidget()
self.tabs.addTab(self.pie_chart_tab, "?? 使用時長占比")
layout = QVBoxLayout(self.pie_chart_tab)
# 添加標(biāo)題
title_label = QLabel("應(yīng)用使用時長占比")
title_label.setFont(QFont("Microsoft YaHei", 12, QFont.Bold))
title_label.setAlignment(Qt.AlignCenter)
title_label.setStyleSheet("padding: 10px;")
layout.addWidget(title_label)
# 創(chuàng)建圖表
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):
"""初始化周統(tǒng)計圖表標(biāo)簽頁"""
self.weekly_chart_tab = QWidget()
self.tabs.addTab(self.weekly_chart_tab, "?? 周使用趨勢")
layout = QVBoxLayout(self.weekly_chart_tab)
# 添加標(biāo)題
title_label = QLabel("近七日應(yīng)用使用時長趨勢")
title_label.setFont(QFont("Microsoft YaHei", 12, QFont.Bold))
title_label.setAlignment(Qt.AlignCenter)
title_label.setStyleSheet("padding: 10px;")
layout.addWidget(title_label)
# 創(chuàng)建圖表
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):
"""初始化系統(tǒng)托盤"""
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):
"""托盤圖標(biāo)點擊事件處理"""
if reason == QSystemTrayIcon.DoubleClick:
self.show()
self.activateWindow()
def close_app(self):
"""退出應(yīng)用程序"""
self.save_data()
self.tray_icon.hide()
QApplication.quit()
def closeEvent(self, event):
"""重寫關(guān)閉事件,最小化到托盤"""
event.ignore()
self.hide()
self.tray_icon.showMessage(
"應(yīng)用使用時長統(tǒng)計",
"程序已最小化到系統(tǒng)托盤",
QSystemTrayIcon.Information,
2000
)
def get_emoji_icon(self, emoji):
"""將emoji轉(zhuǎn)換為圖標(biāo)"""
return emoji
def get_current_app(self):
"""獲取當(dāng)前活動窗口的應(yīng)用"""
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"
# 清理應(yīng)用名稱
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"獲取應(yīng)用名稱出錯: {e}")
return "Unknown"
def update_app_usage(self):
"""更新應(yīng)用使用時長"""
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):
"""更新表格數(shù)據(jù)"""
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)
# 應(yīng)用名稱
app_item = QTableWidgetItem(app)
# 使用時長
time_item = QTableWidgetItem(self.format_time(seconds))
time_item.setTextAlignment(Qt.AlignRight)
# 設(shè)置數(shù)據(jù)
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)
# 高亮顯示當(dāng)前運行應(yīng)用
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))
# 設(shè)置前三名樣式
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, "暫無數(shù)據(jù)", ha='center', va='center', fontsize=12)
self.bar_canvas.draw()
return
# 準(zhǔn)備數(shù)據(jù)
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]
# 創(chuàng)建條形圖
colors = cm.viridis(np.linspace(0.2, 0.8, len(apps)))
bars = ax.barh(np.arange(len(apps)), times, color=colors, edgecolor='none')
# 設(shè)置標(biāo)簽
ax.set_yticks(np.arange(len(apps)))
ax.set_yticklabels(apps)
# 添加數(shù)據(jù)標(biāo)簽
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('應(yīng)用使用時長統(tǒng)計', 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, "暫無數(shù)據(jù)", ha='center', va='center', fontsize=12)
self.pie_canvas.draw()
return
# 準(zhǔn)備數(shù)據(jù)
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]
# 分離主要應(yīng)用和其他應(yīng)用
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]
# 限制標(biāo)簽長度
labels = [label[:12] + '...' if len(label) > 12 else label for label in labels]
percentages = [(size/total_time)*100 for size in sizes]
# 創(chuàng)建餅圖
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)
# 添加圖例和標(biāo)題
ax.set_title('應(yīng)用使用時長占比 (≥5%顯示)', fontsize=13, pad=15)
legend_labels = [f"{label} ({p:.1f}%)" for label, p in zip(labels, percentages)]
ax.legend(wedges, legend_labels,
title="應(yīng)用列表",
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):
"""更新周統(tǒng)計柱狀圖"""
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)]
# 收集所有應(yīng)用名稱
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, "暫無周數(shù)據(jù)", ha='center', va='center', fontsize=12)
self.weekly_canvas.draw()
return
# 選擇前5個最常用的應(yīng)用
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]
# 準(zhǔn)備柱狀圖數(shù)據(jù)
bar_width = 0.15
x = np.arange(len(dates))
# 創(chuàng)建顏色映射
colors = cm.viridis(np.linspace(0.2, 0.8, len(top_apps)))
# 繪制每個應(yīng)用的柱狀圖
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) # 轉(zhuǎn)換為小時
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])
# 設(shè)置x軸標(biāo)簽
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('近七日應(yīng)用使用時長趨勢 (Top 5應(yīng)用)', 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):
"""將秒數(shù)格式化為 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):
"""加載保存的數(shù)據(jù)"""
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"加載數(shù)據(jù)出錯: {e}")
self.app_data = {}
def save_data(self):
"""保存當(dāng)前數(shù)據(jù)"""
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"保存數(shù)據(jù)出錯: {e}")
def load_daily_data(self, date):
"""加載指定日期的數(shù)據(jù)"""
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"加載每日數(shù)據(jù)出錯: {e}")
return None
def save_weekly_data(self):
"""每周數(shù)據(jù)保存"""
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"保存每周數(shù)據(jù)出錯: {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("應(yīng)用使用時長統(tǒng)計")
app.setApplicationDisplayName("?? 應(yīng)用使用時長統(tǒng)計")
tracker = AppUsageTracker()
tracker.show()
sys.exit(app.exec_())
深度優(yōu)化建議
性能提升方向
1. **數(shù)據(jù)壓縮**:對長期存儲的JSON數(shù)據(jù)進(jìn)行g(shù)zip壓縮
2. **增量更新**:改用SQLite替代JSON文件存儲
3. **采樣優(yōu)化**:動態(tài)調(diào)整監(jiān)控頻率(活躍時高頻,閑置時低頻)
功能擴展
用戶體驗改進(jìn)
- 添加主題切換功能
- 支持導(dǎo)出CSV/PDF報告
- 增加數(shù)據(jù)篩選功能
總結(jié)與展望
這款應(yīng)用時長統(tǒng)計工具通過:
1. **精準(zhǔn)監(jiān)控**:秒級采集精度
2. **直觀可視化**:專業(yè)級圖表呈現(xiàn)
3. **無感運行**:完善的托盤管理
4. **數(shù)據(jù)持久化**:雙重備份機制
實現(xiàn)了對數(shù)字生活習(xí)慣的全方位分析。特別適合:
- 自由職業(yè)者時間管理
- 家長監(jiān)控兒童設(shè)備使用
- 程序員分析開發(fā)效率
**未來演進(jìn)路線**:
- 移動端配套應(yīng)用
- 瀏覽器插件集成
- AI使用建議功能
以上就是Python+Qt實現(xiàn)智能應(yīng)用時長統(tǒng)計工具的詳細(xì)內(nèi)容,更多關(guān)于Python統(tǒng)計應(yīng)用時長的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
一文帶你精通Python中*args和**kwargs的應(yīng)用技巧
如果能在Python中創(chuàng)建適應(yīng)不同場景的函數(shù),而無需每次都重寫它們,會使得操作簡潔方便,這就是*args和**kwargs的魔力所在,下面我們就來看看它們的具體一些應(yīng)用技巧吧2024-03-03
關(guān)于python3的ThreadPoolExecutor線程池大小設(shè)置
這篇文章主要介紹了關(guān)于python3的ThreadPoolExecutor線程池大小設(shè)置,線程池的理想大小取決于被提交任務(wù)的類型以及所部署系統(tǒng)的特性,需要的朋友可以參考下2023-04-04

