Bootstrap

Python 实现绘图软件:基于 tkinter 和面向对象编程

在 Python 中,我们可以使用 tkinter 模块来创建图形用户界面(GUI)应用程序。本文将介绍如何使用 tkinter 和面向对象编程的思想来实现一个简单的绘图软件。

一、代码分析

1. 导入模块

import tkinter
from tkinter import colorchooser

我们导入了 tkinter 模块和 colorchooser 模块,前者用于创建 GUI,后者用于选择颜色。

2. 定义 Draw 类

class Draw:
    def __init__(self):
        # 初始化窗口
        self.root = tkinter.Tk()
        self.root.title("画图软件")

        # 初始化菜单
        self.init_menu()

        # 初始化画布
        self.init_canvas()

        # 初始化事件绑定
        self.init_event()

        # 初始化状态栏
        self.init_status()

        # 其他初始化设置
        self.current_shape = None
        self.current_color = "black"
        self.start_x = None
        self.start_y = None
        self.max_id = 0
        self.shapes = []

    def undo(self):
        # 撤销功能,删除最后一个绘制的图形
        last = self.shapes.pop()
        self.canvas.delete(last)

    def clear(self):
        # 清除功能,清空画布并清除图形列表
        self.canvas.delete("all")
        self.shapes.clear()

    def choose_color(self):
        # 选择颜色功能,使用 `colorchooser` 选择颜色并设置当前颜色
        r = colorchooser.askcolor()
        if r[1]:
            self.set_current_color(r[1])

    def set_current_color(self, color):
        # 设置当前颜色
        self.current_color = color

    def set_current_shape(self, shape):
        # 设置当前形状,并更新状态栏信息
        self.current_shape = shape

        if shape == "line":
            self.status.config("当前选择直线,右键停止绘制")
        elif shape == "rect":
            self.status.config("当前选择矩形,右键停止绘制")
        elif shape == "oval":
            self.status.config("当前选择椭圆,右键停止绘制")

    def begie_draw(self, e):
        # 开始绘制图形,记录起始坐标并创建初始图形
        self.start_x = e.x
        self.start_y = e.y
        if self.current_shape == "line":
            self.max_id = self.canvas.create_line(self.start_x, self.start_y, self.start_x, self.start_y,
                                                  fill=self.current_color)
        elif self.current_shape == "rect":
            self.max_id = self.canvas.create_rectangle(self.start_x, self.start_y, self.start_x, self.start_y,
                                                       outline=self.current_color)
        elif self.current_shape == "oval":
            self.max_id = self.canvas.create_oval(self.start_x, self.start_y, self.start_x, self.start_y,
                                                  outline=self.current_color)
        self.shapes.append(self.max_id)

    def update_draw(self, e):
        # 更新绘制图形,根据鼠标移动调整图形位置
        if self.start_x is not None and self.start_y is not None:
            self.canvas.coords(self.max_id, self.start_x, self.start_y, e.x, e.y)

    def stop_draw(self, e):
        # 停止绘制图形,重置起始坐标
        self.start_x = None
        self.start_y = None

    def init_event(self):
        # 初始化事件绑定,包括鼠标点击、移动和释放事件
        self.canvas.bind("<Button - 1>", self.begie_draw)
        self.canvas.bind("<Motion>", self.update_draw)
        self.canvas.bind("<ButtonRelease - 1>", self.stop_draw)
        self.canvas.bind("<ButtonRelease - 3>", self.set_current_shape(None))

    def init_canvas(self):
        # 初始化画布
        self.canvas = tkinter.Canvas(master = self.root, width = 600, height = 500)
        self.canvas.pack()

    def init_status(self):
        # 初始化状态栏
        self.status = tkinter.Label(text = "我是状态栏")
        self.status.pack()

    def init_menu(self):
        # 初始化菜单
        self.main_menu = tkinter.Menu(master = self.root)

        self.shape_menu = tkinter.Menu(master = self.main_menu, tearoff = False)
        self.shape_menu.add_command(label = "直线", command = lambda: self.set_current_shape("line"))
        self.shape_menu.add_command(label = "矩形", command = lambda: self.set_current_shape("rect"))
        self.shape_menu.add_command(label = "椭圆", command = lambda: self.set_current_shape("oval"))
        self.main_menu.add_cascade(label = "图形", menu = self.shape_menu)

        self.color_menu = tkinter.Menu(master = self.main_menu, tearoff = False)
        self.color_menu.add_command(label = "红色", command = lambda: self.set_current_color("red"))
        self.color_menu.add_command(label = "绿色", command = lambda: self.set_current_color("green"))
        self.color_menu.add_command(label = "蓝色", command = lambda: self.set_current_color("blue"))
        self.color_menu.add_separator()
        self.color_menu.add_command(label = "自定义", command = lambda: self.choose_color())
        self.main_menu.add_cascade(label = "颜色", menu = self.color_menu)

        self.other_menu = tkinter.Menu(master = self.main_menu, tearoff = False)
        self.other_menu.add_command(label = "撤销", command = self.undo)
        self.other_menu.add_command(label = "清除", command = self.clear)
        self.other_menu.add_command(label = "退出", command = self.root.destroy)
        self.main_menu.add_cascade(label = "其他", menu = self.other_menu)

        self.root.config(menu = self.main_menu)

    def run(self):
        # 运行主循环
        self.root.mainloop()
  • __init__ 方法:进行了一系列的初始化操作,包括创建窗口、初始化菜单、画布、事件绑定和状态栏等。
  • undo 方法:实现撤销功能,删除最后绘制的图形。
  • clear 方法:实现清除功能,清空画布并清除图形列表。
  • choose_color 方法:用于选择颜色。
  • set_current_color 和 set_current_shape 方法:分别用于设置当前颜色和形状,并更新状态栏信息。
  • begie_drawupdate_draw 和 stop_draw 方法:处理绘图过程中的鼠标事件,包括开始绘制、更新图形和停止绘制。
  • init_eventinit_canvasinit_status 和 init_menu 方法:分别用于初始化事件绑定、画布、状态栏和菜单。

3. 主程序

if __name__ == '__main__':
    draw = Draw()
    draw.run()

在主程序中创建 Draw 类的实例,并运行绘图软件。

二、总结

通过使用 tkinter 模块和面向对象编程的思想,我们成功实现了一个简单的绘图软件。这个软件具有基本的绘图功能,包括选择图形、颜色,绘制、更新和停止绘制图形,以及撤销和清除操作。希望这个示例对大家学习 tkinter 和面向对象编程有所帮助。

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;