分享一个定时重启电脑小工具,用Python 写的

[复制链接]
133 |10
发表于 2025-10-31 15:52:48 | 显示全部楼层 |阅读模式
====更新====
8.15更新内容:
1.增加了关机、重启、休眠三种状态切换,三种状态定时任务互不干扰。
2.可设置程序开机自启动,附带状态提示。
3.可以选择开机时候自动运行的程序(部分应用可能是路径问题,兼容不到位。支持bat文件,可用bat文件开启)
4.优化了倒计时部分,由分钟后执行[输入框]改为 [输入框]后执行,更符合阅读体验。
5.优化了[小时]、[分钟]默认为0会导致设置0:00问题。
5.倒计时最后五秒有变色显示。
6.使用互斥锁禁止重复开启软件。
7.任务逻辑优化、UI体验还有些一时想不起哈哈自行发现吧
V2版本


ps: bat 命令 start "" "C:\Users\scr\AppData\Local\Programs\Microsoft VS Code\Code.exe"

支持文件类型



https://ghbseymour.lanzoum.com/b00od8195c
密码:52pj


=====原=====

一个定时重启电脑的小工具,可选择每日、每周、每月某个时间点自动重启电脑。

打包的时候把所有依赖的 Python 库 都打包了,所以体积可能有些大。


win10和win11都测试过,有问题可以留言讨论。
有需要可自取。

欢迎讨论优化内容。
在线查毒

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

发表于 2025-10-31 15:52:56 | 显示全部楼层
收藏了,辛苦楼主
回复

使用道具 举报

发表于 2025-10-31 15:53:42 | 显示全部楼层
[Python]  
  1. import tkinter as tk
  2. from tkinter import ttk, messagebox, filedialog
  3. import time
  4. import threading
  5. import os
  6. import subprocess
  7. import winreg
  8. import sys
  9. from datetime import datetime, timedelta
  10. import msvcrt
  11. class TimedTaskTool:
  12.     def __init__(self, root):
  13.         # 检查是否已经有实例在运行
  14.         self.check_single_instance()
  15.         self.root = root
  16.         self.root.title("定时任务工具")
  17.         self.root.geometry("500x720")  # 增加宽度以显示所有星期
  18.         self.root.resizable(False, False)
  19.         # 设置中文字体,适当缩小
  20.         self.style = ttk.Style()
  21.         self.style.configure("TLabel", font=("SimHei", 8))
  22.         self.style.configure("TRadiobutton", font=("SimHei", 8))
  23.         self.style.configure("TButton", font=("SimHei", 8))
  24.         self.style.configure("TCheckbutton", font=("SimHei", 8))
  25.         # 操作模式
  26.         self.operation_mode = tk.StringVar(value="重启")
  27.         self.create_operation_mode_frame()
  28.         # 日期设置
  29.         self.day_of_month = tk.IntVar(value=15)
  30.         self.week_days = {"周一": tk.BooleanVar(), "周二": tk.BooleanVar(),
  31.                           "周三": tk.BooleanVar(), "周四": tk.BooleanVar(),
  32.                           "周五": tk.BooleanVar(), "周六": tk.BooleanVar(),
  33.                           "周日": tk.BooleanVar()}
  34.         self.create_date_frame()
  35.         # 时间设置
  36.         self.hour = tk.IntVar(value=12)
  37.         self.minute = tk.IntVar(value=0)
  38.         self.create_time_frame()
  39.         # 任务存储 - 支持多个定时任务
  40.         self.tasks = {}
  41.         self.task_threads = {}
  42.         self.task_statuses = {}
  43.         for mode in ["重启", "关机", "休眠"]:
  44.             self.tasks[mode] = None
  45.             self.task_threads[mode] = None
  46.             self.task_statuses[mode] = tk.StringVar(value=f"{mode}任务: 未设置")
  47.         # 重复频率
  48.         self.repeat_type = tk.StringVar(value="每日")
  49.         self.create_repeat_frame()
  50.         # 倒计时操作
  51.         self.countdown_minutes = tk.IntVar(value=1)
  52.         self.countdown_status = tk.StringVar(value="未启动")
  53.         self.countdown_label = None  # 用于控制颜色
  54.         self.create_countdown_frame()
  55.         # 开机设置
  56.         self.startup_auto = tk.BooleanVar(value=False)
  57.         self.startup_program = tk.StringVar(value="未选择任何项目")
  58.         self.startup_check_var = tk.BooleanVar(value=False)
  59.         self.create_startup_frame()
  60.         # 任务按钮
  61.         self.create_task_buttons()
  62.         # 任务状态
  63.         self.create_status_label()
  64.         # 检查开机自启动状态
  65.         self.check_startup_status()
  66.     def check_single_instance(self):
  67.         # 使用文件锁实现单实例
  68.         self.lock_file = os.path.join(os.environ.get('TEMP', 'C:\\temp'), 'timed_task_tool.lock')
  69.         try:
  70.             # 尝试创建并锁定文件
  71.             self.lock = open(self.lock_file, 'w')
  72.             msvcrt.locking(self.lock.fileno(), msvcrt.LK_NBLCK, 1)
  73.         except:
  74.             messagebox.showerror("错误", "程序已经在运行中!")
  75.             sys.exit(1)
  76.     def create_operation_mode_frame(self):
  77.         frame = ttk.LabelFrame(self.root, text="操作模式", padding="10")
  78.         frame.pack(fill="x", padx=10, pady=5)
  79.         ttk.Radiobutton(frame, text="重启", variable=self.operation_mode, value="重启").pack(side="left", padx=3)
  80.         ttk.Radiobutton(frame, text="关机", variable=self.operation_mode, value="关机").pack(side="left", padx=3)
  81.         ttk.Radiobutton(frame, text="休眠", variable=self.operation_mode, value="休眠").pack(side="left", padx=3)
  82.     def create_date_frame(self):
  83.         frame = ttk.LabelFrame(self.root, text="日期设置", padding="10")
  84.         frame.pack(fill="x", padx=10, pady=5)
  85.         ttk.Label(frame, text="每月几号: ").grid(row=0, column=0, padx=5, pady=5)
  86.         day_spinbox = ttk.Spinbox(frame, from_=1, to=31, textvariable=self.day_of_month, width=5)
  87.         day_spinbox.grid(row=0, column=1, padx=5, pady=5)
  88.         ttk.Label(frame, text="(设置每月的操作日期,自动处理月份天数差异)").grid(row=0, column=2, padx=5, pady=5, sticky="w")
  89.         # 创建一个水平框架来放置星期选择,不使用网格布局
  90.         ttk.Label(frame, text="每周几: ").grid(row=1, column=0, padx=5, pady=2, sticky="w")
  91.         
  92.         days_frame = ttk.Frame(frame)
  93.         days_frame.grid(row=1, column=1, columnspan=6, sticky="w")
  94.         
  95.         days_order = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
  96.         
  97.         # 所有星期放在同一行显示
  98.         for day in days_order:
  99.             # 使用pack布局,水平排列
  100.             ttk.Checkbutton(days_frame, text=day, variable=self.week_days[day]).pack(side="left", padx=3, pady=2)
  101.     def create_time_frame(self):
  102.         frame = ttk.LabelFrame(self.root, text="操作时间设置 (24小时制)", padding="10")
  103.         frame.pack(fill="x", padx=10, pady=5)
  104.         ttk.Label(frame, text="小时: ").grid(row=0, column=0, padx=3, pady=3)
  105.         hour_spinbox = ttk.Spinbox(frame, from_=0, to=23, textvariable=self.hour, width=4)
  106.         hour_spinbox.grid(row=0, column=1, padx=3, pady=3)
  107.         ttk.Label(frame, text="分钟: ").grid(row=0, column=2, padx=3, pady=3)
  108.         minute_spinbox = ttk.Spinbox(frame, from_=0, to=59, textvariable=self.minute, width=4)
  109.         minute_spinbox.grid(row=0, column=3, padx=3, pady=3)
  110.     def create_repeat_frame(self):
  111.         frame = ttk.LabelFrame(self.root, text="重复频率", padding="10")
  112.         frame.pack(fill="x", padx=10, pady=5)
  113.         ttk.Radiobutton(frame, text="每日", variable=self.repeat_type, value="每日").pack(side="left", padx=3)
  114.         ttk.Radiobutton(frame, text="每周", variable=self.repeat_type, value="每周").pack(side="left", padx=3)
  115.         ttk.Radiobutton(frame, text="每月", variable=self.repeat_type, value="每月").pack(side="left", padx=3)
  116.     def create_countdown_frame(self):
  117.         frame = ttk.LabelFrame(self.root, text="倒计时操作", padding="10")
  118.         frame.pack(fill="x", padx=10, pady=5)
  119.         minute_spinbox = ttk.Spinbox(frame, from_=1, to=1440, textvariable=self.countdown_minutes, width=4)
  120.         minute_spinbox.grid(row=0, column=0, padx=3, pady=3)
  121.         ttk.Label(frame, text="后执行操作").grid(row=0, column=1, padx=3, pady=3)
  122.         self.countdown_label = ttk.Label(frame, textvariable=self.countdown_status, foreground="blue", width=10)
  123.         self.countdown_label.grid(row=0, column=2, padx=3, pady=3)
  124.         ttk.Button(frame, text="开始", command=self.start_countdown, width=6).grid(row=0, column=3, padx=2, pady=3)
  125.         ttk.Button(frame, text="取消", command=self.cancel_countdown, width=6).grid(row=0, column=4, padx=2, pady=3)
  126.     def create_startup_frame(self):
  127.         frame = ttk.LabelFrame(self.root, text="开机设置", padding="10")
  128.         frame.pack(fill="x", padx=10, pady=5)
  129.         self.startup_status_label = ttk.Label(frame, text="未开启", foreground="red", width=6)
  130.         ttk.Checkbutton(frame, text="程序开机自启动: ", variable=self.startup_auto, command=self.toggle_startup).grid(row=0, column=0, padx=3, pady=3, sticky="w")
  131.         self.startup_status_label.grid(row=0, column=1, padx=2, pady=3)
  132.         self.startup_check_var = tk.BooleanVar(value=False)
  133.         ttk.Checkbutton(frame, text="开机后自动运行: ", variable=self.startup_check_var).grid(row=1, column=0, padx=3, pady=3, sticky="w")
  134.         ttk.Label(frame, textvariable=self.startup_program, width=15).grid(row=1, column=1, padx=2, pady=3, sticky="w")
  135.         ttk.Button(frame, text="浏览...", command=self.browse_program, width=6).grid(row=1, column=2, padx=2, pady=3)
  136.     def create_task_buttons(self):
  137.         frame = ttk.Frame(self.root, padding="10")
  138.         frame.pack(fill="x", padx=10, pady=5)
  139.         ttk.Button(frame, text="设置定时任务", command=self.set_timed_task, width=10).pack(side="left", padx=5, pady=3)
  140.         ttk.Button(frame, text="取消定时任务", command=self.cancel_timed_task, width=10).pack(side="right", padx=5, pady=3)
  141.     def create_status_label(self):
  142.         frame = ttk.LabelFrame(self.root, text="系统状态", padding="10")
  143.         frame.pack(fill="x", padx=10, pady=5)
  144.         # 添加当前时间显示
  145.         self.current_time_var = tk.StringVar()
  146.         ttk.Label(frame, textvariable=self.current_time_var, foreground="gray").grid(row=0, column=0, padx=3, pady=1, sticky="w")
  147.         # 任务状态显示
  148.         status_frame = ttk.Frame(frame)
  149.         status_frame.grid(row=1, column=0, columnspan=3, sticky="ew", pady=2)
  150.         for i, mode in enumerate(["重启", "关机", "休眠"]):
  151.             ttk.Label(status_frame, textvariable=self.task_statuses[mode], foreground="blue").grid(row=0, column=i, padx=5, pady=1, sticky="w")
  152.         # 程序状态显示
  153.         self.program_status_var = tk.StringVar(value="程序运行正常")
  154.         ttk.Label(frame, textvariable=self.program_status_var, foreground="green").grid(row=2, column=0, padx=3, pady=1, sticky="w")
  155.         # 更新时间的函数
  156.         def update_time():
  157.             current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  158.             self.current_time_var.set(f"当前时间: {current_time}")
  159.             # 每秒更新一次
  160.             self.root.after(1000, update_time)
  161.         # 启动时间更新
  162.         update_time()
  163.     def check_startup_status(self):
  164.         try:
  165.             key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Run', 0, winreg.KEY_READ)
  166.             value, _ = winreg.QueryValueEx(key, 'TimedTaskTool')
  167.             winreg.CloseKey(key)
  168.             self.startup_auto.set(True)
  169.             self.startup_status_label.config(text="已开启", foreground="green")
  170.         except:
  171.             self.startup_auto.set(False)
  172.             self.startup_status_label.config(text="未开启", foreground="red")
  173.     def toggle_startup(self):
  174.         try:
  175.             if self.startup_auto.get():
  176.                 # 开启开机自启动
  177.                 key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Run', 0, winreg.KEY_WRITE)
  178.                 winreg.SetValueEx(key, 'TimedTaskTool', 0, winreg.REG_SZ, sys.executable)
  179.                 winreg.CloseKey(key)
  180.                 self.startup_status_label.config(text="已开启", foreground="green")
  181.             else:
  182.                 # 关闭开机自启动
  183.                 try:
  184.                     key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Run', 0, winreg.KEY_WRITE)
  185.                     winreg.DeleteValue(key, 'TimedTaskTool')
  186.                     winreg.CloseKey(key)
  187.                     self.startup_status_label.config(text="未开启", foreground="red")
  188.                 except FileNotFoundError:
  189.                     # 如果值不存在,依旧显示未开启
  190.                     self.startup_status_label.config(text="未开启", foreground="red")
  191.         except Exception as e:
  192.             messagebox.showerror("错误", f"设置开机自启动失败: {str(e)}")
  193.     def browse_program(self):
  194.         filename = filedialog.askopenfilename(title="选择程序", filetypes=[("所有文件", "*.*")])
  195.         if filename:
  196.             self.startup_program.set(filename)
  197.     def start_countdown(self):
  198.         minutes = self.countdown_minutes.get()
  199.         seconds = minutes * 60
  200.         self.countdown_status.set(f"倒计时中 ({minutes}分钟)")
  201.         self.countdown_label.config(foreground="blue")
  202.         self.root.update()
  203.         # 创建倒计时线程
  204.         def countdown():
  205.             for i in range(seconds, 0, -1):
  206.                 minutes_left = i // 60
  207.                 seconds_left = i % 60
  208.                
  209.                 # 最后5秒变红
  210.                 if i <= 5:
  211.                     self.countdown_label.config(foreground="red")
  212.                     self.countdown_status.set(f"即将执行 ({seconds_left}秒)")
  213.                 else:
  214.                     self.countdown_status.set(f"倒计时中 ({minutes_left}分{seconds_left}秒)")
  215.                
  216.                 time.sleep(1)
  217.                 if self.countdown_status.get().startswith("未启动"):
  218.                     break
  219.             
  220.             if not self.countdown_status.get().startswith("未启动"):
  221.                 self.countdown_status.set("执行中...")
  222.                 self.execute_operation()
  223.                 self.countdown_label.config(foreground="blue")
  224.                 self.countdown_status.set("未启动")
  225.         
  226.         threading.Thread(target=countdown, daemon=True).start()
  227.     def cancel_countdown(self):
  228.         self.countdown_status.set("未启动")
  229.         self.countdown_label.config(foreground="blue")
  230.     def set_timed_task(self):
  231.         # 获取设置
  232.         operation = self.operation_mode.get()
  233.         hour = self.hour.get()
  234.         minute = self.minute.get()
  235.         repeat_type = self.repeat_type.get()
  236.         # 验证设置
  237.         if repeat_type == "每周":
  238.             selected_days = [day for day, var in self.week_days.items() if var.get()]
  239.             if not selected_days:
  240.                 messagebox.showerror("错误", "请选择每周的至少一天")
  241.                 return
  242.         # 取消该操作模式的现有任务
  243.         self.cancel_timed_task(operation)
  244.         # 创建新任务
  245.         self.tasks[operation] = {"hour": hour, "minute": minute, "repeat_type": repeat_type}
  246.         self.task_threads[operation] = threading.Thread(
  247.             target=self.task_runner,
  248.             args=(operation, hour, minute, repeat_type),
  249.             daemon=True
  250.         )
  251.         self.task_threads[operation].start()
  252.         # 更新状态
  253.         if repeat_type == "每日":
  254.             status = f"每日 {hour:02d}:{minute:02d} 执行"
  255.         elif repeat_type == "每周":
  256.             selected_days = [day for day, var in self.week_days.items() if var.get()]
  257.             days_str = ", ".join(selected_days)
  258.             status = f"每周 {days_str} {hour:02d}:{minute:02d} 执行"
  259.         else:  # 每月
  260.             status = f"每月 {self.day_of_month.get()}号 {hour:02d}:{minute:02d} 执行"
  261.         self.task_statuses[operation].set(f"{operation}任务: 已设置 ({status})")
  262.         messagebox.showinfo("成功", f"{operation}定时任务已设置:\n{status}")
  263.     def cancel_timed_task(self, operation=None):
  264.         if operation:
  265.             # 取消特定操作的任务
  266.             if self.task_threads[operation] and self.task_threads[operation].is_alive():
  267.                 # 通知线程结束
  268.                 self.tasks[operation] = None
  269.                 self.task_threads[operation].join(1)  # 等待线程结束,最多等待1秒
  270.                 self.task_threads[operation] = None
  271.             self.task_statuses[operation].set(f"{operation}任务: 未设置")
  272.         else:
  273.             # 取消所有任务
  274.             for mode in ["重启", "关机", "休眠"]:
  275.                 self.cancel_timed_task(mode)
  276.     def task_runner(self, operation, hour, minute, repeat_type):
  277.         while True:
  278.             # 检查任务是否已被取消
  279.             if self.tasks[operation] is None:
  280.                 break
  281.             try:
  282.                 now = datetime.now()
  283.                 target_time = now.replace(hour=hour, minute=minute, second=0, microsecond=0)
  284.                 # 如果今天的目标时间已过,则设置为明天
  285.                 if target_time <= now:
  286.                     target_time += timedelta(days=1)
  287.                 # 计算等待时间
  288.                 wait_time = (target_time - now).total_seconds()
  289.                 # 等待到目标时间,每秒检查一次任务是否已取消
  290.                 wait_done = True
  291.                 for _ in range(int(wait_time // 1)):
  292.                     if self.tasks[operation] is None:
  293.                         wait_done = False
  294.                         break
  295.                     time.sleep(1)
  296.                 # 检查是否需要执行
  297.                 if wait_done and self.tasks[operation] is not None:
  298.                     # 更新当前时间
  299.                     now = datetime.now()
  300.                     
  301.                     # 根据重复类型检查是否应该执行
  302.                     should_execute = False
  303.                     if repeat_type == "每日":
  304.                         should_execute = True
  305.                     elif repeat_type == "每周":
  306.                         weekday = now.weekday()  # 0=周一, 6=周日
  307.                         weekdays_map = {"周一": 0, "周二": 1, "周三": 2, "周四": 3, "周五": 4, "周六": 5, "周日": 6}
  308.                         selected_days = [weekdays_map[day] for day, var in self.week_days.items() if var.get()]
  309.                         should_execute = weekday in selected_days
  310.                     elif repeat_type == "每月":
  311.                         # 处理月份天数差异
  312.                         day_of_month = self.day_of_month.get()
  313.                         last_day = (now.replace(day=28) + timedelta(days=4)).replace(day=1) - timedelta(days=1)
  314.                         if day_of_month > last_day.day:
  315.                             should_execute = now.day == last_day.day
  316.                         else:
  317.                             should_execute = now.day == day_of_month
  318.                     if should_execute:
  319.                         self.execute_operation(operation)
  320.             except Exception as e:
  321.                 # 记录错误但不中断任务
  322.                 error_msg = f"任务执行错误: {str(e)}操作: {operation}"
  323.                 print(error_msg)
  324.                 # 可以选择记录到日志文件
  325.                 try:
  326.                     with open("task_error.log", "a") as f:
  327.                         f.write(f"{datetime.now()}: {error_msg}\n")
  328.                 except:
  329.                     pass
  330.                 # 短暂暂停后继续
  331.                 time.sleep(5)
  332.     def execute_operation(self, operation=None):
  333.         if operation is None:
  334.             operation = self.operation_mode.get()
  335.         try:
  336.             if operation == "重启":
  337.                 os.system("shutdown /r /t 0")
  338.             elif operation == "关机":
  339.                 os.system("shutdown /s /t 0")
  340.             elif operation == "休眠":
  341.                 # 注意:Windows休眠命令可能需要管理员权限
  342.                 os.system("rundll32.exe powrprof.dll,SetSuspendState 0,1,0")
  343.         except Exception as e:
  344.             messagebox.showerror("操作失败", f"无法执行{operation}操作: {str(e)}")
  345.             # 记录错误到日志
  346.             try:
  347.                 with open("operation_error.log", "a") as f:
  348.                     f.write(f"{datetime.now()}: 无法执行{operation}操作: {str(e)}\n")
  349.             except:
  350.                 pass
  351. def on_closing(root, app):
  352.     # 取消所有定时任务
  353.     app.cancel_timed_task()
  354.     # 释放文件锁
  355.     try:
  356.         msvcrt.locking(app.lock.fileno(), msvcrt.LK_UNLCK, 1)
  357.         app.lock.close()
  358.         os.remove(app.lock_file)
  359.     except:
  360.         pass
  361.     root.destroy()
  362. if __name__ == "__main__":
  363.     root = tk.Tk()
  364.     app = TimedTaskTool(root)
  365.     root.protocol("WM_DELETE_WINDOW", lambda: on_closing(root, app))
  366.     root.mainloop()
复制代码
回复

使用道具 举报

发表于 2025-10-31 15:54:02 | 显示全部楼层
这是定时重启操作系统吗?有没有定时重启某个应用程序
回复

使用道具 举报

发表于 2025-10-31 15:54:34 | 显示全部楼层
是的,是定时重启电脑的,可能我的叙述不太清楚,我改一下

目前没有重启某应用这个功能。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

发表于 2025-10-31 15:54:56 | 显示全部楼层
多谢支持

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

发表于 2025-10-31 15:55:36 | 显示全部楼层
用系统cmd命令也不错
回复

使用道具 举报

发表于 2025-10-31 15:55:44 | 显示全部楼层
建议你在下面增加倒计时关机和倒计时休眠,这也有用
回复

使用道具 举报

发表于 2025-10-31 15:56:42 | 显示全部楼层
感觉真是不错啊啊啊啊
回复

使用道具 举报

发表于 2025-10-31 15:57:34 | 显示全部楼层
这个不错,挺好。。定期定时。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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