码迷,mamicode.com
首页 > 其他好文 > 详细

x01.paint: 绘图程序

时间:2020-05-24 19:21:12      阅读:43      评论:0      收藏:0      [点我收藏+]

标签:rectangle   frame   append   utils   逻辑   move   png   str   filename   

绘图程序结构简单,逻辑也不复杂,例如在工具栏 (tool_frame) 中选择画线 (draw_line), 在选项栏(top_frame) 设置,然后在画布 (canvas_frame) 中进行绘制即可。其他如画方画园等,无论是操作还是实现,都基本类同。

1. 效果图:

            技术图片

2. 代码:

技术图片
import os
import sys
import tkinter as tk
from tkinter import colorchooser, messagebox, filedialog

# 为引用 utils,在 site-packages 目录下新建 mypath.pth 文件,
# 添加所需导入模块的目录路径, 如 ‘x01.lab/py/’ 所在路径。
import utils
from paint.core import CanvasFrame, R, ToolFrame, TopFrame

sys.path.append(utils.R.CurrentDir)


class MainWindow(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title(x01.paint)
        utils.R.win_center(self)

        self.menu = tk.Menu(self)
        utils.R.generate_menus(self,[file, edit, help], sepindies=(2, 4))
        self.configure(menu=self.menu)

        self.top_frame = TopFrame(self)
        self.top_frame.configure(height=25)
        self.top_frame.pack(side=top, fill=x, pady=2)

        self.tool_frame = ToolFrame(self)
        self.tool_frame.configure(width=80, relief=raised)
        self.tool_frame.pack(side=left, fill=y, pady=3)

        self.canvas_frame = CanvasFrame(self)
        self.canvas_frame.pack(side=right, fill=both, expand=yes)

        self.tool_frame.tool_click(0)

    def file_1_new(self):
        self.canvas_frame.canvas.delete(tk.ALL)
        self.canvas_frame.canvas.config(bg=white)

    def file_2_save(self):
        filename = filedialog.asksaveasfilename(master=self, title=Save,
            filetypes=[(postscript file, *.ps), (All Files, *.*)])
        if not filename: return
        self.canvas_frame.canvas.postscript(file=filename, colormode=color)
        messagebox.showinfo(title=self.title, message=filename +  Save success!)

    def file_3_quit(self):
        self.destroy()
    
    def edit_1_undo(self):
        items = list(self.canvas_frame.canvas.find(all))
        try:
            last_item = items.pop()
        except IndexError:
            return
        self.canvas_frame.canvas.delete(last_item)

    def edit_2_zoom_in(self):
        self.canvas_frame.canvas.scale(all, 0,0,1.2,1.2)
        self.canvas_frame.canvas.config(scrollregion=self.canvas_frame.canvas.bbox(tk.ALL))

    def edit_3_zoom_out(self):
        self.canvas_frame.canvas.scale(all, 0,0,0.8,0.8)
        self.canvas_frame.canvas.config(scrollregion=self.canvas_frame.canvas.bbox(tk.ALL))

    def help_1_about(self):
        messagebox.showinfo(x01.paint, 绘图程序,版权属于x01(黄雄)所有。)


if __name__ == "__main__": 
    win = MainWindow()
    win.mainloop()
main.py
技术图片
import cmath
import math
import os
import sys
import tkinter as tk

from tkinter import colorchooser, ttk 

import utils


class R:
    Functions = (
        "draw_line", "draw_oval", "draw_rectangle", "draw_arc",
        "draw_triangle", "draw_star", "draw_irregular_line", "draw_super_shape", 
        "draw_text", "delete_item", "fill_item", "duplicate_item", 
        "move_to_top", "drag_item", "enlarge_item_size", "reduce_item_size"
    )

    SuperShapes = {
        "shape A": (1.5, 1.5, 5, 2, 7, 7),
        "shape B": (1.5, 1.5, 3, 5, 18, 18),
        "shape C": (1.4, 1.4, 4, 2, 4, 13),
        "shape D": (1.6, 1.6, 7, 3, 4, 17),
        "shape E": (1.9, 1.9, 7, 3, 6, 6),
        "shape F": (4, 4, 19, 9, 14, 11),
        "shape G": (12, 12, 1, 15, 20, 3),
        "shape H": (1.5, 1.5, 8, 1, 1, 8),
        "shape I": (1.2, 1.2, 8, 1, 5, 8),
        "shape J": (8, 8, 3, 6, 6, 6),
        "shape K": (8, 8, 2, 1, 1, 1),
        "shape L": (1.1, 1.1, 16, 0.5, 0.5, 16)

    }


class CanvasFrame(tk.Frame):
    current_item = None 
    fill = red
    outline = red
    width = 2.0 
    number_of_spokes = 5
    arrow = None
    dash = None
    x1,y1,x2,y2 = 0,0,0,0
    selected_super_shape = shape A

    def __init__(self, master):
        super().__init__(master)
        self.master = master

        self.init_canvas()
        self.bind_events()

    def bind_events(self):
        self.canvas.bind(<Button-1>, self.mouse_left_pressed)
        self.canvas.bind(<Button1-Motion>, self.mouse_pressed_motion)
        self.canvas.bind(<Motion>, self.mouse_unpressed_motion)

    def mouse_left_pressed(self, e=None):
        self.x1 = self.x2 = e.x
        self.y1 = self.y2 = e.y
        self.execute_selected_method()

    def mouse_pressed_motion(self, e=None):
        self.x2 = e.x 
        self.y2 = e.y 
        self.canvas.delete(self.current_item)
        self.execute_selected_method()

    def mouse_unpressed_motion(self, e=None): 
        self.master.tool_frame.current_coordinate_label.config(text=x:{}\ny:{}.format(e.x,e.y))

    def init_canvas(self):
        self.canvas = tk.Canvas(self, background=white, width=500, height=500, scrollregion=(0,0,800,800))
        x_scroll = tk.Scrollbar(self, orient=horizontal)
        x_scroll.pack(side=bottom, fill=x)
        x_scroll.config(command=self.canvas.xview)
        y_scroll = tk.Scrollbar(self, orient=vertical)
        y_scroll.pack(side=right, fill=y)
        y_scroll.config(command=self.canvas.yview)
        self.canvas.config(xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set)
        self.canvas.pack(side=right, fill=both, expand=yes)

    def execute_selected_method(self):
        self.current_item = None 
        func = getattr(self, self.master.tool_frame.selected_function, self.function_not_defined)
        func()

    def function_not_defined(self): pass

    def draw_line(self):
        self.current_item = self.canvas.create_line(self.x1, self.y1, self.x2, self.y2, fill=self.fill, 
            width=self.width, arrow=self.arrow, dash=self.dash)

    def draw_oval(self):
        self.current_item = self.canvas.create_oval(self.x1, self.y1, self.x2, self.y2, outline=self.outline,
            fill=self.fill, width=self.width)

    def draw_rectangle(self):
        self.current_item = self.canvas.create_rectangle(self.x1, self.y1, self.x2, self.y2, outline=self.outline,
            fill=self.fill, width=self.width)

    def draw_arc(self):
        self.current_item = self.canvas.create_arc(self.x1,self.y1,self.x2, self.y2, outline=self.outline, 
            fill=self.fill, width=self.width)

    def draw_triangle(self):
        dx = self.x2 - self.x1
        dy = self.y2 - self.y1
        z = complex(dx,dy)
        radius, angle0 = cmath.polar(z)
        edges = 3
        points = list()
        for edge in range(edges):
            angle = angle0 + edge * (2*math.pi)/edges
            points.append(self.x1 + radius * math.cos(angle))
            points.append(self.y1 + radius * math.sin(angle))
        self.current_item = self.canvas.create_polygon(points, outline=self.outline, 
            fill=self.fill, width=self.width)

    def draw_star(self):
        dx = self.x2 - self.x1 
        dy = self.y2 - self.y1
        z = complex(dx,dy)
        radius_out, angle0 = cmath.polar(z)
        radius_in = radius_out / 2
        points = []
        for edge in range(self.number_of_spokes):
            angle = angle0 + edge * (2*math.pi) / self.number_of_spokes
            points.append(self.x1 + radius_out * math.cos(angle))
            points.append(self.y1 + radius_out * math.sin(angle))
            angle += math.pi / self.number_of_spokes
            points.append(self.x1 + radius_in * math.cos(angle))
            points.append(self.y1 + radius_in * math.sin(angle))
        self.current_item = self.canvas.create_polygon(points, outline=self.outline,
            fill=self.fill, width=self.width)

    def draw_irregular_line(self):
        self.current_item = self.canvas.create_line(self.x1,self.y1,self.x2,self.y2,
            fill=self.fill, width=self.width)
        self.canvas.bind(<B1-Motion>, self.update_irregular_line)

    def update_irregular_line(self, e=None):
        self.x1, self.y1 = self.x2, self.y2
        self.x2,self.y2 = e.x, e.y
        self.draw_irregular_line()

    def draw_super_shape(self):
        points = self.get_shape_points(self.selected_super_shape)
        self.current_item = self.canvas.create_polygon(points, fill=self.fill,
            outline=self.outline, width=self.width)

    def get_shape_points(self, key):
        a,b,m,n1,n2,n3 = R.SuperShapes[key]
        points = []
        for i in self.float_range(0, 2*math.pi, 0.01):
            raux = (abs(1 / a * abs(math.cos(m*i/4))) ** n2
                + abs(1 / b * abs(math.sin(m*i/4))) ** n3)
            r = abs(raux) ** (-1/n1)
            x = self.x2 + r * math.cos(i)
            y = self.y2 + r * math.sin(i)
            points.extend((x,y))
        return points

    def float_range(self, start, end, step):
        while start < end:
            yield start 
            start += step 

    def draw_text(self): 
        text = self.master.top_frame.text_entry.get()
        fontsize = self.master.top_frame.fontsize_spinbox.get()
        self.current_item = self.canvas.create_text(self.x2,self.y2, text=text,
            font=(‘‘, fontsize), fill=self.fill)

    def delete_item(self):
        self.current_item = None 
        self.canvas.delete(current)

    def fill_item(self):
        try:
            self.canvas.itemconfig(current, fill=self.fill, outline=self.outline)
        except TclError:
            self.canvas.itemconfig(current, fill=self.fill)

    def duplicate_item(self):
        try:
            function_name = create_ + self.canvas.type(current)
        except TypeError:
            return 
        coordinates = tuple(map(lambda i: i+10, self.canvas.coords(current)))
        configs = self.get_configs()
        self.function_wrapper(function_name, coordinates, configs)

    def get_configs(self):
        configs = {}
        for k,v in self.canvas.itemconfig(current).items():
            if v[-1] and v[-1] not in [0, 0.0, 0,0, current]:
                configs[k] = v[-1]
        return configs

    def function_wrapper(self, function_name, *arg, **kwargs):
        func = getattr(self.canvas, function_name)
        func(*arg, **kwargs)

    def move_to_top(self):
        self.current_item = None
        self.canvas.tag_raise(current)

    def drag_item(self): 
        self.canvas.move(current, self.x2-self.x1, self.y2-self.y1)
        self.canvas.bind(<B1-Motion>, self.drag_update)

    def drag_update(self, e=None):
        self.x1, self.y1 = self.x2, self.y2
        self.x2, self.y2 = e.x, e.y 
        self.drag_item()

    def enlarge_item_size(self): 
        self.current_item = None 
        if self.canvas.find_withtag(current):
            self.canvas.scale(current, self.x2, self.y2, 1.2, 1.2)
            self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))

    def reduce_item_size(self): 
        self.current_item = None 
        if self.canvas.find_withtag(current):
            self.canvas.scale(current, self.x2, self.y2, 0.8, 0.8)
            self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))


class ToolFrame(tk.Frame):
    def __init__(self, master):
        super().__init__(master=master)
        self.master = master
        self.selected_function = R.Functions[0]
        self.foreground = red
        self.background = white

        self.create_tool_buttons()
        self.create_color_palette()
        self.create_current_coordinate_label()

    def create_current_coordinate_label(self):
        self.current_coordinate_label = tk.Label(self, text=x:0\ny:0)
        self.current_coordinate_label.grid(row=11,column=1, columnspan=2,padx=1, sticky=w)

    def create_color_palette(self):
        self.color_palette = tk.Canvas(self, height=55, width=55)
        self.color_palette.grid(row=10,column=1,columnspan=2, pady=5, padx=5)
        self.background_rect = self.color_palette.create_rectangle(15,15,40,40,
            outline=self.background, fill=self.background)
        self.foreground_rect = self.color_palette.create_rectangle(1,1,33,33,
            outline=self.foreground, fill=self.foreground)
        self.bind_color_palette()

    def bind_color_palette(self):
        self.color_palette.tag_bind(self.background_rect, <Button-1>, self.set_background_color)
        self.color_palette.tag_bind(self.foreground_rect, <Button-1>, self.set_foreground_color)

    def set_foreground_color(self, e=None):
        self.foreground = colorchooser.askcolor(title=select foreground color)[-1]
        self.color_palette.itemconfig(self.foreground_rect, outline=self.foreground, fill=self.foreground)

    def set_background_color(self, e=None):
        self.background = colorchooser.askcolor(title=select background color)[-1]
        self.color_palette.itemconfig(self.background_rect, outline=self.background, fill=self.background)

    def create_tool_buttons(self):
        for i, name in enumerate(R.Functions):
            icon = tk.PhotoImage(file=os.path.join(utils.R.CurrentDir, paint/icons/+name+.gif))
            self.button = tk.Button(self, image=icon, command=lambda i=i: self.tool_click(i))
            self.button.grid(row=i//2,column=1+i%2, sticky=nsew)
            self.button.image=icon 

    def tool_click(self, i):
        self.selected_function = R.Functions[i]
        self.remove_top_function()
        self.add_top_function()
        self.master.canvas_frame.bind_events()

    def remove_top_function(self):
        for child in self.master.top_frame.winfo_children():
            child.destroy()
            
    def add_top_function(self): 
        name = self.selected_function.replace(_,  ).capitalize() + :
        tk.Label(self.master.top_frame, text=name).pack(side=left, padx=5)
        icon = tk.PhotoImage(file=os.path.join(utils.R.CurrentDir, paint/icons/+self.selected_function+.gif))
        label = tk.Label(self.master.top_frame, image=icon)
        label.image = icon 
        label.pack(side=left)
        self.master.top_frame.create_options(self.selected_function)


class TopFrame(tk.Frame):
    def __init__(self, master):
        super().__init__(master=master)

    def create_options(self, selected_function):
        name = {}_options.format(selected_function)
        func = getattr(self, name, self.function_not_defined)
        func()

    def function_not_defined(self): pass 

    def draw_line_options(self):
        self.create_fill_combobox()
        self.create_width_combobox()
        self.create_arrow_combobox()
        self.create_dash_combobox()

    def draw_oval_options(self):
        self.create_fill_combobox()
        self.create_outline_combobox()
        self.create_width_combobox()

    def draw_rectangle_options(self):
        self.create_fill_combobox()
        self.create_outline_combobox()
        self.create_width_combobox()

    def draw_arc_options(self):
        self.create_fill_combobox()
        self.create_outline_combobox()
        self.create_width_combobox()

    def draw_triangle_options(self):
        self.create_fill_combobox()
        self.create_outline_combobox()
        self.create_width_combobox()

    def draw_star_options(self):
        self.create_spokes_combobox()
        self.create_fill_combobox()
        self.create_outline_combobox()
        self.create_width_combobox()

    def draw_irregular_line_options(self):
        self.create_fill_combobox()
        self.create_width_combobox()

    def draw_super_shape_options(self):
        self.create_shapes_combobox()
        self.create_fill_combobox()
        self.create_outline_combobox()
        self.create_width_combobox()

    def draw_text_options(self):
        self.create_text_entry()
        self.create_fontsize_spinbox()
        self.create_fill_combobox()

    def fill_item_options(self):
        self.create_fill_combobox()
        self.create_outline_combobox()

    def create_fill_combobox(self):
        tk.Label(self,text=Fill:).pack(side=left, padx=5)
        self.fill_combobox = ttk.Combobox(self, state=readonly, width=5)
        self.fill_combobox.pack(side=left)
        self.fill_combobox[values] = (none, fg, bg, black, white)
        self.fill_combobox.bind(<<ComboboxSelected>>, self.set_fill)
        self.fill_combobox.set(self.master.canvas_frame.fill)

    def create_width_combobox(self):
        tk.Label(self, text=Width:).pack(side=left, padx=5)
        self.width_combobox = ttk.Combobox(self, state=readonly, width=3)
        self.width_combobox.pack(side=left)
        self.width_combobox[values] = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
        self.width_combobox.bind(<<ComboboxSelected>>, self.set_width)
        self.width_combobox.set(1)

    def create_arrow_combobox(self):
        tk.Label(self, text=Arrow:).pack(side=left, padx=5)
        self.arrow_combobox = ttk.Combobox(self, state=readonly, width=5)
        self.arrow_combobox.pack(side=left)
        self.arrow_combobox[values] = (none, first, last, both)
        self.arrow_combobox.bind(<<ComboboxSelected>>, self.set_arrow)
        self.arrow_combobox.set(none)

    def create_dash_combobox(self):
        tk.Label(self, text=Dash:).pack(side=left, padx=5)
        self.dash_combobox = ttk.Combobox(self, state=readonly, width=5)
        self.dash_combobox.pack(side=left)
        self.dash_combobox[values] = (none, small, mediun, large)
        self.dash_combobox.bind(<<ComboboxSelected>>, self.set_dash)
        self.dash_combobox.set(none)

    def create_outline_combobox(self):
        tk.Label(self, text=Outline:).pack(side=left, padx=5)
        self.outline_combobox = ttk.Combobox(self, state=readonly, width=5)
        self.outline_combobox.pack(side=left)
        self.outline_combobox[values] = (none, fg, bg, black, white)
        self.outline_combobox.bind(<<ComboboxSelected>>, self.set_outline)
        self.outline_combobox.set(self.master.canvas_frame.outline)

    def create_spokes_combobox(self):
        tk.Label(self,text=Spokes:).pack(side=left, padx=5)
        self.spokes_combobox = ttk.Combobox(self, state=readonly, width=5)
        self.spokes_combobox.pack(side=left)
        self.spokes_combobox[values] = tuple(i for i in range(5,50))
        self.spokes_combobox.bind(<<ComboboxSelected>>, self.set_spokes)
        self.spokes_combobox.set(5)

    def create_shapes_combobox(self):
        tk.Label(self,text=Shapes:).pack(side=left, padx=5)
        self.shapes_combobox = ttk.Combobox(self, state=readonly, width=8)
        self.shapes_combobox.pack(side=left)
        self.shapes_combobox[values] = sorted(tuple(i for i in R.SuperShapes.keys()))
        self.shapes_combobox.bind(<<ComboboxSelected>>, self.set_shapes)
        self.shapes_combobox.set(self.master.canvas_frame.selected_super_shape)

    def create_text_entry(self):
        tk.Label(self, text=Text:).pack(side=left, padx=5)
        self.text_entry = tk.Entry(self, width=20)
        self.text_entry.pack(side=left)

    def create_fontsize_spinbox(self):
        tk.Label(self, text=Font size:).pack(side=left, padx=5)
        v = tk.IntVar()
        v.set(12)
        self.fontsize_spinbox = tk.Spinbox(self, from_=2,to=100,width=3, textvariable=v)
        self.fontsize_spinbox.pack(side=left)

    def set_width(self, e=None):
        self.master.canvas_frame.width = float(self.width_combobox.get())

    def set_fill(self, e=None):
        clr = self.fill_combobox.get()
        if clr == none:
            self.master.canvas_frame.fill = ‘‘
        elif clr == fg:
            self.master.canvas_frame.fill = self.master.tool_frame.foreground
        elif clr == bg:
            self.master.canvas_frame.fill = self.master.tool_frame.background
        else :
            self.master.canvas_frame.fill = clr 

    def set_arrow(self, e=None):
        self.master.canvas_frame.arrow = self.arrow_combobox.get()


    def set_dash(self, e=None):
        dash = self.fill_combobox.get()
        if dash == none:
            self.master.canvas_frame.dash = None
        elif dash == small:
            self.master.canvas_frame.dash = 1
        elif dash == medium:
            self.master.canvas_frame.dash = 15
        elif dash == large:
            self.master.canvas_frame.dash = 100 

    def set_outline(self, e=None):
        v = self.outline_combobox.get()
        if v == none:
            self.master.canvas_frame.outline = ‘‘
        elif v == fg:
            self.master.canvas_frame.outline = self.master.tool_frame.foreground
        elif v == bg:
            self.master.canvas_frame.outline = self.master.tool_frame.background
        else:
            self.master.canvas_frame.outline = v

    def set_spokes(self, e=None):
        self.master.canvas_frame.number_of_spokes = int(self.spokes_combobox.get())

    def set_shapes(self, e=None):
        self.master.canvas_frame.selected_super_shape = self.shapes_combobox.get()

if __name__ == "__main__": 
    pass     
core.py

3. 下载:

x01.lab/py/paint

 

x01.paint: 绘图程序

标签:rectangle   frame   append   utils   逻辑   move   png   str   filename   

原文地址:https://www.cnblogs.com/china_x01/p/12952130.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!