1
1.将图片文件,比如图标,背景转换成py文件便于打包
import base64
import os
"""
iconimg.ico 图标
loading_new.gif 展示的gif
"""
def get_files(path, file_list=[]):
# 获取文件夹下的所有文件
for i in os.listdir(path):
path1 = os.path.join(path, i)
if os.path.isdir(path1):
get_files(path1, file_list)
elif os.path.isfile(path1):
file_list.append(i)
return file_list
def pic2py(picture_names, py_name):
write_data = []
for picture_name in picture_names:
filename = picture_name.replace('.', '_')
with open("%s" % picture_name, 'rb') as r:
b64str = base64.b64encode(r.read())
# 注意这边 b64str 一定要加上.decode()
write_data.append('%s = "%s"\n' % (filename, b64str.decode()))
with open(f'./{py_name}.py','w+') as f:
for data in write_data:
f.write(data)
def run():
# 需要转码的图片:
os.chdir('./Image') # 变更路径到当前文件中的Image文件夹
pics = get_files('./') # 将你的图片都输入进去
pic2py(pics, 'image')
if __name__ == '__main__':
run()
2. 将生成的image.py 放在与主文件同级目录
# -*- coding: utf-8 -*-
import shlex
import webbrowser
from tkinter import *
import tkinter.messagebox
import threading
import tkinter.filedialog
import tkinter.dialog
from image import *
from base64 import b64encode, b64decode
import time
from PIL import Image, ImageTk, ImageSequence
from io import BytesIO
import sys
import asyncio
from pyppeteer.launcher import launch
import os
import re
class GUI:
def __init__(self):
# 图标
self.iconphoto_path = iconimg_png
# gif 动态图
self.loading_gif = loading_new_gif
self.root = Tk()
self.root.title("展示gif")
# 设置无标题栏
self.root.overrideredirect(True)
# 配置文件路径,打包后 .exe的绝对路径
self.current_file_path = os.path.dirname(os.path.realpath(sys.argv[0]))
self.configure_path = f'{self.current_file_path}/浏览器路径.ini'
# gif动画停止
self.gif_stop = False
# 访问目标url及浏览器路径
self.url = None
self.browser_path = None
# 设置窗体尺寸并居屏幕中心
self.width, self.height = 350, 300
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()
window_size = f'{self.width}x{self.height}+{round((screen_width - self.width) / 2)}+{round((screen_height - self.height) / 2)}'
self.root.geometry(window_size)
# 设置gif为透明背景
if 'win32' in str(sys.platform):
# win 展示动画
print('win 展示动画')
self.frame_canvas()
else:
# mac 展示动画
print('mac 展示动画')
self.root.wm_overrideredirect(False)
# 设置透明背景
self.root.wm_attributes("-transparent", True)
self.mac_canvas()
# 窗口不可拉伸
# self.root.resizable(0, 0)
# alpha 越小透明度越高
self.root.attributes('-alpha', 1.0)
# 设置图标
self.root.iconphoto(False, PhotoImage(data=self.iconphoto_path))
self.top0 = None
self.login()
tkinter.mainloop()
def Cavas_Click(self, event):
self.x = event.x
self.y = event.y
def Cavas_Release(self, event):
self.x = None
self.y = None
def OnMotion(self, event):
deltax = event.x - self.x
deltay = event.y - self.y
_x = self.root.winfo_x() + deltax
_y = self.root.winfo_y() + deltay
self.root.geometry("+%s+%s" % (_x, _y))
def frame_canvas(self):
self.frame = Label(self.root, bg='white')
self.frame.place(relwidth=1.0, relheight=1.0)
# 创建画布
self.canvas = Canvas(self.frame, width=self.width, height=self.height, highlightthickness=0, bg='white')
self.canvas.place(relwidth=1, relheight=1)
# self.canvas.pack(fill=tkinter.BOTH, expand=True)
self.pic_with_win_auto_size()
def resize(self, w, h, w_box, h_box, pil_image):
"""
对一个pil_image对象进行缩放,让它在一个矩形框内,还能保持比例
"""
f1 = w_box / w
f2 = h_box / h
factor = min(f1, f2)
width = int(w * factor)
height = int(h * factor)
width, height = w_box, h_box
pil_image.convert('RGBA')
return pil_image.resize((width, height), Image.Resampling.LANCZOS)
def MouseDown(self, event):
self.mousX = event.x
self.mousY = event.y
def MouseMove(self, event):
w1 = self.root.winfo_x() # w1为标签1的左边距
h1 = self.root.winfo_y() # h1为标签1的上边距
new_x = (event.x - self.mousX) + w1
new_y = (event.y - self.mousY) + h1
s = f"{self.width}x{self.height}+{new_x}+{new_y}"
self.root.geometry(s)
def size(self, event):
x1 = self.root.winfo_pointerx()
y1 = self.root.winfo_pointery()
x0 = self.root.winfo_rootx()
y0 = self.root.winfo_rooty()
self.root.geometry("%sx%s" % ((x1 - x0), (y1 - y0)))
def callback3(self, canvas):
# 停止操作
canvas.quit()
def right_close(self, top, canvas, event=None):
# 右键菜单关闭
menu = Menu(top, tearoff=False)
menu.add_command(label="关闭动画", command=lambda *e: self.callback3(canvas))
menu.post(event.x_root, event.y_root) # post在指定的位置显示弹出菜单
def pic_with_win_auto_size(self):
# 修改gif尺寸并展示
pil_image = Image.open(BytesIO(b64decode(self.loading_gif)))
images = ImageSequence.Iterator(pil_image)
for frame in images:
w, h = frame.size
w_box = self.frame.winfo_width()
h_box = self.frame.winfo_height()
pil_image_resized = self.resize(w, h, w_box, h_box, frame)
tk_image = ImageTk.PhotoImage(pil_image_resized)
self.canvas.delete('imageC')
self.canvas.create_image(w_box // 2, h_box // 2, image=tk_image, tags='imageC')
# 画布绑定移动动作
# 按下鼠标左键绑定MouseDown函数
self.canvas.bind("<Button-1>", self.MouseDown)
self.canvas.bind("<ButtonRelease-1>", self.Cavas_Release)
# 鼠标左键按住拖曳事件
self.canvas.bind("<B1-Motion>", self.MouseMove)
# 鼠标右键关闭
self.canvas.bind("<Button-3>", lambda event: self.right_close(self.top0, self.canvas, event))
self.root.wm_attributes('-transparentcolor', 'white')
time.sleep(0.09)
self.frame.update_idletasks() # 刷新
self.frame.update()
if self.gif_stop:
self.canvas.delete()
return
self.frame.after(0, self.pic_with_win_auto_size)
def mac_canvas(self):
# mac 显示GIF动画
self.label = Label(self.root)
self.label.place(relwidth=1.0, relheight=1.0)
# gif的帧数
num_idx = 4
for k in range(num_idx):
img = PhotoImage(data=b64decode(self.loading_gif), format='gif -index %i' % (k))
# 显示当前帧的图片
self.label.configure(image=img, bg="systemTransparent")
# 按下鼠标左键绑定MouseDown函数
self.label.bind("<Button-1>", self.MouseDown)
self.label.bind("<ButtonRelease-1>", self.Cavas_Release)
# 鼠标左键按住拖曳事件
self.label.bind("<B1-Motion>", self.MouseMove)
# 鼠标右键关闭
if sys.platform.lower().startswith('freebsd') or sys.platform.lower().startswith('darwin'):
self.label.bind("<Button-2>", lambda event: self.right_close(self.top0, self.label, event))
else:
self.label.bind("<Button-3>", lambda event: self.right_close(self.top0, self.label, event))
self.label.update_idletasks()
self.label.update()
if self.gif_stop:
self.label.destroy()
return
# 立即启动定时器函数(update)
self.root.after(100, self.mac_canvas)
def login(self):
self.deal_file_thread(self.show)
def callback1(self, t, event=None):
# 剪切内容操作
t.event_generate('<<Cut>>')
def callback2(self, t, event=None):
# 复制操作
t.event_generate('<<Copy>>')
def popup(self, top, t, event=None):
# 绑定右键,菜单显示剪切复制选项
menu = Menu(top, tearoff=False)
menu.add_command(label="剪切", command=lambda *e: self.callback1(t))
menu.add_command(label="复制", command=lambda *e: self.callback2(t))
menu.post(event.x_root, event.y_root) # post在指定的位置显示弹出菜单
def show(self):
result = self.open_url()
print('result:', result)
if not result or not self.browser_path or not os.path.exists(str(self.browser_path)):
if not os.path.exists(self.configure_path):
with open(self.configure_path, 'w', encoding='utf-8') as f:
f.write('谷歌浏览器路径:C:\xxxx.exe' + '\n')
self.gif_stop = True
tkinter.messagebox.showinfo('请在配置文件中填写谷歌浏览器路径')
self.root.quit()
else:
# 关闭
self.gif_stop = True
self.root.quit()
def deal_file_thread(self, func, *args):
t = threading.Thread(target=func, args=args)
t.setDaemon(True)
t.start()
def get_browser_path1(self, browser):
# 获取windows 路径方式1
import winreg
result = []
# 需要遍历的两个注册表
sub_key = [r'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',
r'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall',
]
for i in sub_key:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, i)
for j in range(winreg.QueryInfoKey(key)[0]):
try:
each_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, f'{i}\\{winreg.EnumKey(key, j)}')
display_path, reg_sz = winreg.QueryValueEx(each_key, "DisplayIcon")
if browser in display_path:
result.append(display_path.split(',')[0])
except WindowsError:
pass
return result
def get_browser_path2(self, browser):
import winreg
# 获取windows 路径方式2
# 连接注册表根键 以HKEY_LOCAL_MACHINE为例
regRoot = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
subDir = r'SOFTWARE'
# 获取指定目录下所有键的控制
keyHandle = winreg.OpenKey(regRoot, subDir)
# 获取该目录下所有键的个数(0-下属键个数 1-当前键值个数)
count = winreg.QueryInfoKey(keyHandle)[0]
lists = []
for i in range(count):
# 穷举键获取键名
subKeyName = winreg.EnumKey(keyHandle, i)
subDir_2 = r'%s\%s' % (subDir, subKeyName)
# 根据获取的键名拼接之前的路径作为参数 获取当前键下所属键的控制
keyHandle_2 = winreg.OpenKey(regRoot, subDir_2)
num = winreg.QueryInfoKey(keyHandle_2)[1]
for j in range(num):
name, value, type_ = winreg.EnumValue(keyHandle_2, j)
if browser in name.lower():
_browser_regs = '\\'.join(value.split('\\')[:-1]) + '\\DefaultIcon'
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, _browser_regs)
value1, _type1 = winreg.QueryValueEx(key, "")
lists.append(value1.split(',')[0])
# 读写操作结束后关闭键
winreg.CloseKey(keyHandle_2)
return lists
def get_browser_path3(self):
import winreg
# 获取windows 路径方式3
result = None
if winreg:
for subkey in ['ChromeHTML\\\\shell\\\\open\\\\command',
'Applications\\\\chrome.exe\\\\shell\\\\open\\\\command']:
try:
result = winreg.QueryValue(winreg.HKEY_CLASSES_ROOT, subkey)
except WindowsError:
pass
if result is not None:
result_split = shlex.split(result, False, True)
result = result_split[0] if result_split else None
if os.path.isfile(result):
break
result = None
else:
expected = "google-chrome" + (".exe" if os.name == 'nt' else "")
for parent in os.environ.get('PATH', '').split(os.pathsep):
path = os.path.join(parent, expected)
if os.path.isfile(path):
result = path
break
return [result]
def get_browser_path4(self, path, file_list=[]):
# 从c盘读取谷歌浏览器路径 方式4
try:
os.listdir(path)
except:
return
lidir = []
for i in os.listdir(path):
path1 = os.path.join(path, i)
pathtemp1 = path1.lower()
if os.path.isdir(path1) and ('program' in pathtemp1 or 'user' in pathtemp1):
temp_list = ['tencent', 'windows', 'common', 'microsoft', 'appdata', 'documents', 'desktop', 'default',
'public', 'package', 'administer']
flug = True
for name in temp_list:
if name in pathtemp1:
flug = False
if flug:
lidir.append(path1)
elif os.path.isfile(path1):
if 'google' in pathtemp1 and pathtemp1.endswith('chrome.exe') and 'temp' not in pathtemp1:
file_list.append(path1.replace('\\\\', '\\'))
return file_list
for li in lidir:
self.get_browser_path4(li, file_list)
return file_list
def get_browser_path5(self):
# 从桌面快捷方式获取谷歌浏览器路径 方式5
from win32com.client import Dispatch
def GetDesktopPath(path, file_list=[]):
try:
os.listdir(path)
except:
return
lidir = []
for i in os.listdir(path):
path1 = os.path.join(path, i)
pathtemp1 = path1.lower()
if os.path.isdir(path1):
if pathtemp1.endswith('desktop'):
file_list.append(path1.replace('\\\\', '\\'))
return file_list
else:
lidir.append(path1)
for li in lidir:
GetDesktopPath(li, file_list)
return file_list
shell1 = Dispatch('WScript.shell')
browser_path_list = []
for directory in GetDesktopPath(r'C:\Users'):
for fn in os.listdir(directory):
if fn.endswith('.lnk') and 'chrome' in fn.lower():
link = os.path.join(directory, fn)
browser_path = shell1.CreateShortCut(link).Targetpath
browser_path_list.append(browser_path)
return list(set(browser_path_list))
def get_mac_soft_path(self, path, file_list=[]):
# mac 获取谷歌浏览器的路径
for i in os.listdir(path):
path1 = os.path.join(path, i)
if os.path.isdir(path1):
self.get_mac_soft_path(path1, file_list)
elif os.path.isfile(path1):
if 'MacOS' in path1 and path1.endswith('Chrome'):
file_list.append(path1)
return file_list
return file_list
def open_url(self):
"""
使用指定的浏览器打开url对应的网页地址
:param url: 网页地址
:param browsers: 浏览器名称列表
:return: 是否打开成功
"""
self.url = ''
browser = 'chrome'
if os.path.exists(self.configure_path):
try:
with open(self.configure_path, 'r', encoding='utf-8') as f:
data = f.read()
except:
data = ''
if sys.platform.lower().startswith('freebsd') or sys.platform.lower().startswith('darwin'):
browser_path = re.findall('谷歌浏览器路径:(.*?)\n', data)
else:
browser_path = re.findall('谷歌浏览器路径:(.*?\.exe)', data)
if browser_path:
path = browser_path[0].strip()
else:
path = None
else:
if sys.platform.lower().startswith('freebsd') or sys.platform.lower().startswith('darwin'):
path = self.get_mac_soft_path('/Applications/')
else:
path = self.get_browser_path1(browser) or self.get_browser_path2(
browser) or self.get_browser_path3() or self.get_browser_path4(r'C:\\') or self.get_browser_path5()
if isinstance(path, list) or isinstance(path,tuple):
path = path[0]
else:
path = path
print('path:', path)
if path:
self.browser_path = path
return True
else:
return False
async def calculate(self, browser_path, url):
dic = {'headless': False, 'timeout': 60000, 'autoClose': False, 'ignoreDefaultArgs': ['--enable-automation'],
'args': ['--disable-infobars', '--start-maximized'], 'defaultViewport': None} # '--start-maximized'
print('browser_path:', browser_path)
print('url:', url)
if browser_path:
dic['executablePath'] = browser_path
browser = await launch(dic)
page = (await browser.pages())[0]
time.sleep(0.5)
await page.goto(url)
self.root.quit()
def open_browser2(self):
# pyppeteer 开启新的浏览器
if self.url and self.browser_path:
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(self.calculate(self.browser_path, self.url))
except Exception as e:
print('打开浏览器失败:',e)
print('浏览器路径:',self.browser_path)
if not os.path.exists(self.configure_path):
with open(self.configure_path, 'w', encoding='utf-8') as f:
f.write('谷歌浏览器路径:xxxx.exe' + '\n')
loop.close()
def open_browser(self):
# 开启当前浏览器打开页面
import subprocess
if self.url and self.browser_path:
if self.browser_path:
with open(self.configure_path, 'w', encoding='utf-8') as f:
f.write('谷歌浏览器路径:%s'%self.browser_path + '\n')
command = r'"%s" "%s"' % (self.browser_path, self.url)
print('command:', command)
try:
subprocess.Popen(command, shell=True)
except Exception as e:
print('e:', e)
webbrowser.register('chrome', None, webbrowser.BackgroundBrowser(self.browser_path))
webbrowser.open(self.url, 0, False)
else:
if not os.path.exists(self.configure_path):
with open(self.configure_path, 'w', encoding='utf-8') as f:
f.write('谷歌浏览器路径:xxxx.exe' + '\n')
def suppress_keyboard_interrupt_message():
old_except_hook = sys.excepthook
def new_hook(exc_type, value, traceback):
if exc_type != KeyboardInterrupt:
old_except_hook(exc_type, value, traceback)
else:
pass
sys.excepthook = new_hook
if __name__ == "__main__":
suppress_keyboard_interrupt_message()
GUI().open_browser()
#GUI().open_browser2()
windows 打包 pyinstaller -F -w --clean -i .\Image\xxxx.ico .\xxxx.py -p .\image.py mac 打包 pyinstaller -F -w --clean -i .\Image\xxxx.icns .\xxxx.py -p .\image.py