| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- """
- 每日提醒工具 - 晚上11:30弹出人物提醒写日报
- 显示美化窗口
- """
- import sys
- import os
- import subprocess
- from pathlib import Path
- from datetime import datetime
- # 设置控制台编码为UTF-8(Windows)
- if sys.platform == 'win32':
- import io
- sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
- sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
- try:
- import tkinter as tk
- from tkinter import messagebox
- TKINTER_AVAILABLE = True
- except ImportError:
- TKINTER_AVAILABLE = False
- print("❌ 错误: tkinter 未安装(Python应该自带tkinter)")
- try:
- from PIL import Image, ImageTk
- PIL_AVAILABLE = True
- except ImportError:
- PIL_AVAILABLE = False
- print("⚠️ 警告: Pillow 未安装,无法显示图片")
- print("💡 请运行: pip install Pillow")
- class DailyReminder:
- def __init__(self, base_dir=None):
- self.base_dir = base_dir or Path(__file__).parent
- self.window = None
- self.canvas = None
- self.photo = None
- self.original_image = None
-
- # 窗口设置
- self.window_width = 160
- self.window_height = 160
- self.image_size = (150, 150) # 图片大小适配窗口
-
- def load_image(self):
- """加载人物图片"""
- # 尝试多种可能的图片路径和格式
- image_paths = [
- self.base_dir / "assets" / "person.png",
- self.base_dir / "assets" / "person.jpg",
- self.base_dir / "assets" / "person.jpeg",
- self.base_dir / "assets" / "reminder.png",
- self.base_dir / "assets" / "reminder.jpg",
- ]
-
- for img_path in image_paths:
- if img_path.exists():
- try:
- img = Image.open(img_path)
- # 转换为RGBA模式以支持透明背景
- if img.mode != 'RGBA':
- img = img.convert('RGBA')
- # 调整图片大小
- img = img.resize(self.image_size, Image.Resampling.LANCZOS)
- self.original_image = img
- return True
- except Exception as e:
- print(f"⚠️ 加载图片失败 {img_path}: {e}")
- continue
-
- print("❌ 未找到人物图片文件")
- print("💡 请将图片放在 assets/ 目录下,命名为 person.png 或 person.jpg")
- return False
-
- def show_reminder(self):
- """显示提醒窗口"""
- if not TKINTER_AVAILABLE:
- self.show_system_notification()
- return
-
- if not PIL_AVAILABLE:
- try:
- messagebox.showerror("错误", "Pillow 未安装,无法显示图片\n请运行: pip install Pillow")
- except:
- print("❌ 错误: Pillow 未安装,无法显示图片\n💡 请运行: pip install Pillow")
- return
-
- if not self.load_image():
- try:
- messagebox.showerror("错误", "未找到人物图片文件\n请将图片放在 assets/ 目录下\n支持的名称: person.png, person.jpg, reminder.png")
- except:
- print("❌ 错误: 未找到人物图片文件\n💡 请将图片放在 assets/ 目录下")
- return
-
- # 创建主窗口
- self.window = tk.Toplevel()
- self.window.title("📝 写日报提醒")
-
- # 设置窗口属性
- self.window.attributes('-topmost', True) # 置顶
- self.window.attributes('-alpha', 0.95) # 半透明
-
- # 移除窗口边框(可选,创建无边框窗口)
- # self.window.overrideredirect(True)
-
- # 计算窗口位置(屏幕右下角)
- screen_width = self.window.winfo_screenwidth()
- screen_height = self.window.winfo_screenheight()
- x = screen_width - self.window_width - 20 # 距离右边20像素
- y = screen_height - self.window_height - 60 # 距离底部60像素(留出任务栏空间)
-
- self.window.geometry(f"{self.window_width}x{self.window_height}+{x}+{y}")
-
- # 设置窗口背景色
- self.window.configure(bg='#f0f0f0')
-
- # 创建画布
- self.canvas = tk.Canvas(
- self.window,
- width=self.window_width,
- height=self.window_height,
- bg='#f0f0f0',
- highlightthickness=0
- )
- self.canvas.pack(fill=tk.BOTH, expand=True)
-
- # 显示图片
- self.update_image()
-
- # 绑定点击事件
- self.canvas.bind('<Button-1>', self.on_click)
- self.window.bind('<Button-1>', self.on_click)
-
- # 淡入动画
- self.fade_in()
-
- # 窗口关闭事件
- self.window.protocol("WM_DELETE_WINDOW", self.on_close)
-
- def update_image(self):
- """更新显示的图片"""
- if not self.original_image:
- return
-
- # 转换为PhotoImage
- self.photo = ImageTk.PhotoImage(self.original_image)
-
- # 清除画布并重新绘制
- self.canvas.delete("image")
- x = (self.window_width - self.image_size[0]) // 2
- y = (self.window_height - self.image_size[1]) // 2 # 居中显示
- self.canvas.create_image(x, y, anchor=tk.NW, image=self.photo, tags="image")
-
- def fade_in(self):
- """淡入动画"""
- if not self.window:
- return
-
- alpha = 0.0
- step = 0.05
-
- def fade():
- nonlocal alpha
- if alpha < 0.95:
- alpha += step
- self.window.attributes('-alpha', alpha)
- self.window.after(20, fade)
-
- fade()
-
- def on_click(self, event=None):
- """点击事件处理"""
- self.on_close()
- self.start_write_report()
-
- def on_close(self):
- """关闭窗口"""
- # 淡出动画
- if self.window:
- alpha = 0.95
- def fade_out():
- nonlocal alpha
- if alpha > 0:
- alpha -= 0.1
- try:
- self.window.attributes('-alpha', alpha)
- self.window.after(30, fade_out)
- except:
- pass
- else:
- if self.window:
- self.window.destroy()
- fade_out()
-
- def start_write_report(self):
- """启动写日报"""
- try:
- write_report_script = self.base_dir / "write_report.py"
- if not write_report_script.exists():
- error_msg = f"未找到 write_report.py\n路径: {write_report_script}"
- try:
- messagebox.showerror("错误", error_msg)
- except:
- print(f"❌ {error_msg}")
- return
-
- # 使用subprocess启动写日报脚本,并传递--daily参数
- python_exe = sys.executable
- subprocess.Popen(
- [python_exe, str(write_report_script), "--daily"],
- cwd=str(self.base_dir),
- creationflags=subprocess.CREATE_NEW_CONSOLE if sys.platform == 'win32' else 0
- )
- except Exception as e:
- error_msg = f"启动写日报失败: {e}"
- try:
- messagebox.showerror("错误", error_msg)
- except:
- print(f"❌ {error_msg}")
-
- def show_system_notification(self):
- """显示系统通知(备选方案)"""
- try:
- from plyer import notification
- notification.notify(
- title="📝 写日报提醒",
- message="该写日报啦!点击通知打开写日报。",
- timeout=10
- )
- except:
- print("📝 写日报提醒:该写日报啦!")
- def main():
- """主函数"""
- base_dir = Path(__file__).parent
-
- # 检查今天是否已经提醒过(可选功能)
- # 这里可以添加检查逻辑,避免重复提醒
-
- reminder = DailyReminder(base_dir)
- reminder.show_reminder()
-
- # 运行tkinter主循环
- if TKINTER_AVAILABLE:
- root = tk.Tk()
- root.withdraw() # 隐藏主窗口
- root.mainloop()
- if __name__ == "__main__":
- main()
|