zoukankan      html  css  js  c++  java
  • x01.paint: 绘图程序

    绘图程序结构简单,逻辑也不复杂,例如在工具栏 (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:{}
    y:{}'.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
    y: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

  • 相关阅读:
    如何使用vs2008单元测试416a3648
    限制TextBox的长度
    DataGrid双击事件
    结构与类
    DataGrid删除对话框 & 限制编辑模试TextBox长度
    安逸...
    新来的,请多关照~!
    asp.net中使用JMail发邮件
    silverlight3datagrid中的数据导出到excel
    sl3中的DataGrid中的数据导出到Excel中 使用csv格式 解决中文是乱码的问题
  • 原文地址:https://www.cnblogs.com/china_x01/p/12952130.html
Copyright © 2011-2022 走看看