Python基于Tkinte设计简易的绘图工具实现画图软件功能(第29节)


虽然Python在人工智能领域和数据处理方面被广泛运用,但是作为一种强大而灵活的编程语言,对于日常简单的应用,Python也提供了非常友好的支持。本节教程将介绍如何通过Python的Tkinter库,结合PIL图像处理库设计一个绘图工具,开发简单的画图小软件。

1、Python绘图工具介绍

我们的目标是使用Python基于Tkinter设计和构建一个基本的绘图应用程序,在这里我们可以简单地使用铅笔在画布上绘制不同的图形,在右边的工具栏中有铅笔画图、画直线、画矩形、画圆形、添加文本、橡皮擦、颜色填充、设置前景色和设置背景色等功能。顶部的主菜单有导入图片、保存图片、清屏、撤销操作等功能。

在工具栏中,可以使用橡皮擦擦除已绘制的图形,以及可以改变铅笔和橡皮擦的粗细,添加文本时同样可以选择文字输入的大小。我们还可以修改画布的背景颜色并将已绘制的图像保存在我们的本地计算机上。

Python绘图工具设计思路

使用Python的Tkinter标准库快速创建GUI应用程序,主要通过Tkinter库的Canvas控件提供了一个自定义的绘图区域,程序中通过不同的函数来绘制不同的图形。

页面布局:绘图工具主要分为左右两部分,左部分为绘图区域,右部分为工具栏区域(功能区),工具栏内提供不同的按钮以实现不同的绘制效果。

事件监听:通过给工具栏内的按钮绑定事件,来实现不同的功能,包括绘制直线、矩形、圆形等功能。

绘图区域:监听鼠标左键的按下(开始绘图)和抬起(停止绘图),再根据右边工具栏内不同的功能按钮实现不同的操作。

导入图像:可导入后缀名为jpg、png、gif的图像,导入后可在画布上呈现图片,还可以对已导入的图像进行绘画。

保存图像:点击菜单栏中的“保存”按钮即可保存已绘制的图像,可以保存为指定后缀名的图像文件,包括jpg、png、gif图像。

清屏:顾名思义,清理画布上已绘制的所有图像。

撤销:即返回上一步绘制操作。

快捷操作:在画布上直接右击鼠标,可弹出菜单栏中的菜单。

注意:使用矩形或圆形工具在画布上绘制一个矩形或圆形,默认情况下图形填充颜色是背景色白色,边框颜色是前景色黑色,如果想重新填充颜色,可以在工具栏内点击“颜色填充”按钮,选择目标颜色后再点击已绘制的矩形或圆形,就可以实现颜色填充操作。颜色选择可以在输入框内输入指定的十六进制颜色代码,当输入框被编辑时会自动启用验证,检查十六进制颜色代码是否错误。

2、Python绘图工具界面演示

Python基于Tkinte设计简易的绘图工具实现画图软件功能

3、代码实现

(1)安装PIL库

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

pip install Pillow

Pillow(Python Imaging Library)简称PIL,是Python的第三方图像处理库,支持多种图像文件格式处理,提供丰富的图像操作功能,包括打开、编辑、保存为多种格式的图像文件。

(2)Python绘图工具,完整代码如下所示:

动手练一练:

import tkinter as tk
from tkinter import ttk, DOTBOX
from PIL import Image, ImageTk, ImageGrab
from tkinter import messagebox, colorchooser, filedialog
import webbrowser

# 定义DrawTool类,用于封装绘图程序的功能
class DrawTool(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.master = master
        self.pack()

        self.temp = []  # 保存图形的类型
        self.li = []    # 保存所画图形的坐标
        self.fill_color = None # 保存填充的颜色
        self.text = None # 保存文本内容

        self.lastDraw = 0
        self.end = [0]

        self.yesno = 0
        self.function = 1   # 打开程序时,默认使用铅笔工具
        self.X = 0
        self.Y = 0

        # 默认前景颜色为黑色
        self.foreColor = '#000000'
        # 默认背景颜色为白色
        self.backColor = '#FFFFFF'

        self.draw_app_widget()
        self.setMenu()

    # 创建绘图工具窗口组件
    def draw_app_widget(self):
        # 创建新的PhotoImage对象
        self.image = tk.PhotoImage()
        # 创建Canvas画布
        self.canvas = tk.Canvas(root, borderwidth=0, highlightthickness=0, bg='white', width=canvas_width, height=canvas_height)
        self.canvas.create_image(canvas_width, canvas_height, image=self.image)

        # 鼠标点击事件绑定
        self.canvas.bind('<Button-1>', self.onLeftButtonDown)
        self.canvas.bind('<B1-Motion>', self.onLeftButtonMove)
        self.canvas.bind('<ButtonRelease-1>', self.onLeftButtonUp)
        self.canvas.bind('<ButtonRelease-3>', self.onRightButtonUp)
        self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.canvas.config(cursor="pencil")

        # 在右边"工具栏"创建工具按钮
        self.tool_frame = ttk.LabelFrame(root, text="工具栏")
        self.tool_frame.pack(side=tk.RIGHT, padx=5, pady=5, fill=tk.Y)

        self.pencil_frame = ttk.LabelFrame(self.tool_frame)
        self.pencil_frame.pack(side=tk.TOP)
        self.pencil_button = tk.Button(self.pencil_frame, text="铅笔", command=lambda:self.pencilDraw(self.buttons[0]), width=10)
        self.pencil_button.pack(side=tk.LEFT, padx=5, pady=5)
        self.choose_pencil_size = tk.Scale(self.pencil_frame, from_=1, to=20, orient=tk.HORIZONTAL)
        self.choose_pencil_size.pack(side=tk.LEFT, padx=5)
        self.pencil_button.config(bg='#aaffff')

        self.line_frame = ttk.LabelFrame(self.tool_frame)
        self.line_frame.pack(side=tk.TOP)
        self.line_button = tk.Button(self.line_frame, text="直线", command=lambda:self.drawLine(self.buttons[1]), width=10)
        self.line_button.pack(side=tk.LEFT, padx=5, pady=5)
        self.choose_line_size = tk.Scale(self.line_frame, from_=1, to=20, orient=tk.HORIZONTAL)
        self.choose_line_size.pack(side=tk.LEFT, padx=5)

        self.rectangle_frame = ttk.LabelFrame(self.tool_frame)
        self.rectangle_frame.pack(side=tk.TOP)
        self.rectangle_button = tk.Button(self.rectangle_frame, text="矩形", command=lambda:self.drawRectangle(self.buttons[2]), width=10)
        self.rectangle_button.pack(side=tk.LEFT, padx=5, pady=5)
        self.choose_rectangle_size = tk.Scale(self.rectangle_frame, from_=1, to=20, orient=tk.HORIZONTAL)
        self.choose_rectangle_size.pack(side=tk.LEFT, padx=5)

        self.circle_frame = ttk.LabelFrame(self.tool_frame)
        self.circle_frame.pack(side=tk.TOP)
        self.circle_button = tk.Button(self.circle_frame, text="圆形", command=lambda:self.drawCircle(self.buttons[3]), width=10)
        self.circle_button.pack(side=tk.LEFT, padx=5, pady=5)
        self.choose_circle_size = tk.Scale(self.circle_frame, from_=1, to=20, orient=tk.HORIZONTAL)
        self.choose_circle_size.pack(side=tk.LEFT, padx=5)

        self.text_frame = ttk.LabelFrame(self.tool_frame)
        self.text_frame.pack(side=tk.TOP)
        self.text_button = tk.Button(self.text_frame, text="文本", command=lambda:self.drawText(self.buttons[4]), width=10)
        self.text_button.pack(side=tk.LEFT, padx=5, pady=5)
        self.choose_text_size = tk.Scale(self.text_frame, from_=10, to=50, orient=tk.HORIZONTAL, command=self.get_value)
        self.choose_text_size.pack(side=tk.LEFT, padx=5)
        self.choose_text_size.set(20)

        self.eraser_frame = ttk.LabelFrame(self.tool_frame)
        self.eraser_frame.pack(side=tk.TOP)
        self.erase_button = tk.Button(self.eraser_frame, text="橡皮擦", command=lambda:self.onErase(self.buttons[5]), width=10)
        self.erase_button.pack(side=tk.LEFT, padx=5, pady=5)
        self.choose_eraser_size = tk.Scale(self.eraser_frame, from_=1, to=20, orient=tk.HORIZONTAL)
        self.choose_eraser_size.pack(side=tk.LEFT, padx=5)
        self.choose_eraser_size.set(5)

        # 填充颜色
        self.fill_color_frame = ttk.LabelFrame(self.tool_frame)
        self.fill_color_frame.pack(side=tk.TOP)

        self.fill_color_chooser = tk.Button(self.fill_color_frame,
            text="颜色填充",
            command = lambda:self.fill_color_change(self.buttons[6]),
            width=10,
            )
        self.fill_color_chooser.pack(side=tk.LEFT, padx=5, pady=5)

        self.input_fill_color = tk.StringVar()
        self.input_fill_color.set("#FFFFFF")
        change_fill_color = root.register(self.change_fill_color)
        self.enter_fill_color = tk.Entry(self.fill_color_frame,
                textvariable=self.input_fill_color,
                width=8,
                validate='key', # 当输入框被编辑时启用验证
                validatecommand=(change_fill_color, '%P'),
                )
        self.enter_fill_color.pack(side=tk.LEFT, padx=5)

        self.show_fill_color = tk.Frame(self.fill_color_frame)
        self.show_fill_color.pack(expand=tk.YES, fill=tk.BOTH, side=tk.LEFT, padx=5)

        self.fill_color_set= tk.Button(self.show_fill_color, 
                                       text="", 
                                       bg="#FFFFFF", 
                                       command=lambda:self.fill_color_change(self.buttons[6]), 
                                       width=5
                                       )
        self.fill_color_set.pack(fill=tk.BOTH, expand=True)

        # 选择前景色
        self.fore_color_frame = ttk.LabelFrame(self.tool_frame)
        self.fore_color_frame.pack(side=tk.TOP)

        fore_color_chooser = tk.Button(self.fore_color_frame,
            text="选择前景色",
            command = self.fore_color_change,
            width=10,
            )
        fore_color_chooser.pack(side=tk.LEFT, padx=5, pady=5)

        self.input_fore_color = tk.StringVar()
        self.input_fore_color.set("#000000")
        change_fore_color = root.register(self.change_fore_color)
        self.enter_fore_color = tk.Entry(self.fore_color_frame,
                textvariable=self.input_fore_color,
                width=8,
                validate='key', # 当输入框被编辑时启用验证
                validatecommand=(change_fore_color, '%P'),
                )
        self.enter_fore_color.pack(side=tk.LEFT, padx=5)

        self.show_fore_color = tk.Frame(self.fore_color_frame)
        self.show_fore_color.pack(expand=tk.YES, fill=tk.BOTH, side=tk.LEFT, padx=5)

        self.fore_color_set= tk.Button(self.show_fore_color, text="", bg="#000000", command=self.fore_color_change, width=5)
        self.fore_color_set.pack(fill=tk.BOTH, expand=True)

        # 选择背景色
        self.back_color_frame = ttk.LabelFrame(self.tool_frame)
        self.back_color_frame.pack(side=tk.TOP)

        back_color_chooser = tk.Button(self.back_color_frame,
            text="选择背景色",
            command = self.back_color_change,
            width=10,
            )
        back_color_chooser.pack(side=tk.LEFT, padx=5, pady=5)

        self.input_back_color = tk.StringVar()
        self.input_back_color.set("#FFFFFF")
        change_back_color = root.register(self.change_back_color)
        self.enter_back_color = tk.Entry(self.back_color_frame,
                textvariable=self.input_back_color,
                width=8,
                validate='key', # 当输入框被编辑时启用验证
                validatecommand=(change_back_color, '%P'),
                )
        self.enter_back_color.pack(side=tk.LEFT, padx=5)

        self.show_back_color = tk.Frame(self.back_color_frame)
        self.show_back_color.pack(expand=tk.YES, fill=tk.BOTH, side=tk.LEFT, padx=5)

        self.back_color_set= tk.Button(self.show_back_color, text="", bg="#FFFFFF", command=self.back_color_change, width=5)
        self.back_color_set.pack(fill=tk.BOTH, expand=True)

        # 改变画布背景
        self.bg_btn = tk.Button(self.tool_frame, text="改变画布背景", command=self.canvas_color, width=30)
        self.bg_btn.pack(side=tk.TOP, padx=10, pady=10)

        # 将按钮保存到buttons列表中
        self.buttons = [self.pencil_button,
        self.line_button,
        self.rectangle_button,
        self.circle_button,
        self.text_button,
        self.erase_button,
        self.fill_color_chooser
        ]

    # 将Scale组件中获取的值转换为整数
    def get_value(self, value):
        self.value_int = int(value)

    # 定义函数,用于改变填充颜色
    def change_fill_color(self, color):
        try:
            self.fill_color_set['bg'] = color
        except:
            pass
        return True

    # 选择指定的颜色
    def fill_color_change(self, button):
        # 重置所有按钮颜色为正常颜色
        for default_button in self.buttons:
            default_button.config(bg='SystemButtonFace')  # 使用系统按钮背景色作为正常颜色

        # 将被点击的按钮颜色设置为淡蓝色
        button.config(bg='#aaffff')

        try:
            # 使用askcolor显示颜色选择器,并设置初始颜色
            color = colorchooser.askcolor(title="请选择填充颜色", initialcolor=self.enter_fill_color.get())
            if color[1] != None:
                self.input_fill_color.set(color[1])
                self.fill_color = color[1]
            self.canvas.config(cursor="cross")
            self.function = 7
        except:
            # 如果颜色值输入错误,则弹出提示框
            messagebox.showerror("错误", f"颜色输入值错误“{self.enter_fill_color.get()}”")
            color = colorchooser.askcolor(title="请选择填充颜色", initialcolor="#FFFFFF")
            if color[1] != None:
                self.input_fill_color.set(color[1])
                self.fill_color = color[1]
            self.canvas.config(cursor="cross")
            self.function = 7

    # 定义函数,用于改变前景颜色
    def change_fore_color(self, color):
        try:
            self.fore_color_set['bg'] = color
        except:
            pass
        return True

    # 选择指定的颜色
    def fore_color_change(self):
        try:
            # 使用askcolor显示颜色选择器,并设置初始颜色
            color = colorchooser.askcolor(title="请选择填充颜色", initialcolor=self.enter_fore_color.get())
            if color[1] != None:
                self.input_fore_color.set(color[1])
                self.foreColor = color[1]
            self.canvas.config(cursor="arrow")
        except:
            # 如果颜色值输入错误,则弹出提示框
            messagebox.showerror("错误", f"颜色输入值错误“{self.enter_fore_color.get()}”")
            color = colorchooser.askcolor(title="请选择填充颜色", initialcolor="#000000")
            if color[1] != None:
                self.input_fore_color.set(color[1])
                self.foreColor = color[1]
            self.canvas.config(cursor="arrow")

    # 定义函数,用于改变背景颜色
    def change_back_color(self, color):
        try:
            self.back_color_set['bg'] = color
        except:
            pass
        return True

    # 选择指定的颜色
    def back_color_change(self):
        try:
            # 使用askcolor显示颜色选择器,并设置初始颜色
            color = colorchooser.askcolor(title="请选择填充颜色", initialcolor=self.enter_back_color.get())
            if color[1] != None:
                self.input_back_color.set(color[1])
                self.backColor = color[1]
            self.canvas.config(cursor="arrow")
        except:
            # 如果颜色值输入错误,则弹出提示框
            messagebox.showerror("错误", f"颜色输入值错误“{self.enter_back_color.get()}”")
            color = colorchooser.askcolor(title="请选择填充颜色", initialcolor="#FFFFFF")
            if color[1] != None:
                self.input_back_color.set(color[1])
                self.backColor = color[1]
            self.canvas.config(cursor="arrow")

    # 创建窗口菜单栏
    def setMenu(self):
        self.menu = tk.Menu(self, bg='#33b3fd')
        root.config(menu=self.menu)
        self.menu.add_command(label='导入', command=self.Import)
        self.menu.add_command(label='保存', command=self.SavePicture)
        self.menu.add_command(label='清屏', command=self.Clear)
        self.menu.add_command(label='撤销', command=self.Back)

        add_menu = tk.Menu(self.menu, tearoff=0)
        add_menu.add_command(label="关于程序", command=self.about_draw_app)
        add_menu.add_command(label="程序讲解", command=self.draw_help_window)
        add_menu.add_separator()  
        add_menu.add_command(label="退出", command=root.quit)
        self.menu.add_cascade(label="帮助", menu=add_menu)

    # 从本地电脑导入图像文件
    def Import(self):
        filename = filedialog.askopenfilename(title='导入图片', filetypes=[('image', '*.jpg *.png *.gif')])
        if filename:
            # 打开本地图片并转换为RGBA模式
            self.image = Image.open(filename)
            if self.image.mode!= 'RGBA':
                self.image = self.image.convert('RGBA')
            get_width, get_height = self.image.size
            self.image = self.image.resize((get_width, get_height), Image.Resampling.LANCZOS)
            # ImageTk.PhotoImage将PIL图像对象转换为Tkinter可显示格式的类
            # 解决PIL与Tkinter内部图像格式不兼容的问题
            self.image = ImageTk.PhotoImage(self.image)
            # 在Canvas画布上加载图像,anchor参数设置为“nw”,确保图像的左上角与Canvas的左上角对齐
            self.canvas.create_image(0, 0, image=self.image, anchor='nw')

    # 保存画布
    def SavePicture(self):
        try:
            # 创建保存文件对话框,允许用户选择文件保存路径并指定文件名或文件扩展名
            file_save = filedialog.asksaveasfilename(
                defaultextension='*.jpg',
                filetypes=[
                ("JPG files", "*.jpg"),
                ("PNG files", "*.png"),
                ("GIF files", "*.gif"),
                ],
            )
            # 左点坐标
            x = self.master.winfo_rootx() + self.canvas.winfo_x()
            # 上点坐标
            y = self.master.winfo_rooty() + self.canvas.winfo_y()
            # 右点坐标
            x1 = x + self.canvas.winfo_width()
            # 下点坐标
            y1 = y + self.canvas.winfo_height()
            # crop()方法定义裁剪区域(坐标为左、上、右、下四个点)
            # save()方法保存结果图片,压缩质量为95%最高质量
            ImageGrab.grab().crop((x, y, x1, y1)).save(file_save, quality=95)
            messagebox.showinfo('保存成功', f'图像已成功保存为“{file_save}”')
        except:
            pass

    # 画布清屏
    def Clear(self):
        for item in self.canvas.find_all():
            self.canvas.delete(item)
        # 清屏后对数据进行初始化
        self.temp.clear()
        self.end.clear()
        self.li.clear()

    # 撤回已绘制的操作
    def Back(self):
        items = self.canvas.find_all()
        if items:
            self.canvas.delete(items[-1])
        try:
            self.end.pop()
            self.li.pop()
        except:
            self.end = [0]

    # 点击鼠标左键执行操作
    def onLeftButtonDown(self, event):
        self.yesno = 1
        self.X = event.x
        self.Y = event.y

        # 点击鼠标左键执行颜色填充
        if self.function == 7:
            for i in range(len(self.li)):
                if (self.X >= self.li[i][0] and self.X <= self.li[i][2]) and (self.Y >= self.li[i][1] and self.Y <= self.li[i][3]):
                    if self.temp[i] == 'rect':
                        rect = self.canvas.create_rectangle(self.li[i][0], self.li[i][1], self.li[i][2], self.li[i][3])
                        self.canvas.itemconfig(rect, fill=self.fill_color)
                        self.end.append(rect)   # 加入撤销列表

                    elif self.temp[i] == 'oval':
                        oval = self.canvas.create_oval(self.li[i][0], self.li[i][1], self.li[i][2], self.li[i][3])
                        self.canvas.itemconfig(oval, fill=self.fill_color)
                        self.end.append(oval)  # 加入撤销列表
                    break

        # 点击鼠标左键执行文本绘制
        if self.function == 4:
            self.canvas.create_text(event.x, event.y, font=("等线", self.value_int), text=self.text, fill=self.foreColor)

    # 按下鼠标左键并移动后执行操作
    def onLeftButtonMove(self, event):
        if self.yesno == 0:
            return

        if self.function == 1:    # 铅笔绘图
            self.pencil_width = self.choose_pencil_size.get()
            self.lastDraw = self.canvas.create_line(self.X, self.Y, event.x, event.y, width=self.pencil_width, fill=self.foreColor, capstyle=tk.ROUND, smooth=tk.TRUE, splinesteps=36)
            self.X = event.x
            self.Y = event.y

        elif self.function == 2:  # 画直线
            try:
                self.canvas.delete(self.lastDraw)
            except Exception:
                pass
            self.line_width = self.choose_line_size.get()
            self.lastDraw = self.canvas.create_line(self.X, self.Y, event.x, event.y, width=self.line_width, fill=self.foreColor, capstyle=tk.ROUND, smooth=tk.TRUE, splinesteps=36)

        elif self.function == 3:  # 画矩形
            try:
                self.canvas.delete(self.lastDraw)
            except Exception:
                pass
            self.rectangle_width = self.choose_rectangle_size.get()
            self.lastDraw = self.canvas.create_rectangle(self.X, self.Y, event.x, event.y, width=self.rectangle_width, fill=self.backColor, outline=self.foreColor)

        elif self.function == 5:  # 橡皮擦
            self.eraser_width = self.choose_eraser_size.get()
            self.lastDraw = self.canvas.create_line(self.X, self.Y, event.x, event.y, width=self.eraser_width, fill=self.backColor, capstyle=tk.ROUND, smooth=tk.TRUE, splinesteps=36)
            self.X = event.x
            self.Y = event.y

        elif self.function == 6:  # 画圆
            try:
                self.canvas.delete(self.lastDraw)
            except Exception:
                pass
            self.circle_width = self.choose_circle_size.get()
            self.lastDraw = self.canvas.create_oval(self.X, self.Y, event.x, event.y, width=self.circle_width, fill=self.backColor, outline=self.foreColor)

    # 鼠标左键释放后执行操作
    def onLeftButtonUp(self, event):
        if self.function == 2:
            self.lastDraw = self.canvas.create_line(self.X, self.Y, event.x, event.y, fill=self.foreColor)

        elif self.function == 3:    # 正方形操作
            self.lastDraw = self.canvas.create_rectangle(self.X, self.Y, event.x, event.y, outline=self.foreColor)
            self.li.append((self.X, self.Y, event.x, event.y))  # 保存图型的坐标
            self.temp.append('rect')

        elif self.function == 6:    # 圆形操作
            self.lastDraw = self.canvas.create_oval(self.X, self.Y, event.x, event.y, outline=self.foreColor)
            self.li.append((self.X, self.Y, event.x, event.y))  # 保存图型的坐标
            self.temp.append('oval')

        self.yesno = 0
        if self.function != 7:
            self.end.append(self.lastDraw)

    # 在画布中点击鼠标右键,弹出“菜单栏”中的菜单
    def onRightButtonUp(self, event):
        self.menu.post(event.x_root, event.y_root)

    # 定义铅笔绘制
    def pencilDraw(self, button):
        self.canvas.config(cursor="pencil")
        # 重置所有按钮颜色为正常颜色
        for default_button in self.buttons:
            default_button.config(bg='SystemButtonFace')  # 使用系统按钮背景色作为正常颜色

        # 将被点击的按钮颜色设置为淡蓝色
        button.config(bg='#aaffff')
        self.function = 1

    # 定义绘制直线
    def drawLine(self, button):
        self.canvas.config(cursor="pencil")
        # 重置所有按钮颜色为正常颜色
        for default_button in self.buttons:
            default_button.config(bg='SystemButtonFace')  # 使用系统按钮背景色作为正常颜色

        # 将被点击的按钮颜色设置为淡蓝色
        button.config(bg='#aaffff')
        self.function = 2

    # 定义绘制矩形
    def drawRectangle(self, button):
        self.canvas.config(cursor="dot")
        # 重置所有按钮颜色为正常颜色
        for default_button in self.buttons:
            default_button.config(bg='SystemButtonFace')  # 使用系统按钮背景色作为正常颜色

        # 将被点击的按钮颜色设置为淡蓝色
        button.config(bg='#aaffff')
        self.function = 3

    # 定义绘制圆形
    def drawCircle(self, button):
        self.canvas.config(cursor="dot")
        # 重置所有按钮颜色为正常颜色
        for default_button in self.buttons:
            default_button.config(bg='SystemButtonFace')  # 使用系统按钮背景色作为正常颜色

        # 将被点击的按钮颜色设置为淡蓝色
        button.config(bg='#aaffff')
        self.function = 6

    # 创建文本输入窗口
    def txt_entry(self):
        window = tk.Toplevel(root)
        window.title("文本输入")
        screen_width, screen_height = window.maxsize()
        # 窗口的宽和高
        width = 225
        height = 120
        centre = '%dx%d+%d+%d' % (width, height, (screen_width - width) / 2,
                                (screen_height - height) / 2)
        window.geometry(centre)
        window.resizable(width=False, height=False)

        # 创建标签和输入框
        tk.Label(window, text="请输入文本内容", font=("宋体", 12)).pack(pady=5)
        entry = tk.Entry(window, width=25, font=("宋体", 12))
        entry.pack(pady=10)
        # 将鼠标焦点定位到输入框内
        entry.focus_set()

        # 显示已输入的文本内容
        if self.text:
            entry.insert(tk.END, self.text)

        # 创建按钮并绑定事件
        def confirm():
            self.text = entry.get()
            window.destroy()  # 关闭窗口

        # 关闭文本输入窗口
        def window_quit():
            window.destroy()

        confirm_button = tk.Button(window, text="确认", command=confirm, width=12, height=1, font=("宋体", 12))
        confirm_button.pack(side=tk.LEFT, padx=5, pady=5)

        quit_button = tk.Button(window, text="取消", command=window_quit, width=12, height=1, font=("宋体", 12))
        quit_button.pack(side=tk.RIGHT, padx=5, pady=5)

    # 定义绘制文字
    def drawText(self, button): 
        self.canvas.config(cursor="pencil")
        # 重置所有按钮颜色为正常颜色
        for default_button in self.buttons:
            default_button.config(bg='SystemButtonFace')  # 使用系统按钮背景色作为正常颜色

        # 将被点击的按钮颜色设置为淡蓝色
        button.config(bg='#aaffff')
        self.txt_entry()
        self.function = 4

    # 定义橡皮擦功能
    def onErase(self, button):
        self.canvas.config(cursor=DOTBOX)
        # 重置所有按钮颜色为正常颜色
        for default_button in self.buttons:
            default_button.config(bg='SystemButtonFace')  # 使用系统按钮背景色作为正常颜色

        # 将被点击的按钮颜色设置为淡蓝色
        button.config(bg='#aaffff')
        self.function = 5

    # 选择画布背景颜色
    def canvas_color(self):
        color = colorchooser.askcolor()
        self.canvas.configure(background=color[1])

    # 关于绘图程序
    def about_draw_app(self):
        about = tk.Tk()
        about.title('关于绘图程序')

        # 设置窗口居中
        window_width = 650
        window_height = 500
        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=650, height=500)
        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、png、gif的图像', font=("宋体", 14)).place(x=50, y=150)
        tk.Label(about_frame, text='保存图像:可以将图像保存为指定后缀名的图像文件', 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='快捷操作:在画布上直接右击鼠标,可弹出菜单栏中的菜单', font=("宋体", 14)).place(x=50, y=390)
        tk.Label(about_frame, text='创作者:www.pyhint.com', font=("宋体", 14)).place(x=50, y=450)
        about.mainloop()

    # 绘图程序讲解页面
    def draw_help_window(self):
        webbrowser.open("https://www.pyhint.com/article/162.html")

# 当前模块直接被执行
if __name__ == '__main__':
    canvas_width = 900    # 定义画布宽度
    canvas_height = 600    # 定义画布高度
    root = tk.Tk()         # 创建主窗口
    root.title('绘图工具')   # 软件名

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

    # 实例化程序主页面
    DrawTool(root)
    # 开启主循环,让窗口处于显示状态
    root.mainloop()