一个自动切换壁纸的python程序
豆包AI写的,想显示图标需要在项目目录下放置图片img.png
可以使用pyinstaller打包成单文件程序pyinstaller -F -w -i img.png wallpaper.py
python
import tkinter as tk
from tkinter import filedialog, messagebox
import ctypes
import os
import sys
import time
import threading
import random
from pathlib import Path
import json
import pystray
from PIL import Image
import winreg
# Windows设置壁纸API
SPI_SETDESKWALLPAPER = 0x0014
SPIF_UPDATEINIFILE = 0x01
SPIF_SENDCHANGE = 0x02
# 全局控制变量
is_running = False
thread = None
img_list = []
current_idx = 0
tray_icon = None
def set_wallpaper(image_path):
if not os.path.exists(image_path):
return False
ctypes.windll.user32.SystemParametersInfoW(
SPI_SETDESKWALLPAPER, 0, image_path,
SPIF_UPDATEINIFILE | SPIF_SENDCHANGE
)
return True
def load_img_folder(folder_path):
global img_list, current_idx
img_suffix = [".jpg", ".jpeg", ".png", ".bmp"]
img_list.clear()
current_idx = 0
if not os.path.isdir(folder_path):
return False
for file in os.listdir(folder_path):
suf = Path(file).suffix.lower()
if suf in img_suffix:
img_list.append(os.path.join(folder_path, file))
return len(img_list) > 0
def loop_change_wallpaper(folder, interval, is_random):
global is_running, current_idx
if not load_img_folder(folder):
messagebox.showerror("错误", "文件夹内没有找到图片!")
is_running = False
return
while is_running:
if is_random:
target_img = random.choice(img_list)
else:
if current_idx >= len(img_list):
current_idx = 0
target_img = img_list[current_idx]
current_idx += 1
set_wallpaper(target_img)
time.sleep(interval)
def select_folder():
path = filedialog.askdirectory(title="选择壁纸图片文件夹")
if path:
entry_folder.delete(0, tk.END)
entry_folder.insert(0, path)
def start_task():
global is_running, thread
if is_running:
messagebox.showinfo("提示", "已经在运行中!")
return
folder = entry_folder.get().strip()
time_str = entry_time.get().strip()
random_mode = random_var.get()
with open('config.json', 'w', encoding='utf-8') as f:
json.dump({
"folder": folder,
"time_str": time_str,
"random": random_mode
}, f)
if not folder or not os.path.isdir(folder):
messagebox.showerror("错误", "请选择有效的图片文件夹!")
return
try:
interval = int(time_str)
if interval < 1:
messagebox.showerror("错误", "间隔时间必须大于0秒!")
return
except ValueError:
messagebox.showerror("错误", "请输入合法数字!")
return
is_running = True
thread = threading.Thread(target=loop_change_wallpaper, args=(folder, interval, random_mode))
thread.daemon = True
thread.start()
label_status.config(text="状态:运行中", fg="green")
def stop_task():
global is_running
is_running = False
label_status.config(text="状态:已停止", fg="red")
# ==================== 开机自启功能 ====================
def set_startup(enable):
key = winreg.HKEY_CURRENT_USER
key_path = r"Software\Microsoft\Windows\CurrentVersion\Run"
app_name = "自动壁纸轮换工具"
exe_path = os.path.abspath(sys.argv[0])
try:
with winreg.OpenKey(key, key_path, 0, winreg.KEY_WRITE) as reg:
if enable:
winreg.SetValueEx(reg, app_name, 0, winreg.REG_SZ, exe_path)
messagebox.showinfo("成功", "✅ 已设置开机自动启动")
else:
try:
winreg.DeleteValue(reg, app_name)
messagebox.showinfo("成功", "❌ 已取消开机自动启动")
except FileNotFoundError:
messagebox.showinfo("提示", "未设置过开机启动")
except Exception as e:
messagebox.showerror("错误", f"设置失败:{str(e)}")
# ==================== 托盘图标功能 ====================
def show_window():
root.deiconify()
root.lift()
root.focus_force()
def quit_app():
stop_task()
if tray_icon:
tray_icon.stop()
os._exit(0)
def next_wallpaper():
global current_idx
folder = entry_folder.get().strip()
random_mode = random_var.get()
if not img_list:
load_img_folder(folder)
if img_list:
if random_mode:
target = random.choice(img_list)
else:
current_idx = (current_idx + 1) % len(img_list)
target = img_list[current_idx]
set_wallpaper(target)
def load_tray_icon():
try:
return Image.open("img.png")
except:
return Image.new("RGB", (32, 32), (70, 70, 70))
def setup_tray():
global tray_icon
icon_img = load_tray_icon()
menu = pystray.Menu(
pystray.MenuItem("显示主界面", show_window),
pystray.MenuItem("立即切换", next_wallpaper),
pystray.MenuItem("退出", quit_app)
)
tray_icon = pystray.Icon("WallpaperTool", icon_img, "自动壁纸轮换", menu=menu)
tray_icon.on_left_click = lambda _, __: show_window()
tray_icon.run()
def hide_to_tray():
root.withdraw()
# ==================== 配置 & 界面 ====================
if os.path.exists('config.json'):
with open('config.json', 'r', encoding='utf-8') as f:
config = json.load(f)
else:
config = {"folder": "", "time_str": '30', "random": False}
root = tk.Tk()
root.title("自动壁纸轮换工具")
root.geometry("450x320")
root.resizable(False, False)
root.protocol("WM_DELETE_WINDOW", hide_to_tray)
root.bind("<Unmap>", lambda e: hide_to_tray() if root.state() == "iconic" else None)
# 界面布局
tk.Label(root, text="图片文件夹:").place(x=20, y=30)
entry_folder = tk.Entry(root, width=30)
entry_folder.place(x=110, y=30)
entry_folder.insert(0, config.get("folder", ""))
tk.Button(root, text="选择目录", command=select_folder).place(x=360, y=28)
tk.Label(root, text="轮换间隔(秒):").place(x=20, y=80)
entry_time = tk.Entry(root, width=30)
entry_time.place(x=110, y=80)
entry_time.insert(0, config.get("time_str", "30"))
tk.Label(root, text="轮播模式:").place(x=20, y=130)
random_var = tk.BooleanVar(value=config.get("random", False))
tk.Radiobutton(root, text="顺序轮播", variable=random_var, value=False).place(x=110, y=130)
tk.Radiobutton(root, text="随机轮播", variable=random_var, value=True).place(x=220, y=130)
tk.Button(root, text="开始轮换", width=12, height=2, command=start_task).place(x=80, y=180)
tk.Button(root, text="停止轮换", width=12, height=2, command=stop_task).place(x=220, y=180)
# 开机自启按钮
tk.Button(root, text="开机自动启动", width=12, height=1, command=lambda: set_startup(True)).place(x=80, y=230)
tk.Button(root, text="取消开机启动", width=12, height=1, command=lambda: set_startup(False)).place(x=220, y=230)
label_status = tk.Label(root, text="状态:未启动", fg="gray")
label_status.place(x=180, y=290)
# 启动托盘
tray_thread = threading.Thread(target=setup_tray, daemon=True)
tray_thread.start()
root.mainloop()