windows 换壁纸,第一个exe程序
特点:查找指定文件夹(子文件夹)下所有 .jpg .jpeg .png 图片,过滤掉预设的比例和像素的图,根据设定时间定时更换
BUG
输入框本来应该限制数字的,没有做到~
没有点击结束就点击停止的话会挂在后台运行,只能杀进程~所以命名a…,好找
不支持视频播放,还没百度到资料~~
界面预览
下载
链接: https://pan.baidu.com/s/1LCBSR68VTPRkE_lbgVVMbw
提取码: bolg
源码
import os
from time import sleep
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from tkinter import messagebox
from tkinter.filedialog import askdirectory
from PIL import Image
import os
import random
import time
from threading import Thread
import win32gui,win32con,win32api
import logging
from logging import handlers
class Logger(object):
level_relations = {
'debug':logging.DEBUG,
'info':logging.INFO,
'warning':logging.WARNING,
'error':logging.ERROR,
'crit':logging.CRITICAL
}#日志级别关系映射
def __init__(self,filename,level='info',when='D',backCount=3,fmt='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
self.logger = logging.getLogger(filename)
format_str = logging.Formatter(fmt)#设置日志格式
self.logger.setLevel(self.level_relations.get(level))#设置日志级别
sh = logging.StreamHandler()#往屏幕上输出
sh.setFormatter(format_str) #设置屏幕上显示的格式
th = handlers.TimedRotatingFileHandler(filename=filename,when=when,backupCount=backCount,encoding='utf-8')#往文件里写入#指定间隔时间自动生成文件的处理器
#实例化TimedRotatingFileHandler
#interval是时间间隔,backupCount是备份文件的个数,如果超过这个个数,就会自动删除,when是间隔的时间单位,单位有以下几种:
# S 秒
# M 分
# H 小时、
# D 天、
# W 每星期(interval==0时代表星期一)
# midnight 每天凌晨
th.setFormatter(format_str)#设置文件里写入的格式
self.logger.addHandler(sh) #把对象加到logger里
self.logger.addHandler(th)
log = Logger('au_all.log',level='info')
def setWallpaperFromBMP(imagepath):
# log.logger.info('======win_cv:'+ win_cv)
k = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER,"Control Panel\\Desktop",0,win32con.KEY_SET_VALUE)
win32api.RegSetValueEx(k, "WallpaperStyle", 0, win32con.REG_SZ, win_cv) #2拉伸适应桌面,0桌面居中 10填充,6适应,2拉伸, 居中 0,跨区22
win32api.RegSetValueEx(k, "TileWallpaper", 0, win32con.REG_SZ, "0")
win32gui.SystemParametersInfo(win32con.SPI_SETDESKWALLPAPER,imagepath, 1+2)
def receive():
# 实例化Application
app = Application()
# 主消息循环:
app.mainloop()
def send(self):
global time_n
global win_cv
if time_n<3:
time_n = 3
log.logger.info('==>>总数:'+str(count_s))
i = 0
index_len = len(files)-1
while True:
# log.logger.info(f"send at {time.strftime('%X')}")
win_cv_v = self.cv.get() #10 填充 ,6 适应 ,2 拉伸 , 居中 0, 跨区 22
# log.logger.info('======win_cv_v:'+ str(win_cv_v))
if win_cv_v == '居中':
win_cv = '0'
elif win_cv_v == '拉伸':
win_cv = '2'
elif win_cv_v == '适应':
win_cv = '6'
elif win_cv_v == '填充':
win_cv = '10'
elif win_cv_v == '跨区':
win_cv = '22'
if '顺序' == str(self.cv2.get()):
if i<index_len:
i += 1
else:
i = 0
else:
i = random.randint(0,index_len)
if b1 == False or len(files) == 0:
log.logger.info('======>>结束循环')
break
else:
# log.logger.info('======>>循环')
# log.logger.info(i)
# log.logger.info(files[i])
setWallpaperFromBMP(files[i])
sleep(time_n)
count_s = 0
time_n = 5
files = []
t1 = Thread(target=receive)
t2 = Thread(target=send)
b1 = True
win_cv = '0'
class Application(tk.Tk):
'''
文件夹选择程序
界面与逻辑分离
'''
def __init__(self):
'''初始化'''
super().__init__() # 有点相当于tk.Tk()
self.createWidgets()
def createWidgets(self):
'''界面'''
self.geometry("400x250+200+200")
self.resizable(False,False)
self.title('tk')
# 定义一些变量
# self.entryvar = tk.StringVar()
# self.keyvar = tk.StringVar()
# self.keyvar.set('关键字')
# items = ['BufferPool','Close','Data Capture','Compress','Pqty','Sqty']
self.btn_v1 = True
self.btn_v2 = True
self.list_files = []
self.img_count = 0
self.path = tk.StringVar()
self.w_pro1 = tk.StringVar()
self.w_pro1.set(21)
self.h_pro1= tk.StringVar()
self.h_pro1.set(9)
self.w_pro2 = tk.StringVar()
self.w_pro2.set(4)
self.h_pro2= tk.StringVar()
self.h_pro2.set(3)
self.w_size = tk.StringVar()
self.w_size.set(1920)
self.h_size = tk.StringVar()
self.h_size.set(1080)
self.t_time = tk.StringVar()
self.t_time.set(5)
self.cv = tk.StringVar()
self.cv2 = tk.StringVar()
self.btn_text1 = tk.StringVar()
self.btn_text1.set('横')
self.lab_text = tk.StringVar()
self.lab_text.set('数量:')
self.img_num = tk.StringVar()
self.img_num.set(str(0))
self.btn_text2 = tk.StringVar()
self.btn_text2.set('开始')
tk.Label(self,text = "目标路径:").place(x=20,y=40)
tk.Entry(self, textvariable = self.path).place(x=80,y=40)
tk.Button(self, text = "路径选择", command = self.selectPath).place(x=250,y=35)
tk.Label(self,text = "比例:").place(x=20,y=80)
tk.Entry(self, textvariable = self.w_pro1,width=5).place(x=80,y=80)
tk.Label(self,text = ":").place(x=120,y=80)
tk.Entry(self, textvariable = self.h_pro1,width=5).place(x=130,y=80)
tk.Label(self,text = "——").place(x=180,y=80)
tk.Entry(self, textvariable = self.w_pro2,width=5).place(x=220,y=80)
tk.Label(self,text = ":").place(x=260,y=80)
tk.Entry(self, textvariable = self.h_pro2,width=5).place(x=270,y=80)
tk.Label(self,text = "最小尺寸:").place(x=20,y=120)
tk.Entry(self, textvariable = self.w_size,width=5).place(x=80,y=120)
tk.Label(self,text = "x").place(x=120,y=120)
tk.Entry(self, textvariable = self.h_size,width=5).place(x=130,y=120)
tk.Button(self, textvariable=self.btn_text1,width=10,height=1,command = self.switch).place(x=300,y=120)
tk.Label(self,text = "时间(s):").place(x=20,y=160)
tk.Entry(self, textvariable = self.t_time,width=5).place(x=80,y=160)
com = ttk.Combobox(self, textvariable=self.cv,width=4)
#设置下拉数据
com["value"] = ("居中", "拉伸", "适应",'填充','跨区')
com['state'] = 'readonly'
#设置默认值
com.current(2)
com.place(x=140,y=160)
con = ttk.Combobox(self, textvariable=self.cv2,width=4)
#设置下拉数据
con["value"] = ("顺序", "随机")
con['state'] = 'readonly'
#设置默认值
con.current(1)
con.place(x=220,y=160)
tk.Label(self,textvariable = self.lab_text).place(x=20,y=200)
tk.Label(self,textvariable = self.img_num).place(x=80,y=200)
tk.Button(self, textvariable=self.btn_text2,width=10,height=1,command=self.getV).place(x=300,y=200)
def selectPath(self):
path_ = askdirectory()
self.path.set(path_)
def askdirectory (**options):
"Ask for a directory, and return the file name"
return Directory(**options).show()
def switch(self):
# log.logger.info(self.btn_v1)
self.btn_v1 = not self.btn_v1
if self.btn_v1:
self.btn_text1.set('横')
self.w_pro1.set(21)
self.h_pro1.set(9)
self.w_pro2.set(4)
self.h_pro2.set(3)
self.w_size.set(1920)
self.h_size.set(1080)
else:
self.btn_text1.set('竖')
self.w_pro1.set(4)
self.h_pro1.set(3)
self.w_pro2.set(1)
self.h_pro2.set(2)
self.w_size.set(540)
self.h_size.set(1080)
# 遍历文件夹
def walkFile(self,file_path):
for root, dirs, files in os.walk(file_path):
# root 表示当前正在访问的文件夹路径
# dirs 表示该文件夹下的子目录名list
# files 表示该文件夹下的文件list
# 遍历文件
for f in files:
file_name = os.path.join(root, f)
log.logger.info('==>>'+file_name)
if file_name.endswith(".jpg") or file_name.endswith(".jpeg") or file_name.endswith(".png"):
self.img_count += 1
try:
# 获取尺寸
img = Image.open(file_name)
imgSize = img.size # 大小/尺寸
w = img.width # 图片的宽
h = img.height # 图片的高
f = img.format # 图像格式
# log.logger.info(imgSize)
log.logger.info(str(w) + ' : ' + str(h) + ' -- ' + str(f))
# log.logger.info(w/h)
w1 = int(self.w_pro1.get())
h1 = int(self.h_pro1.get())
w2 = int(self.w_pro2.get())
h2 = int(self.h_pro2.get())
ws = int(self.w_size.get())
hs = int(self.h_size.get())
# log.logger.info(isinstance(w1,int))
# log.logger.info(isinstance(h1,int))
# log.logger.info(isinstance(w2,int))
# log.logger.info(isinstance(h2,int))
# log.logger.info(isinstance(ws1,int))
# log.logger.info(isinstance(hs1,int))
# log.logger.info(isinstance(w,int))
# log.logger.info(isinstance(h,int))
# log.logger.info(w1/h1>=w/h)
# log.logger.info(w/h >= w2/h2)
# log.logger.info(w >= ws)
# log.logger.info(h >= hs)
if w1/h1 >= w/h and w/h >= w2/h2 and w >= ws and h >= hs:
log.logger.info('========>>>>>符合')
self.list_files.append(file_name)
# log.logger.info(file_name)
else:
log.logger.info('========>>>>>不匹配')
# log.logger.info(str(w1/h1)+ '>=' + str(w/h))
# log.logger.info(str(w/h)+ '>=' + str(w2/h2))
# log.logger.info(str(w)+ '>=' + str(ws))
# log.logger.info(str(h)+ '>=' + str(hs))
# break
except OSError:
log.logger.info("图像异常:\t"+file_name)
# 遍历所有的文件夹
for d in dirs:
dir_name = os.path.join(root, d)
log.logger.info('==>>'+dir_name)
def getV(self):
global b1
global count_s
global files
global time_n
global win_cv
self.btn_v2 = not self.btn_v2
if self.btn_v2:
self.btn_text2.set('开始')
else:
self.btn_text2.set('停止')
if self.btn_v2 == False:
# log.logger.info('==>>')
# log.logger.info(self.path.get())
# log.logger.info(self.w_pro1.get()+':'+self.h_pro2.get()+'--'+self.w_pro2.get()+':'+self.h_pro2.get())
# log.logger.info(self.w_size.get()+':'+self.h_size.get())
# log.logger.info(self.t_time.get())
self.walkFile(self.path.get())
# log.logger.info('==>>')
# log.logger.info(len(list_files))
imgnum = len(self.list_files)
self.img_num.set(str(imgnum))
# for i in self.list_files:
# log.logger.info(i)
count_s = self.img_count
files = self.list_files
time_n = int(self.t_time.get())
b1 = True
# log.logger.info('======win_cv:'+ win_cv)
Thread(target=send,args=(self,)).start()
log.logger.info("=================<<<<<<<<<<<开始:\n")
else:
self.img_num.set('0')
self.list_files = []
files = []
b1 = False
self.img_count = 0
count_s = 0
win_cv = '0'
log.logger.info("=================<<<<<<<<<<<停止:\n")
if __name__ == '__main__':
# print(f"main at {time.strftime('%X')}")
log.logger.info("====>>main")
t1.start()
# the directory dialog has its own _fix routines.
class Directory(tk.commondialog.Dialog):
"Ask for a directory"
command = "tk_chooseDirectory"
def _fixresult(self, widget, result):
if result:
# convert Tcl path objects to strings
try:
result = result.string
except AttributeError:
# it already is a string
pass
# keep directory until next time
self.options["initialdir"] = result
self.directory = result # compatibility
return result
#
# convenience stuff
'''
make
pip install pyinstaller
cd 装环境的位置
pipenv shell
pip install 引用的资源,已安装下次可以继续用
pyinstaller -Fw G:\workspace\VSCode\Python\newpy\uus.py
'''