近代史上,每一個庚子年都不尋常: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分鐘自動切換壁紙。有興趣的同學,還可以打包成服務程序,甚至做成任務托盤程序,將會更加實用。