tkinter 在windows和mac os 中展示gif动画

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

favicon制作 | 制作ico图标 | 在线ico图标转换工具 方便制作favicon.ico — 在线工具

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值