近代史上,每一个庚子年都不寻常:1840年鸦片战争,1900年八国联军侵华,1960年大饥荒。2020年的这个春节,一场突如其来的新型冠状病毒疫情横扫东亚,大有席卷全球之势。这场无妄之灾,使得很多人放弃了聚会和旅行的计划,大家不得不蜗居于斗室。但是,病毒再猖狂,也无法阻止程序员对于美好的生活的向往。今天,我来教大家用Python做一个壁纸切换工具,展示以前旅行的照片,让桌面带我们去周游世界!
1. 用Python设置Windows壁纸
设置Windnows壁纸,需要修改Windows注册表,用Python操作Windows注册表,一般使用Pywin32模块。该模块包装了几乎所有的Windows API,可以方便地从Python直接调用。Pywin32允许你像VC一样的形式来使用Python开发win32应用,代码风格可以类似win32 sdk,也可以类似MFC,由你选择。安装Pywin32模块,可以使用如下命令直接安装,也可以从Python模块仓库下载whl文件在本地安装。
python -m pip install pywin32
用Python设置Windows壁纸,分为5步,核心代码只有5行:
import win32api
import win32gui
import win32con
def set_wallpaper(photo_path):
"""设置壁纸"""
# 1.打开注册表键
key = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, win32con.KEY_SET_VALUE)
# 2.设置壁纸风格:0=居中 1=平铺 2=拉伸
win32api.RegSetValueEx(key, "WallpaperStyle", 0, win32con.REG_SZ, "2")
# 3.设置壁纸是否缩放:0=缩放 1=原图
win32api.RegSetValueEx(key, "TileWallpaper", 0, win32con.REG_SZ, "0")
# 4.设置壁纸
win32gui.SystemParametersInfo(win32con.SPI_SETDESKWALLPAPER, photo_path, 3)
# 5.关闭注册表键
win32api.RegCloseKey(key)
随便找了一张去年春天济南五龙潭樱花盛开时节拍摄的照片,运行:
photo_path = r'D:\CSDN\Column\desktop\album\20200129150646.jpg'
set_wallpaper(photo_path)
我的桌面瞬间变成了这样:
熟悉注册表的同学可以跳过本节剩余内容,直接进入下一节。对注册表结构感兴趣的同学,可以继续读完本节。点击Win + R,输入regedit可以打开系统的注册表编辑器,如下图所示:
注册表分为左右两部分,左侧是键目录,右侧是值列表。注册表中键和值,与我们程序员通常所说的键和值不同。这里的键类似于目录,值类似于文件,每个值都包含了三项内容:名称、类型、数据。
Windows的注册表的键一个树状结构,它有六大根节点:
- HKEY_LOCAL_MACHINE:注册表的核心主键,记录了计算机上的所有硬件和软件的配置
- HKEY_CLASSES_ROOT:这其实不是真正的要节点,而是HKEY_LOCAL_MACHINE\Software\Classes的链接,对该节点的操作与操作HKEY_LOCAL_MACHINE\Software\Classes是一样的
- HKEY_USERS:注册表的核心主键,记录了Windows中所有用户的设置信息
- HKEY_CURRENT_USER:是HKEY_USERS中当前用户键的链接,保存了当前登录用户的所有配置信息
- HKEY_CURRENT_CONFIG:是HKEY_LOCAL_MACHINE\Config的链接
- HKEY_DYN_DATA:记录了系统的动态数据
壁纸信息每个用户是不同的,所以我们需要操作HKEY_CURRENT_USER中的内容,具体是HKEY_CURRENT_USER\Control Panel\Desktop,这里面有三个值修改修改:
- WallPaper:壁纸文件的路径
- WallpaperStyle:有三个选项:0=居中 1=平铺 2=拉伸
- TileWallpaper:有两个选项:0=缩放 1=原图
使用pywin32模块操作注册表,需要进行三步操作:
- 打开注册表键
调用win32api.RegOpenKeyEx打开注册表键,它有四个参数,分别为:- 根节点
- 子节点
- 必须为0
- 对打开的子项进行的操作,包括win32con.KEY_ALL_ACCESS、win32con.KEY_READ、win32con.KEY_WRITE、win32con.KEY_SET_VALUE等
- 修改注册表值
要修改注册表的值,在打开键时,第四个参数需要设置为win32con.KEY_SET_VALUE,然后可以调用win32api.RegSetValueEx修改值,它有五个参数为:- 打开的注册表键
- 值的名称
- 必须为0
- 值的数据类型,包括win32con.REG_BINARY、win32con.REG_SZ、win32con.REG_DWORD等
- 值
- 关闭注册表键
操作完注册表后,可以调用win32api.RegCloseKey关闭注册表键
2. 随机切换Windows壁纸
接下来,我们将旅行照片整理到一个目录中,递归遍历所有的照片,然后随机选择一张设置为壁纸:
# -*- coding: utf-8 -*-
import os, random
import win32api, win32gui, win32con
def set_wallpaper(photo_path):
"""设置壁纸"""
# 1.打开注册表键
key = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, win32con.KEY_SET_VALUE)
# 2.设置壁纸风格:0=居中 1=平铺 2=拉伸
win32api.RegSetValueEx(key, "WallpaperStyle", 0, win32con.REG_SZ, "2")
# 3.设置壁纸是否缩放:0=缩放 1=原图
win32api.RegSetValueEx(key, "TileWallpaper", 0, win32con.REG_SZ, "0")
# 4.设置壁纸
win32gui.SystemParametersInfo(win32con.SPI_SETDESKWALLPAPER, photo_path, 3)
# 5.关闭注册表键
win32api.RegCloseKey(key)
def set_wallpaper_random(photo_dir):
"""随机设置壁纸"""
wall_papers = list()
for root, dirs, files in os.walk(photo_dir):
for name in files:
if os.path.splitext(name)[1].lower() == ".jpg":
wall_papers.append(os.path.join(root, name))
set_wallpaper(random.choice(wall_papers))
if __name__ == '__main__':
#photo_path = r'D:\CSDN\Column\desktop\album\20200129150646.jpg'
#set_wallpaper(photo_path)
set_wallpaper_random(r'D:\CSDN\Column\desktop\album')
这个代码运行一次,就可以随机切换一张壁纸。我运行了4次,4个桌面效果如下:
3. 定时切换Windows壁纸
每次想改变壁纸的时候,都得需要手动运行上面的代码,感觉有点麻烦。那好,下面我们就做一个自动定时切换的。实现定时切换功能,需要一个定时调度服务框架。前几天我在数据抓取服务中刚刚介绍了APScheduler库,今天我们继续用它来实现任务的定时执行。APScheduler安装命令如下:
python -m pip install apscheduler
安装完成后可以先用下面的代码试验效果:
from apscheduler.schedulers.blocking import BlockingScheduler
# 任务执行函数
def do_job():
print("do_job")
# 创建调度器
scheduler = BlockingScheduler()
# 添加job
scheduler.add_job(do_job, # 时间到后的执行函数
trigger="cron", # 设置触发器为cron
second="*/1", # 设置每隔一秒执行一次
misfire_grace_time=60 # 如果任务较多,60秒内没有来得急执行此job时,放弃执行
)
# 启动调度
scheduler.start()
如果可以每秒打印出do_job,说明apscheduler可以正常执行。apscheduler有很多种触发器,在这段代码中,使用了cron触发器,这是apscheduler中最为复杂的触发器,它可以使用cron语法,指定非常复杂的触发方式。
cron语法包含秒、分钟、小时、日、月、星期、年七个域,每个域中可以使用一些通配符,用来匹配任务可以被执行的时间,当7个域都被匹配成功时,任务将被执行。每个域支持的通配符如下:
- 秒:可使用", - * /"四个字符以及有效范围为0-59的整数
- 分钟:可使用", - * /"四个字符以及有效范围为0-59的整数
- 小时:可出现", - * /"四个字符以及有效范围为0-23的整数
- 日:可使用", - * / ? L W C"八个字符以及有效范围为0-31的整数
- 月:可使用", - * /"四个字符、有效范围为1-12的整数或JAN-DEC
- 星期:可使用", - * / ? L C #"四个字符、有效范围为1-7的整数或SUN-SAT两个范围。1表示星期天,2表示星期一, 依次类推
- 年:可使用", - * /"四个字符、有效范围为1970-2099年
其中,各字符的含义如下:
-
, 表示列出枚举值值。
在“分钟”域使用5,20,则意味着在5和20分触发两次
-
- 表示范围.
在“分钟”域使用5-20,表示从5分到20分钟每分钟触发一次
-
* 表示匹配该域的任意值。
在“分钟”域使用*, 即表示每分钟都会触发事件
-
/ 表示起始时间开始触发,然后每隔固定时间触发一次.
在“分钟”域使用5/20,则意味着5分钟触发一次,以后间隔20分钟触发一次,即5、25、45等分别触发一次
-
? 也匹配域的任意值,但只能用在“日”和“星期”两个域。因为“日”和“星期”会相互影响,当“日”和“星期”中有一个使用了*以外的规则时,另一个应该使用?而不能使用*。
想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 日:20,月:*,星期:?
-
L 表示最后,只能出现在“日”和“星期”域。
在“星期”域使用5L,意味着在最后的一个星期四触发
-
W 表示有效工作日(周一到周五),只能出现在“日”域,系统将在离指定日期的最近的有效工作日触发事件。
在day使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发; 如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份。
-
LW 这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五
-
# 用于确定每个月第几个星期几,只能出现在“星期”域。
在4#2,表示某月的第二个星期三
把上面的代码稍做修改就可以定时切换壁纸了:
# -*- coding: utf-8 -*-
import os, random
import win32api, win32gui, win32con
from apscheduler.schedulers.blocking import BlockingScheduler
def set_wallpaper(photo_path):
"""设置壁纸"""
# 1.打开注册表键
key = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, win32con.KEY_SET_VALUE)
# 2.设置壁纸风格:0=居中 1=平铺 2=拉伸
win32api.RegSetValueEx(key, "WallpaperStyle", 0, win32con.REG_SZ, "2")
# 3.设置壁纸是否缩放:0=缩放 1=原图
win32api.RegSetValueEx(key, "TileWallpaper", 0, win32con.REG_SZ, "0")
# 4.设置壁纸
win32gui.SystemParametersInfo(win32con.SPI_SETDESKWALLPAPER, photo_path, 3)
# 5.关闭注册表键
win32api.RegCloseKey(key)
def set_wallpaper_random(photo_dir):
"""随机设置壁纸"""
wall_papers = list()
for root, dirs, files in os.walk(photo_dir):
for name in files:
if os.path.splitext(name)[1].lower() == ".jpg":
wall_papers.append(os.path.join(root, name))
set_wallpaper(random.choice(wall_papers))
def set_wallpaper_regular(photo_dir):
"""定时设置壁纸"""
scheduler = BlockingScheduler()
scheduler.add_job(set_wallpaper_random,
args = (photo_dir, ),
trigger = "cron",
second = "*/10" # 每10分钟切换一次
)
scheduler.start()
if __name__ == '__main__':
#photo_path = r'D:\CSDN\Column\desktop\album\20200129150646.jpg'
#set_wallpaper(photo_path)
#set_wallpaper_random(r'D:\CSDN\Column\desktop\album')
set_wallpaper_regular(r'D:\CSDN\Column\desktop\album')
运行这段段代码,每隔10分钟自动切换壁纸。有兴趣的同学,还可以打包成服务程序,甚至做成任务托盘程序,将会更加实用。
转载:https://blog.csdn.net/xufive/article/details/104106627