Python中基于Tkinte设计图片浏览器(第31节)


无论是在工作中,还是在日常生活中,我们都经常需要快速查看电脑上的图片,无论是浏览照片集,还是查看工作中的图像资料,选择一款好的图片浏览器能大幅提升效率。本节教程将介绍如何使用Python的Tkinter库构建一个功能完善的图片浏览器,包括图片翻页浏览、缩放、旋转、保存和删除等功能。

1、图片浏览器介绍

Python作为一种简单而强大的编程语言,提供了丰富的图像处理库和工具。通过Python自带的Tkinter库创建GUI图形操作界面,并借助Python的第三方库PIL(Pillow)图像处理库,我们可以轻松地创建一个功能强大的图片浏览器。

该程序包括初始界面、图片浏览界面和具体功能实现,如打开图片文件、保存图片、删除图片等操作,允许用户浏览和操作本地计算机上的图片,包括上一张、下一张、放大和缩小等功能。通过os模块进行文件操作,PIL库处理图像显示,它涉及到文件操作、图像处理和用户界面设计等方面的技术。

打开图片:浏览图片前,须点击“选择需要查看的图片”按钮选择指定图片,支持浏览多种常见的图片格式包括JPG、JPEG、PNG、GIF、BMP。

保存图片:支持将图片保存为.jpg或.png后缀名的图像文件,这里需要注意的是,如果用户输入保存图片的扩展名是png,则将保留图片的透明背景;如果用户输入保存图片的扩展名是jpg,则程序会自动将透明背景转换成白色背景,这是因为jpg采用有损压缩格式,设计初衷用于存储照片,不支持Alpha通道,因此无法保留透明背景。如果用户输入保存图片的扩展名不包含.jpg或.png后缀名,则程序会提示错误,无法保存。

编辑和删除图片:支持编辑图片包括放大、缩小、左旋转、右旋转,并支持将编辑后的图片保存到本地电脑上。这里需要注意的是,应该谨慎使用“删除图片”功能,删除后不可恢复,注意备份。

菜单栏功能:程序顶部的菜单栏支持打开图片、另存为、删除图片功能。

快捷键操作:支持鼠标右键弹出菜单栏,并支持键盘快捷键,点击键盘左、右箭头键可以在图片之间前后切换。

图片信息显示:显示已打开的图片信息,包括图片路径和图片尺寸,并统计文件夹中的图片数量。

容错处理:程序能够处理文件夹内的异常图像文件。如果打开的图片异常,无法读取图片数据,则程序会自动创建一张提示图片,并在提示图片上显示“不支持这种文件格式”,确保用户体验的连贯性和程序的稳定性。

2、图片浏览器界面演示

Python中基于Tkinte设计图片浏览器

Python中基于Tkinte设计图片浏览器

3、代码实现

(1)下载图标文件

程序中Button按钮控件的图标是通过加载本地图片文件,须将这些图标文件下载到本地电脑内,且须存放在Python程序脚本文件所在的同一目录内。

程序中用到的图标文件包括:

choose.png 选择图片icon图标

open.png 打开图片icon图标

save.png 保存图片icon图标

delete.png 删除图片icon图标

previous.png 上一张图片icon图标

left.png 左旋转icon图标

big.png 图片放大icon图标

small.png 图片缩小icon图标

right.png 右旋转icon图标

next.png 下一张图片icon图标

注意:以上图标文件下载后,必须重新命名,比如:next_20251006120832573889.png下载后重新命名为next.png,right_20251006120804645880.png下载后重新命名为right.png,其它图片以此类推。

(2)安装PIL库

首先,确保你已经安装了PIL库(Pillow)。如果还没有安装,可以通过pip安装:

pip install Pillow

(3)图片浏览器,完整代码如下所示:

动手练一练:

import tkinter as tk
from tkinter import filedialog, messagebox
import webbrowser
from os import listdir, remove, path, chdir
from PIL import ImageTk, Image, UnidentifiedImageError, ImageDraw, ImageFont

# 获取当前脚本文件所在的目录
default_directory = path.dirname(path.abspath(__file__))
# 将当前脚本文件所在的目录设置为工作目录
chdir(default_directory)

# 创建一个白色背景图像,写入内容
def create_image(width, height, color=(255, 255, 255)):
    # 创建新图像
    image = Image.new("RGB", (width, height), color)
    # 创建一个可以在给定图像上绘图的对象
    draw = ImageDraw.Draw(image)
    # 设置文字内容、位置和字体大小
    text = "不支持这种文件格式"
    position = (10, 5)  # 文本的位置,以像素为单位
    font_size = 20  # 字体大小

    # 尝试使用Windows系统预装的黑体字体
    try:
        font = ImageFont.truetype("simhei.ttf", font_size)
    except OSError:
        try:
            # 如果Windows系统不存在“simhei.ttf”字体,则尝试使用系统默认字体
            font = ImageFont.load_default()
        except Exception as e:
            # 如果字体加载失败,则抛出错误提示
            messagebox.showerror("错误", f"无法加载字体: {str(e)}")
            return

    # 在图像上写入文字,fill=(0, 0, 0) 表示黑色文字
    draw.text(position, text, fill=(0, 0, 0), font=font)

    return image

# 创建一个200x30的图像,当图片打开异常时显示该图像
prompt_image = create_image(200, 30)

# 当鼠标悬停在按钮上
def mouse_hover(button, color=None):
    if not color:
        color = '#b3f7fd'
    button.configure(bg=color)

# 当鼠标未悬停在按钮上
def mouse_not_hover(button, color=None):
            if not color:
                color = 'white'
            button.configure(bg=color)

# 定义ImageBrowse类,用于封装图片浏览程序
class ImageBrowse:
    # 初始化参数
    def __init__(self):
        # 初始化图片路径
        self.path = None
        self.dir = None
        # 初始化图片地址列表
        self.result_images = None
        # 初始化当前文件夹内图片总数量
        self.all_images = 0
        # 初始化源图像
        self.source_img = None
        # 初始化源图像尺寸
        self.size = None
        # 初始化图片缩放比例
        self.upper = 1

        self.root = tk.Tk()
        self.root.title('图片浏览器')

        # 设置窗口居中
        window_width = 1000
        window_height = 700
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        x = (screen_width - window_width) / 2
        y = (screen_height - window_height) / 2
        self.root.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))

        # 加载按钮背景图片
        self.choose_icon = Image.open('choose.png')
        self.choose_icon = ImageTk.PhotoImage(self.choose_icon)

        self.open_icon = Image.open('open.png')
        self.open_icon = self.open_icon.resize((50, 40), Image.Resampling.LANCZOS)
        self.open_icon = ImageTk.PhotoImage(self.open_icon)

        self.save_icon = Image.open('save.png')
        self.save_icon = self.save_icon.resize((40, 40), Image.Resampling.LANCZOS)
        self.save_icon = ImageTk.PhotoImage(self.save_icon)

        self.delete_icon = Image.open('delete.png')
        self.delete_icon = self.delete_icon.resize((40, 40), Image.Resampling.LANCZOS)
        self.delete_icon = ImageTk.PhotoImage(self.delete_icon)

        self.previous_icon = Image.open('previous.png')
        self.previous_icon = ImageTk.PhotoImage(self.previous_icon)

        self.left_icon = Image.open('left.png')
        self.left_icon = ImageTk.PhotoImage(self.left_icon)

        self.big_icon = Image.open('big.png')
        self.big_icon = ImageTk.PhotoImage(self.big_icon)

        self.small_icon = Image.open('small.png')
        self.small_icon = ImageTk.PhotoImage(self.small_icon)

        self.right_icon = Image.open('right.png')
        self.right_icon = ImageTk.PhotoImage(self.right_icon)

        self.next_icon = Image.open('next.png')
        self.next_icon = ImageTk.PhotoImage(self.next_icon)

        # 设置按钮,浏览图片前用于选择需要打开的图片
        self.choose = tk.Button(self.root,
                             image=self.choose_icon,
                             relief='flat',
                             background='#f0f0f0',
                             cursor="hand2",
                             command=self.choose_file,
                             )
        self.choose.pack(expand='yes', anchor='center')
        self.choose .bind("<Enter>", lambda e: mouse_hover(self.choose, color='#bbfa68'))
        self.choose .bind("<Leave>", lambda e: mouse_not_hover(self.choose, color="#f0f0f0"))

        # 显示图片信息,包括图片路径和图片尺寸
        self.info_frame = tk.Frame(self.root)
        self.info_frame.pack(fill="x")
        self.info_bar = tk.Label(self.info_frame, font=('宋体', 13))
        self.info_bar.pack()

        # 显示统计信息
        self.status_frame = tk.Frame(self.root, background='#BCBCBC')
        self.status_bar = tk.Label(self.status_frame, font=('黑体', 14), background='#BCBCBC')
        self.status_bar.pack(side='left', padx=10, pady=10)

        # 删除图片按键布置
        delete_button = tk.Button(self.status_frame,
                        image=self.delete_icon,
                        compound="left",
                        text="删除图片",
                        cursor="hand2",
                        padx=10,
                        borderwidth=3,
                        background="#f0f0f0",
                        command=self.delete_image)
        delete_button.pack(side='right', padx=10, pady=10)
        delete_button.bind("<Enter>", lambda e: mouse_hover(delete_button, color='#ff0000'))
        delete_button.bind("<Leave>", lambda e: mouse_not_hover(delete_button, color='#f0f0f0'))

        # 保存图像按键布置
        save_button = tk.Button(self.status_frame,
                        image=self.save_icon,
                        compound="left",
                        text="保存图片",
                        cursor="hand2",
                        padx=10,
                        borderwidth=3,
                        background="#f0f0f0",
                        command=self.save_file)
        save_button.pack(side='right', padx=10, pady=10)
        save_button.bind("<Enter>", lambda e: mouse_hover(save_button, color='#b3f7fd'))
        save_button.bind("<Leave>", lambda e: mouse_not_hover(save_button, color='#f0f0f0'))

        # 打开图像按键布置
        open_button = tk.Button(self.status_frame,
                        image=self.open_icon,
                        compound="left",
                        text="打开图片",
                        cursor="hand2",
                        padx=10,
                        borderwidth=3,
                        background="#f0f0f0",
                        command=self.openfile)
        open_button.pack(side='right', padx=10, pady=10)
        open_button.bind("<Enter>", lambda e: mouse_hover(open_button, color='#b3f7fd'))
        open_button.bind("<Leave>", lambda e: mouse_not_hover(open_button, color='#f0f0f0'))

        # 将窗口关闭事件与window_close函数关联
        self.root.protocol("WM_DELETE_WINDOW", self.window_close)

        self.root.mainloop()

    # 定义函数,用于打开文件选择对话框
    def choose_file(self):
        img_path = filedialog.askopenfilename(
            title='请选择图片文件',
            # 筛选常见图片文件
            filetypes=[('图片', '.jpg .png .gif .bmp .jpeg')],
            )
        if img_path and img_path.endswith(('.jpg', '.png', '.gif', '.jpeg', '.bmp')):
            self.path = img_path
            self.dir = path.split(self.path)[0]
            self.images_get()
            self.choose.destroy()
            self.main_window()

    # 图片路径获取后,将图片路径存放在self.result_images列表中
    def images_get(self):
        # 定义一个小函数,判断是否是图片
        def is_image(path):
            if path.endswith(('.gif', '.jpg', '.jpeg', '.png', '.bmp')):
                return True
            else:
                return False
        # listdir()函数用于列出指定目录下所有的文件和子目录
        files = [self.dir + f'/{name}' for name in listdir(self.dir)]
        self.result_images = list(filter(is_image, files))
        self.all_images = len(self.result_images)

    # 创建主界面组件
    def main_window(self):
        # 进入主界面之前先打开源图像
        self.open_source_image()

        # 创建顶部的菜单栏
        self.mnu = tk.Menu(self.root)
        filemenu = tk.Menu(self.mnu, tearoff=0)
        self.mnu.add_cascade(label='文件', menu=filemenu)
        filemenu.add_command(label='打开', command=self.openfile)
        filemenu.add_command(label='另存为', command=self.save_file)
        filemenu.add_command(label='删除文件', command=self.delete_image)

        help_menu = tk.Menu(self.mnu, tearoff=0)
        help_menu.add_command(label="关于程序", command=self.about_image_browse)
        help_menu.add_command(label="程序讲解", command=self.image_browse_help)
        help_menu.add_separator()  
        help_menu.add_command(label="退出", command=self.window_close)
        self.mnu.add_cascade(label="帮助", menu=help_menu)

        # 放置菜单栏
        self.root.config(menu=self.mnu)

        # 限制窗口显示最小尺寸
        self.root.minsize(1000, int(self.size[1])+100)

        # 调用show函数显示图像
        self.show()

        # 操作按钮布置
        # “in_”参数用于指定组件的父容器
        button_frame = tk.Frame(self.root)
        button_frame.pack(in_=self.root, side='bottom')

        # 放大按键布置
        bigger = tk.Button(button_frame,
                    image=self.big_icon,
                    relief='flat',
                    background='#f0f0f0',
                    cursor="hand2",
                    command=lambda: self.image_size_change(1))
        bigger.grid(row=0, column=4)
        bigger.bind("<Enter>", lambda e: mouse_hover(bigger, color='#ffffff'))
        bigger.bind("<Leave>", lambda e: mouse_not_hover(bigger, color="#f0f0f0"))

        # 缩小按键布置
        smaller = tk.Button(button_frame,
                        image=self.small_icon,
                        relief='flat',
                        background='#f0f0f0',
                        cursor="hand2",
                        command=lambda: self.image_size_change(0))
        smaller.grid(row=0, column=6)
        smaller.bind("<Enter>", lambda e: mouse_hover(smaller, color='#ffffff'))
        smaller.bind("<Leave>", lambda e: mouse_not_hover(smaller, color="#f0f0f0"))

        # 逆时针旋转按键布置
        reverse_rotate = tk.Button(button_frame,
                        image=self.left_icon,
                        relief='flat',
                        background='#f0f0f0',
                        cursor="hand2",
                        command=lambda: self.rotate_image(0))
        reverse_rotate.grid(row=0, column=2)
        reverse_rotate.bind("<Enter>", lambda e: mouse_hover(reverse_rotate, color='#ffffff'))
        reverse_rotate.bind("<Leave>", lambda e: mouse_not_hover(reverse_rotate, color="#f0f0f0"))

        # 顺时针旋转按键布置
        correct_rotate = tk.Button(button_frame,
                        image=self.right_icon,
                        relief='flat',
                        background='#f0f0f0',
                        cursor="hand2",
                        command=lambda: self.rotate_image(1))
        correct_rotate.grid(row=0, column=8)
        correct_rotate.bind("<Enter>", lambda e: mouse_hover(correct_rotate, color='#ffffff'))
        correct_rotate.bind("<Leave>", lambda e: mouse_not_hover(correct_rotate, color="#f0f0f0"))

        # 切换上一张按键布置
        previous = tk.Button(button_frame,
                    image=self.previous_icon,
                    relief='flat',
                    background='#f0f0f0',
                    cursor="hand2",
                    command=lambda: self.turn_page(0))
        previous.grid(row=0, column=0)
        previous.bind("<Enter>", lambda e: mouse_hover(previous, color='#ffffff'))
        previous.bind("<Leave>", lambda e: mouse_not_hover(previous, color="#f0f0f0"))

        # 切换下一张按键布置
        next = tk.Button(button_frame,
                    image=self.next_icon,
                    relief='flat',
                    background='#f0f0f0',
                    cursor="hand2",
                    command=lambda: self.turn_page(1))
        next.grid(row=0, column=10)
        next.bind("<Enter>", lambda e: mouse_hover(next, color='#ffffff'))
        next.bind("<Leave>", lambda e: mouse_not_hover(next, color="#f0f0f0"))

        self.status_frame.pack(fill="x", side='bottom')

    # 定义打开图像方法
    def open_image(self, file_path):
        try:
            self.source_img = Image.open(file_path)
            return self.source_img
        except UnidentifiedImageError as e:
            return None

    # 打开源图像,获取图像数据,根据self.path来更新当前图像参数
    def open_source_image(self):
        self.source_img = self.open_image(self.path)
        if self.source_img:
            self.size = self.source_img.size
            self.default_image = self.source_img
            try:
                self.result_image = ImageTk.PhotoImage(self.source_img)
            except:
                return None
        else:
            # 如果源图像打开异常,则显示提示图像信息
            self.source_img = prompt_image
            self.size = self.source_img.size
            self.default_image = self.source_img
            try:
                self.result_image = ImageTk.PhotoImage(self.source_img)
            except:
                return None

    # 利用tkinter组件显示图像
    def show(self):
        # 计算图像在文件夹中的位置
        index = self.result_images.index(self.path)
        self.status_bar.configure(text=f"显示:第{index + 1}张 / 共{len(self.result_images)}张")
        self.info_bar.configure(text=f'图片信息 | {self.path}【尺寸:{self.size[0]}x{self.size[1]}】')
        # tkinter的Label组件中显示图像
        self.lab = tk.Label(self.root, bg='#BCBCBC')
        self.lab['image'] = self.result_image
        # bind函数绑定键盘左右键,对图像前后翻页
        self.lab.bind('<Left>', lambda event: self.turn_page(0))
        self.lab.bind('<Right>', lambda ev: self.turn_page(1))
        self.lab.focus_set()
        # 右击鼠标显示菜单栏
        self.lab.bind('<Button-3>', self.right_mouse)
        self.lab.pack(anchor='center', expand='yes', fill='both')

    # 下一个或上一个图片翻页
    def turn_page(self, norp):
        index = self.result_images.index(self.path)
        # 默认下一张
        new_index = (index + 1) % self.all_images
        if not norp:
            if not index:
                new_index = self.all_images - 1
            else:
                new_index = (index - 1) % self.all_images
        self.path = self.result_images[new_index]
        self.open_source_image()
        self.lab.destroy()
        self.show()

    # 顺时针或者逆时针旋转图片
    def rotate_image(self, direction):
        # 设置旋转角度为90度
        angle = 90
        # direction=1表示顺时针,否则表示逆时针
        if direction:
            angle = -90
        self.source_img = self.source_img.rotate(angle, expand=True)
        self.size = self.source_img.size
        self.default_image = self.default_image.rotate(angle, expand=True)
        self.result_image = ImageTk.PhotoImage(self.default_image)
        self.lab.destroy()
        self.show()

    # 更改图像大小
    # 需要改变和保留self.default_image,旋转时需要用到
    def image_size_change(self, bors):
        # 变大或者变小
        if_change = 0
        if (self.upper > .1) and (not bors):
            if_change = 1
            self.upper -= .1
        elif (self.upper < 8) and bors:
            if_change = 1
            self.upper += .15
        if if_change:
            new_size = (int(self.size[0]*self.upper), int(self.size[1]*self.upper))
            self.default_image = self.source_img.resize(new_size)
            self.result_image = ImageTk.PhotoImage(self.default_image)
            self.lab.destroy()
            self.show()

    # 点击鼠标右键显示菜单栏
    def right_mouse(self, event):
        self.mmnu = tk.Menu(self.root, tearoff=0)
        self.mmnu.add_command(label='打开', command=self.openfile)
        self.mmnu.add_command(label='另存为', command=self.save_file)
        self.mmnu.add_command(label='删除文件', command=self.delete_image)
        self.mmnu.post(x=event.x_root, y=event.y_root)

    # 定义函数,用于打开文件选择对话框
    def openfile(self):
        img_path = filedialog.askopenfilename(
            title='请选择图片文件',
            # 筛选常见图片文件
            filetypes=[('图片', '.jpg .png .gif .bmp .jpeg')],
        )
        if img_path and img_path.endswith(('.jpg', '.png', '.gif', '.jpeg', '.bmp')):
            self.path = img_path
            self.dir = path.split(self.path)[0]
            self.images_get()
            self.lab.destroy()
            self.open_source_image()
            self.show()

    # 删除已打开的图像,删除后不可恢复
    def delete_image(self):
        if messagebox.askyesno('确认', '是否彻底删除该图片?删除后不可恢复'):
            out_path = self.path
            self.turn_page(1)
            self.result_images.pop(self.result_images.index(out_path))
            self.all_images -= 1
            remove(out_path)
            messagebox.showinfo('完毕', '图片已彻底删除')
            self.images_get()
            # 重新计算图像在文件夹中的位置
            index = self.result_images.index(self.path)
            self.status_bar.configure(text=f"显示:第{index + 1}张 / 共{len(self.result_images)}张")

    # 保存图像
    def save_file(self):
        try:
            # 弹出保存文件对话框
            file_path = filedialog.asksaveasfilename(
                defaultextension='.jpg',
                    filetypes=[
                    ("JPG文件", "*.jpg"),
                    ("PNG文件", "*.png"),
                    ],
                )

            # 获取用户输入的扩展名
            image_name = file_path.split('.')[-1]

            # 检查用户是否取消了保存操作
            if not file_path:
                return  # 用户点击了取消按钮

            # 如果用户输入的扩展名是png,则保留透明背景
            if image_name == "png":
                try:
                    # 将PhotoImage转换为PIL的Image对象
                    # convert()方法将图片转换为RGBA模式(一种包含红色、绿色、蓝色和透明度四个通道的颜色模式)
                    pil_image = ImageTk.getimage(self.result_image).convert("RGBA")
                    # 保存为png格式,压缩质量为95%最高质量
                    pil_image.save(file_path, 'PNG', quality=95)
                    messagebox.showinfo('保存成功', f'图像已成功保存为“{file_path}”')
                    self.images_get()
                    # 重新计算图像在文件夹中的位置
                    index = self.result_images.index(self.path)
                    self.status_bar.configure(text=f"显示:第{index + 1}张 / 共{len(self.result_images)}张")
                except Exception as e:
                    messagebox.showinfo('失败', f'图像保存失败:“{e}”')

            # 如果用户输入的扩展名是jpg,则将透明背景转换成白色背景
            elif image_name == "jpg":
                try:
                    # 将PhotoImage转换为PIL的Image对象
                    # convert()方法将图片转换为RGB模式(一种包含红色、绿色、蓝色三个通道的颜色模式)
                    pil_image = ImageTk.getimage(self.result_image)
                    # 转换图像模式为RGB,并添加白色背景
                    background = Image.new('RGB', pil_image.size, (255, 255, 255))
                    background.paste(pil_image, mask=pil_image.split()[-1])  # 使用透明度通道作为蒙版
                    original_image = background
                    # 保存为jpg格式,压缩质量为95%最高质量
                    original_image.save(file_path, 'JPEG', quality=95)
                    messagebox.showinfo('保存成功', f'图像已成功保存为“{file_path}”')
                    self.images_get()
                    # 重新计算图像在文件夹中的位置
                    index = self.result_images.index(self.path)
                    self.status_bar.configure(text=f"显示:第{index + 1}张 / 共{len(self.result_images)}张")
                except Exception as e:
                    messagebox.showinfo('失败', f'图像保存失败:“{e}”')

            # 如果用户输入其它的扩展名则提示错误
            else:
                messagebox.showerror("错误", "请确保文件名以.jpg或.png结尾")
                return  # 用户输入了错误的文件扩展名,返回重新选择

        except Exception as e:
            messagebox.showerror("错误", f"保存文件时发生错误:{e}")

    # 关于图片浏览程序
    def about_image_browse(self):
        about = tk.Tk()
        about.title('关于图片浏览程序')

        # 设置窗口居中
        window_width = 630
        window_height = 460
        screen_width = about.winfo_screenwidth()
        screen_height = about.winfo_screenheight()
        x = (screen_width - window_width) / 2
        y = (screen_height - window_height) / 2
        about.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
        about.resizable(width=False, height=False)

        about_frame = tk.Frame(about, width=630, height=460)
        about_frame.pack()
        tk.Label(about_frame, text='图片浏览程序', font=("宋体", 16)).place(x=220, y=20)
        tk.Label(about_frame, text='使用编程语言:Python', font=("宋体", 14)).place(x=50, y=90)
        tk.Label(about_frame, text='打开图像:支持打开后缀名为jpg、jpeg、png、gif、bmp的图像', font=("宋体", 14)).place(x=50, y=150)
        tk.Label(about_frame, text='保存图像:可以将图像保存为.jpg或.png后缀名的图像文件', font=("宋体", 14)).place(x=50, y=210)
        tk.Label(about_frame, text='编辑图像:支持旋转图像、放大和缩小图像', font=("宋体", 14)).place(x=50, y=270)
        tk.Label(about_frame, text='图像翻页:点击键盘左、右键,支持对图像前后翻页', font=("宋体", 14)).place(x=50, y=330)
        tk.Label(about_frame, text='创作者:www.pyhint.com', font=("宋体", 14)).place(x=50, y=390)
        about.mainloop()

    # 图片浏览程序讲解页面
    def image_browse_help(self):
        webbrowser.open("https://www.pyhint.com/article/164.html")

    # 点击关闭窗口触发函数
    def window_close(self):
        # 弹出确认对话框
        if messagebox.askokcancel("退出", "你确定要退出吗?"):
            # 点击确定后关闭窗口
            self.root.destroy()

# 当前模块直接被执行
if __name__ == "__main__":
    # 创建主窗口
    app = ImageBrowse()