用JAVA写一个画图程序(课程设计)

该程序使用Java实现了一个图形界面,包括菜单、工具栏和画布。用户可以选择不同的图形、颜色和线条粗细进行绘制。工具栏中的按钮监听用户操作,如曲线、橡皮擦、喷枪等。程序支持撤销、刷新、颜色选择等功能。通过读取配置文件,可以根据指定图形进行显示。此外,程序还具有界面风格切换和文件保存、打开功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.设计思路

首先我直接去了Windows自带画图程序去实践模拟,看看具体方法,进行了布局和按钮的思考。

容器顶层放工具栏,工具栏中存放图形按钮、工具按钮、颜色按钮。对于图形按钮,存放在垂直的Box中,分成行列,设置边框,设置标签,加入JToolbar;对于工具按钮设置Jpanel保存,线条粗细设置垂直Box存储,设置边框后,最后将两者加入水平Box中,与前面图形按钮设置间隔加入JToolbar中,设置标签;对于颜色按钮,画布背景颜色选择按钮单独设置大按钮,直接加入JToolbar,而颜色选择按钮我设置了JPanel,垂直Box进行组装,成行列,设置边框,加入JToolbar中。最后的颜色选择编辑按钮,也是单独大按钮,加入JToolbar中。

最终效果如下:

这个程序,难在哪里?难在工具栏中按钮监听。对于工具栏中各个按钮,我要实时监听。但是对于工具栏中每一个按钮我都进行行为监听,适配器模式也招架不住程序的紊乱。于是写一个类,继承MouseAdapter、ActionListener,重写部分监听方法。

对于行为监听、鼠标抓取,进行了一些操作,下面类的设计会详细讲解。在这个过程中我对所有图形特征进行了分析,顺着这个我也创建了一个Shape类,类属性包含了所有图形的特征。可是工具栏不单单有图形构画,还有橡皮擦、颜色、粗细,为此我对Shape里面的属性做了调整,可以存储当前线条颜色、粗细。

对于菜单的设计较为简单,因为没有太强逻辑可言,你想让它如何展现,展现什么内容,就怎样重写监听方法。我设计了文件保存、打开以及画图的属性、帮助、界面风格。写了一个MyMenu类,进行相关设计组装,下面也会具体讲解。

图画刷新展示需要进行repaint,我写了MyFrame类继承JFrame,重写paint方法。在MyJFrame类中有参构造的同时,我也进行了画图的图标处理,这样更加更美观。

最终就是拼装完成,设置界面,进行显示。

总结:利用java中的现有类,创建主窗口、创建主窗口中内容、设置事件响应机制、显示主窗口、进入消息循环接收处理。
两个ini内容如下(这里ini文件就是简单读取内容,选择性添加按钮):
在这里插入图片描述
在这里插入图片描述
简单地文件内容读取:

/**
     * @param file
     * @return ArrayList 文件内容以若干个字符串传出
     * @throws IOException
     */
    public static ArrayList<String> getFileContent(String file) throws IOException {

        BufferedReader reader = new BufferedReader(new FileReader(file));
        //这里ArrayList是为了存储不确定个数的String
        ArrayList<String> content = new ArrayList<>();
        //获取文件中字符串
        String line = "";
        try{
            while((line=reader.readLine())!=null){
                //首个属性值
                if(line.contains("[")) {
                    continue;
                }
                String str[] = line.split("=");//分割出内容
                if(str.length>1)  line = str[1];
                else line = str[0];

                line = line.trim();//去除首尾空格
                String str1[] = line.split(",");//逗号分隔开若干个
                //遍历加入list
                for (String s : str1) {
                    content.add(s);
                }
            }
            return content;
        }finally{//始终保持文件最终关闭
            reader.close();
        }

    }

输入java Painter conf/Painter-1.ini 展示圆、矩形
在这里插入图片描述

输入java Painter conf/Painter-2.ini 展示圆、矩形、三角形、菱形、多边形

在这里插入图片描述

其中功能按钮、曲线、直线会一直展现。

2.类的设计

(一)类的设计

1.MyMouseListener

继承MouseAdapter适配器和MouseListner接口,进行一些方法重写。通过重写actionPerformed,先行获取按钮内容,设置属性。

(1)曲线、橡皮擦、喷枪、毛笔

在mouseDragged方法中进行行为监听。这个拖拽的过程是需要实时更新的,坐标也需要实时更新。

<1>曲线

是由无数直线拼接而来,不断创建shape,draw。这里我最开始也是用的实心圆,但是太曲折了,在网上资源也都是直线。

直线:在这里插入图片描述

实心圆:在这里插入图片描述

这里对比明显直线更胜一筹。

<2>橡皮擦

我的思路是在鼠标拖拽相应位置同样创建shape,而这些shape对象的颜色则为画布初始颜色,draw,实现橡皮擦功能。

<3>喷枪、毛笔

都是范围内进行喷画,可以用循环画无数条线的方式解决,并且这些直线是不连续的、随机的。可以使用Random循环一次次创建shape,draw。毛笔与喷枪不同的一点就是墨水会减少,需要记录刷新,画笔变细,最后为空,当再次pressed、released刷新“墨水”。

(2) 刷新、上一步

在actionPerformed中获取按钮内容之后,根据if条件,对vector中的数据进行更新。这里刷新之后,上一次vector数据要存起来,防止下次点击上一步不展示任何内容,利用两个vector互相转换,repaint。

(3) 直线、矩形、圆、三角形、菱形

重写mousePressed和mouseReleased方法,获取两顶点坐标,算法得出左上角坐标与右下角坐标。

<1>直线、矩形、圆、椭圆

在库中有相应的draw方法,对于直线、矩形,在已知坐标的情况,创建shape,draw;对于圆,我设置圆心为pressed点,计算拖拽距离为r,创建shape,draw;对于椭圆,我则是借鉴Windows画图中的画法,通过拖拽坐标得宽高,创建shape,draw。

<2>三角形、菱形

三角形:直角三角形、等腰三角形,根据拖拽坐标,找寻第三个点,创建三个type为直线的shape,draw三条线。

菱形:根据拖拽点计算四个点坐标,创建四个type为直线的type,draw四条直线。

(4) 多边形

对于多边形,获取坐标,相邻的点进行联接,创建多个type为直线的shape。并且存着首个坐标点,双击鼠标,可将图形封闭为多边形。

(5) 画笔粗细、颜色编辑

画笔粗细:根据按钮对象,创建stroke对象,在下次画图时传入shape中。

画布颜色:调用JColorChooser.showDialog进行选择,改变背景颜色,同时改变按钮边框颜色。

画笔颜色:根据点击的按钮,设置画笔相应的颜色,存入color对象,传入shape中。另外对点击的图形按钮设置相应的边框颜色。

按钮颜色编辑:自选颜色后可填入按钮中,并且设置循环,可反复覆盖。

2. Shape

这个类实现了每一个图形的数据存储,包含两个坐标点,画笔颜色,图形类型,画笔粗细。

对于直线、椭圆、圆、矩形,两个坐标即可画出图形。多边形、三角形、喷枪、毛笔、橡皮擦,则是由若干条线段构成的,只需创建多个类型为直线的shape对象。color,stroke对象记录当前画笔颜色,画笔粗细。

3.MyFrame

继承JFrame类,设置两个vector,v和v1的目的 v和v2都有存储图形的功能 用于遍历repaint。另外我可以当刷新时,将v的所有数据送给v1。回退时,我可以遍历v1,避免空画。

有参(title)构造MyFrame,并且在其中进行图标的设置。对paint方法进行重写,首先调用父类中的方法。其次将Graphics强制转换为Graphics2D,为了实现画笔粗细。在遍历过程中对shape中stroke,color进行获取,根据type画图。

其中直线、曲线、三角形、多边形的type都是直线,drawLine即可;圆、椭圆、矩形,则根据shape中两个坐标获取左上角坐标,计算大小,调用draw或fill方法。

最后若存在image,则drawImage,打开文件照片之后画布可以显示图片信息。

4.MyMenu

构建菜单,设置菜单条,创建MyMouseListener对象。在类中构造方法,创建菜单条。

文件菜单下创建打开、保存、属性、帮助等menuItem,并且过程中直接设置行为监听。

其中文件打开,JFileChooser默认为当前目录,选取文件进行获取,repaint图片到画布;文件保存,可在一定的区间范围内,画布保存为图片,默认保存路径为当前目录,获取选择文件路径,图片格式为jpg,如果保存了,则设置flag为真,关闭程序不会弹出窗口。

属性和帮助则是弹出窗口显示相关说明性信息。

格式菜单下设置了几种风格,可以进行选择刷新组件外观,更换界面主题,并且repaint,将图画信息转移到当前画布。

最后所有菜单装入菜单条,组装至容器中。

5.MyJToolbar

继承JToolbar类。创建一个初始化方法,对于按钮则可以设计for循环,进行创建加入图片,监听,装入工具栏;对于线条粗细的按钮,设置了一个垂直的Box拼装,监听,装入工具栏;对于颜色按钮,则仅仅设置颜色,监听,装入工具栏。

最后将工具栏装入JFrame的顶部。

6.Main

创建上述几个类的对象,调用各类初始化方法,组装,展示。

(二)类之间的联系

我并没有采用复杂的继承关系和设置抽象的类与接 口,只是继承了java中的一些原有的类和接口,便于 更好地实现自己写的一些类以及继承相应的父类不可 少的方法。其次对于自己写的几个类,我的耦合度可 能高一点,不太好可能,可能也不是,因为各类中都 有创建其他类的对象解决一些问题,各类中有创建相 应变量进行关联,改变窗口界面。

简单地继承:
在这里插入图片描述

类之间的一些联系:
在这里插入图片描述
在这里插入图片描述

3.代码实现

1.Painter 主函数

package com.zzu;

import javax.swing.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

//框架:最上层Menu --->文件保存 导入 界面刷新(清除功能) 风格更换
//     Menu下面放工具栏 绘制各种图形 颜色 线条粗细 橡皮擦 字体模式大小
//     关闭界面可以弹出警告窗口 设置监听器是否保存
//     画布 默认CENTER

//Content:
//          一个shape类存储Point color type
//          矩形: press、release为两侧顶点坐标 通过计算可得左上角右下角坐标及长宽 drawRect(Math.min(x1,x2), Math.min(y1,y2), Math.abs(x2-x1),Math.abs(y2-y1));
//          直线: Mouse press release   drawLine
//          圆: Mouse press release   drawOval
//          菱形: Mouse press release   drawLine
//          喷枪: random 的实心圆 或 坐标点  fillOval
//          曲线: 这就需要MouseDrag监听不断更新起点和终点 Point1->Point2 Point2->新Point 无限小直线 drawLine
//          多边形:release clicked drawLine
//          橡皮擦:区域内添加新图形 颜色为画布颜色 橡皮擦大小也跟画笔粗细相关联
//          回退:返回上一步
//          刷新:画布删除所有图形
//          粗细:  Graphics2D Stroke
//          画布背景颜色:  JColorChooser

public class Painter {

    //创建窗口对象
    MyFrame jf = new MyFrame("画图");

    //创建画图内容监听对象
    MyMouseListener myMouseListener = new MyMouseListener();

    //弹出文件窗口放在JPanel 防止保存图片时出现问题
    JPanel jPanel = new JPanel();

    //创建菜单对象
    MyMenu myMenu = new MyMenu(jf,jPanel);

    //创建工具栏对象
    MyJToolbar myJToolbar =  new MyJToolbar(jf,myMouseListener);

    //空参构造
    public Painter(){
    }

    /**
     * @param file
     * @return ArrayList 文件内容以若干个字符串传出
     * @throws IOException
     */
    public static ArrayList<String> getFileContent(String file) throws IOException {

        BufferedReader reader = new BufferedReader(new FileReader(file));
        //这里ArrayList是为了存储不确定个数的String
        ArrayList<String> content = new ArrayList<>();
        //获取文件中字符串
        String line = "";
        try{
            while((line=reader.readLine())!=null){
                //首个属性值
                if(line.contains("[")) {
                    continue;
                }
                String str[] = line.split("=");//分割出内容
                if(str.length>1)  line = str[1];
                else line = str[0];

                line = line.trim();//去除首尾空格
                String str1[] = line.split(",");//逗号分隔开若干个
                //遍历加入list
                for (String s : str1) {
                    content.add(s);
                }
            }
            return content;
        }finally{//始终保持文件最终关闭
            reader.close();
        }

    }


    /**
     * 展示界面
     * @throws Exception
     */
    public void showUI() throws Exception {

        //读取图形数据
        Scanner sc = new Scanner(System.in);
        String file = sc.next();
        ArrayList<String> list = getFileContent(file);
        myJToolbar.setList(list);

        //JFrame设置监听 可以任意画曲线
        //添加鼠标监听器
        jf.addMouseListener(myMouseListener);
        jf.addMouseMotionListener(myMouseListener);
        //将JFrame传过去 实现repaint
        myMouseListener.setMyFrame(jf);

        //初始化菜单加入到JFrame中
        myMenu.init();

        //初始化工具栏加入JFrame中
        myJToolbar.init();

        //设置界面大小
        jf.setSize(1100,800);
        //居中显示
        jf.setLocationRelativeTo(null);
        //设置可见
        jf.setVisible(true);
        //关闭进程
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) throws Exception {
        new Painter().showUI();
    }
}

2.MyMenu 菜单类

package com.zzu;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.*;

public class MyMenu {
    private MyFrame jf;
    private JPanel jPanel;

    //菜单项组件
    //菜单条
    public JMenuBar jMenuBar = new JMenuBar();

    //两个菜单
    public JMenu fileMenu = new JMenu("文件");
    public JMenu styleMenu = new JMenu("界面风格");

    //确定文件是否被保存
    public boolean flag = false;

    //获取画布图片信息或者获取文件中图片信息
    public BufferedImage image;

    public MyMenu() {
    }

    public MyMenu(MyFrame jf, JPanel jPanel) {
        this.jf = jf;
        this.jPanel = jPanel;
    }

    /**
     * 组装菜单
     * @throws Exception
     */
    public void init() throws Exception {
        //fileMenu下的条目菜单 对应设置行为监听
        //图片打开
        JMenuItem open = new JMenuItem(new AbstractAction("打开",new ImageIcon("打开.png")) {
            @Override
            public void actionPerformed(ActionEvent e) {
                //显示一个文件选择器 当前目录
                JFileChooser fileChooser = new JFileChooser(".");
                fileChooser.showOpenDialog(jPanel);
                //获取选择的文件
                File file = fileChooser.getSelectedFile();
                //如果选择了文件 就进行相关操作
                if(file != null){
                    //进行显示
                    try {
                        image = ImageIO.read(file);
                        //将信息传进MyFrame中
                        jf.setImage(image);
                        jf.setIg(true);
                        jf.repaint();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });
        //图片保存
        JMenuItem save = new JMenuItem(new AbstractAction("保存",new ImageIcon("保存.png")) {
            @Override
            public void actionPerformed(ActionEvent e) {
                //显示一个文件选择器 当前目录
                JFileChooser fileChooser = new JFileChooser(".");
                fileChooser.showSaveDialog(jPanel);
                //获取用户选择的保存文件路径
                File file = fileChooser.getSelectedFile();
                //如果只是打开目录没有保存 则不进行下面操作
                if(file!=null){
                //保存
                try {
                    try {
                        //画布保存为图片 设置区域范围大小
                        image = new Robot().createScreenCapture(new Rectangle(jf.getX(),jf.getY()+250, jf.getWidth(),jf.getHeight()-250));
                    } catch (AWTException ex) {
                        throw new RuntimeException(ex);
                    }
                    ImageIO.write(image,"jpg",file);//存入文件
                    flag = true;//保存成功
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
            }
        });
        //关于画图
        JMenuItem attribute = new JMenuItem(new AbstractAction("关于画图",new ImageIcon("关于画图.png")) {
            //展示特性
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(jf,null,"关于画图",JOptionPane.DEFAULT_OPTION,new ImageIcon("属性.png"));
            }
        });
        //帮助
        JMenuItem help = new JMenuItem(new AbstractAction("帮助",new ImageIcon("帮助.png")) {
            //展示内容
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(null, "" + "******************\n" + "#画图软件使用说明书#\r\n"
                        + "******************\n"
                        + "1.本软件主要分为四个模块:菜单、工具栏、调色板、和画布\n"
                        + "(1)菜单栏的文件子菜单包括打开、保存图片以及帮助,关于我们\r\n"
                        + "(2)工具主要包括清空画板、撤回操作、图形绘制\n"
                        + "(3)调色板位于界面的顶侧工具栏,用于改变画布背景颜色或设置画笔的颜色\n"
                        + "(4)画布用于图形绘制,使用鼠标选中要绘制的图形即可进行绘制\n"
                        +"2.具体操作:\n"
                        +"(1)可在画布绘制任意曲线\n"
                        +"(2)矩形、三角形、菱形、箭头:鼠标拖拽 获得两顶点系统会算法确定位置大小\r\n"
                        +"(3)圆:鼠标拖拽 press点和release点分别为圆心和圆上一点\n"
                        +"(4)多边形:相邻的两点连接,双击则可形成封闭图形\n"
                        +"(5)橡皮擦、喷枪 鼠标点击拖拽即可\n"
                        +"(6)画笔粗细选择\n"
                        +"(7)背景颜色、画笔颜色可自动选择 选择之后点击按钮 按钮边框也会变色\n"
                        +"(8)最后的编辑颜色可以配色进行选择\n", "使用说明", JOptionPane.PLAIN_MESSAGE);
            }
        });

        //styleMenu风格单选
        ButtonGroup buttonGroup = new ButtonGroup();
        JRadioButtonMenuItem metalItem = new JRadioButtonMenuItem("Metal 风格");
        JRadioButtonMenuItem windowsItem = new JRadioButtonMenuItem("Windows 风格",true);//默认
        JRadioButtonMenuItem windowsClassicItem = new JRadioButtonMenuItem("Windows 经典风格");
        JRadioButtonMenuItem motifItem = new JRadioButtonMenuItem("Motif 风格");

        //风格选择监听 避免多次重写
        ActionListener listener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    //获得内容 传送设置风格
                    changeFlavor(e.getActionCommand());
                    //风格改变后需要重画
                    jf.repaint();
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
            }
        };
        //退出若未保存则弹出提示窗口
        jf.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                if (!flag) {
                    // 弹出对话框 提示未保存
                     JOptionPane.showOptionDialog(jf,"你还没保存,确定要退出吗?","BBQ",JOptionPane.DEFAULT_OPTION
                            ,JOptionPane.WARNING_MESSAGE,null,new String[]{"确定","非常确定"},"确定");
                }
            }
        });

        //组装风格菜单
        buttonGroup.add(metalItem);
        buttonGroup.add(windowsItem);
        buttonGroup.add(windowsClassicItem);
        buttonGroup.add(motifItem);
        //添加监听器
        metalItem.addActionListener(listener);
        windowsItem.addActionListener(listener);
        windowsClassicItem.addActionListener(listener);
        motifItem.addActionListener(listener);
        //加入styleMenu
        styleMenu.add(metalItem);
        styleMenu.add(windowsItem);
        styleMenu.add(windowsClassicItem);
        styleMenu.add(motifItem);

        //文件以及帮助菜单
        fileMenu.add(open);
        fileMenu.add(save);
        fileMenu.add(attribute);
        fileMenu.add(help);

        //菜单栏
        jMenuBar.add(fileMenu);
        jMenuBar.add(styleMenu);

        //将组装好的菜单栏装入JFrame中
        jf.setJMenuBar(jMenuBar);
    }

    /**
     *
     * @param command
     * @throws Exception
     * 此方法用于改变界面风格
     */
    public void changeFlavor(String command) throws Exception {
        switch (command) {
            case "Metal 风格":
                UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
                break;
            case "Windows 风格":
                UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
                break;
            case "Windows 经典风格":
                UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");
                break;
            case "Motif 风格":
                UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
                break;
        }

        //刷新组件的外观
        SwingUtilities.updateComponentTreeUI(jf.getContentPane());
        SwingUtilities.updateComponentTreeUI(jMenuBar);

    }

    public MyFrame getJf() {
        return jf;
    }

    public void setJf(MyFrame jf) {
        this.jf = jf;
    }

    public JPanel getjPanel() {
        return jPanel;
    }

    public void setjPanel(JPanel jPanel) {
        this.jPanel = jPanel;
    }

}

3.MyJToolbar 工具栏类

package com.zzu;

import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

public class MyJToolbar extends JToolBar{
    static int num = 12;//当前第几个颜色选择框
    private MyFrame jf;
    private MyMouseListener myMouseListener;
    private ArrayList<String> list;

    public MyJToolbar() {
    }


    public MyJToolbar(MyFrame jf, MyMouseListener myMouseListener) {
        //声明工具条相关内容
        super("工具栏",SwingConstants.HORIZONTAL);
        this.setBackground(new Color(0xCFFCE6));
        this.jf = jf;
        this.myMouseListener = myMouseListener;
    }

    //TODO 工具条拖动画布内容消失问题
    @Override
    public void setFloatable(boolean b) {
        super.setFloatable(b);
        if(b) jf.repaint();
    }

    /**
     * 组装工具栏
     */
    public void init(){
        //组装工具栏
        //工具栏内容从最左侧开始填充
        this.setLayout(new FlowLayout(FlowLayout.LEFT));
        for (int i = 0; i < 3; i++) {
            //设置间隔 美观清晰
            this.addSeparator();
        }

        //第一行的这些图形功能是刚需的 不需要判断
        //第二行的需要根据文件读取图形数据判断是否加入
        String[] image1 = {"直线.png", "曲线.png","空心矩形.png", "实心矩形.png", "空心圆.png","实心圆.png","空心椭圆.png","实心椭圆.png",
                "直角三角形.png","等腰三角形.png","菱形.png", "多边形.png"};
        Box vBox = Box.createVerticalBox();
        JLabel jLabel1 = new JLabel("图形选择");
        JPanel jPanel1 = new JPanel();
        JPanel jPanel2 = new JPanel();
        //遍历组装图形功能按钮
        for (int i = 0; i < image1.length; i++) {
            boolean contain = false;
            if(i<2)   contain = true;//前几个图形不需要判定是否存在在文件中
            else {//文件中是否存在后面图形
                for(String s:list){
                    if(image1[i].contains(s))   {
                        contain = true;
                        break;
                    }
                }
            }

            if(contain){
                //JButton图片内容
                JButton jbt = new JButton();
                ImageIcon icon = new ImageIcon(image1[i]);//实例化ImageIcon对象
                icon.setImage(icon.getImage().getScaledInstance(30,30,Image.SCALE_DEFAULT));//设置图片大小与JButton大小匹配
                jbt.setIcon(icon);//加入JButton中
                //按钮大小
                jbt.setPreferredSize(new Dimension(35,35));
                //设置监听器
                jbt.addActionListener(myMouseListener);
                //默认边框蓝色
                jbt.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
                if(i<6) jPanel1.add(jbt);
                else    jPanel2.add(jbt);
            }
        }
        vBox.add(jPanel1);
        vBox.add(jPanel2);
        vBox.add(jLabel1);
        //vBox.setSize(210,80);
        vBox.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED, Color.RED, Color.GREEN));
        this.add(vBox);
        for (int i = 0; i < 3; i++) {
            //设置间隔 美观清晰
            this.addSeparator();
        }

        //工具按钮
        //水平Box存取工具 线条
        Box hBox = Box.createHorizontalBox();
        //设置边框
        hBox.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED, Color.RED, Color.GREEN));
        //存取按钮
        JPanel jPanel3 = new JPanel();
        JLabel jLabel2 = new JLabel("工具");
        String[] image2 = {"喷枪.png","毛笔.png", "橡皮擦.png","上一步.png","刷新.png"};
        //遍历组装图形功能按钮
        for (int i = 0; i < image2.length; i++) {
            //JButton图片内容
            JButton jbt = new JButton();
            ImageIcon icon = new ImageIcon(image2[i]);//实例化ImageIcon对象
            icon.setImage(icon.getImage().getScaledInstance(35,35,Image.SCALE_DEFAULT));//设置图片大小与JButton大小匹配
            jbt.setIcon(icon);//加入JButton中
            //按钮大小
            jbt.setPreferredSize(new Dimension(40,40));
            //设置监听器
            jbt.addActionListener(myMouseListener);
            //默认边框蓝色
            jbt.setBorder(BorderFactory.createLineBorder(Color.CYAN, 2));
            jPanel3.add(jbt);
        }

        //Vbox用来处置组装线条粗细按钮
        Box vBox2 = Box.createVerticalBox();
        //线条粗细
        String[] stroke = {"stroke1.png","stroke2.png","stroke3.png","stroke4.png"};
        //遍历设置监听和属性
        for(int i = 0;i<stroke.length;i++){
            //JButton粗细内容
            JButton jbt = new JButton();
            //实例化对象
            ImageIcon icon = new ImageIcon(stroke[i]);
            //设置图片大小与JButton大小匹配 加入按钮
            icon.setImage(icon.getImage().getScaledInstance(50,20,Image.SCALE_DEFAULT));
            jbt.setIcon(icon);
            //按钮大小
            jbt.setPreferredSize(new Dimension(50,20));
            //监听
            jbt.addActionListener(myMouseListener);
            vBox2.add(jbt);
        }
        vBox2.add(jLabel2);
        //hBox.setSize(210,80);
        hBox.add(jPanel3);
        hBox.add(vBox2);
        //加入工具条
        this.add(hBox);
        for (int i = 0; i < 3; i++) {
            //设置间隔 美观清晰
            this.addSeparator();
        }

        //设置背景颜色选择按钮
        JButton colorBack = new JButton(new ImageIcon("颜色.png"));
        colorBack.setBorder(BorderFactory.createLineBorder(Color.CYAN, 3));
        //设置监听
        colorBack.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //弹出颜色选择器
                Color color =  JColorChooser.showDialog(jf,"背景颜色选择器",Color.PINK);
                colorBack.setBorder(BorderFactory.createLineBorder(color, 3));
                //修改背景颜色 同时需要重画
                jf.getContentPane().setBackground(color);
                jf.repaint();
            }
        });
        this.add(colorBack);

        //三行颜色选择按钮
        Box vBox3 = Box.createVerticalBox();
        //vBox3.setSize(new Dimension(150,75));
        //三个JPanel分别装一行颜色按钮
        JPanel jPanel6 = new JPanel();
        JPanel jPanel7 = new JPanel();
        JPanel jPanel8 = new JPanel();
        //创建画笔颜色按钮
        Color[] color = {Color.WHITE,Color.BLACK,Color.CYAN,Color.BLUE,Color.PINK,Color.RED,
                Color.ORANGE,Color.MAGENTA,Color.GREEN,Color.GRAY,Color.DARK_GRAY,Color.LIGHT_GRAY,
                Color.WHITE,Color.WHITE,Color.WHITE,Color.WHITE,Color.WHITE,Color.WHITE};
        //设置n个按钮 这样实例化为了后面改变颜色选择按钮颜色
        JButton jbt[] = new JButton[color.length];
        //遍历组装按钮
        for (int i = 0; i < color.length; i++) {
            jbt[i] = new JButton(new ImageIcon(""));
            //按钮大小
            jbt[i].setPreferredSize(new Dimension(25,25));
            //按钮添加相应背景色
            jbt[i].setBackground(color[i]);
            //监听点击的背景色
            jbt[i].addActionListener(myMouseListener);
            if(i<6)  jPanel6.add(jbt[i]);
            else if(i<12) jPanel7.add(jbt[i]);
            else jPanel8.add(jbt[i]);
        }
        //将三个JPanel加入vBOX中
        vBox3.add(jPanel6);
        vBox3.add(jPanel7);
        vBox3.add(jPanel8);
        //设置边框以及一些边框属性
        vBox3.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED, Color.RED, Color.GREEN, Color.BLUE, Color.GRAY));
        //加入工具条
        this.add(vBox3);

        //设置背景颜色选择按钮
        JButton colorEdit = new JButton(new ImageIcon("编辑颜色.png"));
        colorEdit.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED, Color.RED, Color.GREEN));
        //设置监听
        colorEdit.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //弹出颜色选择器
                Color color =  JColorChooser.showDialog(jf,"按钮颜色编辑器",Color.PINK);
                //修改最后一行按钮颜色
                if(num==18){//都已经修改过 从头开始
                    num = 12;
                    jbt[num++].setBackground(color);
                }
                else  jbt[num++].setBackground(color);
            }
        });
        //加入工具条
        this.add(colorEdit);

        //TODO 界面为什么会为空 在哪repaint解决
        //让工具条可以拖动
        //this.setFloatable(true);

        //让工具条不可以拖动
        this.setFloatable(false);
        //工具栏居上
        jf.add(this,BorderLayout.NORTH);
    }



    public MyFrame getJf() {
        return jf;
    }

    public void setJf(MyFrame jf) {
        this.jf = jf;
    }

    public MyMouseListener getMyMouseListener() {
        return myMouseListener;
    }

    public void setMyMouseListener(MyMouseListener myMouseListener) {
        this.myMouseListener = myMouseListener;
    }

    public ArrayList<String> getList() {
        return list;
    }

    public void setList(ArrayList<String> list) {
        this.list = list;
    }
}

4.MyMouseListener 监听器类

package com.zzu;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

class MyMouseListener extends MouseAdapter implements ActionListener {
    //记录当前所选颜色 默认为蓝色
    public Color color = Color.BLACK;

    //Point1 Point2
    public int x1=0,y1=0,x2=0,y2=0;

    //ployX,ployY是多边形的第一个点
    public int ployX,ployY, ployX1, ployY1;

    //按钮名称 默认为null 可直接画曲线
    public String ActionCommand="";

    //判断多边形第一条边是否画出
    public boolean first;


    //毛笔模拟计时器 控制“墨汁”
    public int time,t;

//    //鼠标是否是静态
//    public int status;

    //毛笔是否已经完成上一次画线 默认为真
    boolean last = true;

    //数据存储
    public Vector<Shape> v = new Vector<>();

    //最多有四个shape(菱形四条边)
    public Shape s=null;
    public Shape s1=null;
    public Shape s2=null;
    public Shape s3=null;

    //字体粗细
    public Stroke stroke = new BasicStroke(1);//默认粗细为1

    //获得容器
    private MyFrame myFrame;

    //实时画图
    private Graphics2D g;

    public MyMouseListener() {
    }

    public MyMouseListener(MyFrame myFrame, Graphics2D g) {
        this.myFrame = myFrame;
        this.g = g;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        g = (Graphics2D) myFrame.getGraphics();
        g.setXORMode(myFrame.getBackground());
        //获取图片名字
        JButton jButton = (JButton)e.getSource();
        String command = jButton.getIcon().toString();
        //此处防止上次的点干扰此次作图
        x1=x2;
        y1=y2;
        if(command.equals("")){
            //提取颜色
            color = jButton.getBackground();
        }
        else if(command.equals("刷新.png")){
            //这里写if可以保证多次刷新数据也不会丢失
            if(v.size()>0){
            //保留刷新前的点 避免回退什么也不打印
            Vector<Shape> v1 = new Vector<>(v);
            myFrame.setV1(v1);
            }
            //删除所有点
            v.removeAllElements();
            //这里将back重置为false 不然会出现bug
            myFrame.setBack(false);
            myFrame.setV(v);
            myFrame.repaint();
        }
        else if (command.equals("上一步.png")) {
            int size = v.size();
            //有图形则删 无则不管
            if(size>0){
                v.remove(v.size()-1);
                myFrame.setV(v);
                myFrame.repaint();
            }
            else if(myFrame.getV1().size()>0){
                myFrame.setBack(true);
                myFrame.repaint();
            }
        }//字体粗细 并设置当前画笔粗细
        else if(command.equals("stroke1.png")){
            stroke = new BasicStroke(1);
            g.setStroke(stroke);
        }
        else if(command.equals("stroke2.png")){
            stroke = new BasicStroke(2);
            g.setStroke(stroke);
        }
        else if(command.equals("stroke3.png")){
            stroke = new BasicStroke(4);
            g.setStroke(stroke);
        }
        else if(command.equals("stroke4.png")){
            stroke = new BasicStroke(7);
            g.setStroke(stroke);
        }
        else{//橡皮擦就不要设置边框了
            if(!command.equals("橡皮擦.png")){
                JButton jbt = (JButton) e.getSource();
                //设置边框颜色 提醒画笔颜色
                //将所选按钮框改变为当前已选颜色
                jbt.setBorder(BorderFactory.createLineBorder(color, 2));
                jbt.setBackground(color);
            }
            //画笔颜色
            g.setColor(color);
            //获取图形
            ActionCommand=command;
            if(ActionCommand.equals("多边形.png")){
                //第一条边未画
                first = false;
            }
            else if(ActionCommand.equals("毛笔.png")) {
                //计时器0
                time = 0;
            }
        }
    }

    //得到按压起点坐标
    @Override
    public void mousePressed(MouseEvent e) {
        x1 = e.getX();
        y1 = e.getY();
    }
    //得到释放终点坐标
    @Override
    public void mouseReleased(MouseEvent e) {
        ployX1 = x2;
        ployY1 = y2;
        x2 = e.getX();
        y2 = e.getY();

        //如果released 那么毛笔墨汁刷新
        //计时器都刷新
        t=time=0;
        last = true;

        if(ActionCommand.equals("直角三角形.png")){
            Shape s = new Shape(x1,y1,x2,y2,color,"直线",stroke);
            v.addElement(s);
            g.drawLine(x1,y1,x2,y2);
            Shape s1 = new Shape(Math.min(x1,x2),Math.max(y1,y2),x1,y1,color,"直线",stroke);
            v.addElement(s1);
            g.drawLine(Math.min(x1,x2),Math.max(y1,y2),x1,y1);
            Shape s2 = new Shape(Math.min(x1,x2),Math.max(y1,y2),x2,y2,color,"直线",stroke);
            v.addElement(s2);
            g.drawLine(Math.min(x1,x2),Math.max(y1,y2),x2,y2);

        }
        else if(ActionCommand.equals("等腰三角形.png")){
            Shape s = new Shape(x1,y1,x2,y2,color,"直线",stroke);
            v.addElement(s);
            g.drawLine(x1,y1,x2,y2);
            Shape s1 = new Shape(2*x1-x2,y2,x1,y1,color,"直线",stroke);
            v.addElement(s1);
            g.drawLine(2*x1-x2,y2,x1,y1);
            Shape s2 = new Shape(2*x1-x2,y2,x2,y2,color,"直线",stroke);
            v.addElement(s2);
            g.drawLine(2*x1-x2,y2,x2,y2);
        }
        else if(ActionCommand.equals("菱形.png")){
            int x3 = (x1+x2)/2;
            int y3 = (y1+y2)/2;
            Shape s = new Shape(x1,y3,x3,y1,color,"直线",stroke);
            v.addElement(s);
            g.drawLine(x1,y3,x3,y1);
            Shape s1 = new Shape(x1,y3,x3,y2,color,"直线",stroke);
            v.addElement(s1);
            g.drawLine(x1,y3,x3,y2);
            Shape s2 = new Shape(x2,y3,x3,y1,color,"直线",stroke);
            v.addElement(s2);
            g.drawLine(x2,y3,x3,y1);
            Shape s3 = new Shape(x2,y3,x3,y2,color,"直线",stroke);
            v.addElement(s3);
            g.drawLine(x2,y3,x3,y2);
        }
        else if(ActionCommand.equals("空心矩形.png")){
            Shape s=new Shape(x1, y1, x2, y2,color,"空心矩形",stroke);
            v.addElement(s);
            g.drawRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
        }
        else if(ActionCommand.equals("实心矩形.png")){
            Shape s=new Shape(x1, y1, x2, y2,color,"实心矩形",stroke);
            v.addElement(s);
            g.fillRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
        }
        else if(ActionCommand.equals("空心圆.png")){
            int r = (int)Math.sqrt(Math.pow(x1-x2,2)+Math.pow(y1-y2,2));//半径
            Shape s=new Shape(x1, y1, r, r,color,"空心圆",stroke);
            v.addElement(s);
            g.drawOval(x1,y1,r,r);
        }
        else if(ActionCommand.equals("实心圆.png")){
            int r = (int)Math.sqrt(Math.pow(x1-x2,2)+Math.pow(y1-y2,2));//半径
            Shape s=new Shape(x1, y1, r, r,color,"实心圆",stroke);
            v.addElement(s);
            g.fillOval(x1,y1,r,r);
        }
        else if(ActionCommand.equals("空心椭圆.png")){
            Shape s=new Shape(x1, y1, x2, y2,color,"空心椭圆",stroke);
            v.addElement(s);
            g.drawOval(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
        }
        else if(ActionCommand.equals("实心椭圆.png")){
            Shape s=new Shape(x1, y1, x2, y2,color,"实心椭圆",stroke);
            v.addElement(s);
            g.fillOval(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
        }
        else if(ActionCommand.equals("直线.png")) {
            Shape s=new Shape(x1, y1, x2, y2,color,"直线",stroke);
            v.addElement(s);
            g.drawLine(x1,y1,x2,y2);
        }
        else if(ActionCommand.equals("多边形.png")&&!first){
            //存起始点
            ployX=x1;
            ployY=y1;
            Shape s=new Shape(x1, y1, x2, y2,color,"直线",stroke);
            v.addElement(s);
            //画多边形的第一条边
            g.drawLine(x1,y1,x2,y2);
            first =true;
        }
        else if(ActionCommand.equals("多边形.png")){
            //双击形成封闭图形
            if(e.getClickCount()==2){
                Shape s=new Shape(x2, y2,ployX,ployY,color,"直线",stroke);
                v.addElement(s);
                //首尾点相连
                g.drawLine(x2, y2,ployX,ployY);
                first =false;
            }//否则继续循序连接
            else {
                Shape s=new Shape(x1, y1, ployX1, ployY1,color,"直线",stroke);
                v.addElement(s);
                g.drawLine(x1, y1, ployX1, ployY1);
            }
        }

        myFrame.setV(v);
    }


    //监视曲线 画布 橡皮擦 喷枪
    //这里都是Point1->Point2 Point2更新 若干个Shape
    @Override
    public void mouseDragged(MouseEvent e) {
        g = (Graphics2D) myFrame.getGraphics();
        g.setColor(color);//画笔颜色
        g.setStroke(stroke);//画笔粗细
        ployX1 = x2;
        ployY1 = y2;
        x2 = e.getX();
        y2 = e.getY();
        if( ActionCommand.equals("曲线.png")||ActionCommand.equals("")){
            //添加若干条直线
            s=new Shape(x1, y1,x2, y2,color,"直线",stroke);
            v.addElement(s);
            g.drawLine(x1,y1,x2,y2);
            x1=x2;
            y1=y2;
        }
        else if( ActionCommand.equals("橡皮擦.png")){
            //区域添加背景色的图形
            s=new Shape(x1, y1,x2, y2,UIManager.getColor("control"),"实心圆",stroke);
            g.setColor(UIManager.getColor("control"));
            v.addElement(s);
            g.drawLine(x1,y1,x2,y2);
            x1=x2;
            y1=y2;
        }
        else if( ActionCommand.equals("喷枪.png")){
            //随机在区域内画线
            Random r=new Random();
            //遍历随机画线
            for(int i=0;i<30;i++){
                int a=r.nextInt(20);
                int b=r.nextInt(20);
                s=new Shape(x1+a, y1+b,x2+a, y2+b,color,"直线",stroke);
                v.addElement(s);
                g.drawLine(x1+a,y1+b,x2+a,y2+b);
                x1=x2;
                y1=y2;
            }
        }
        else if( ActionCommand.equals("毛笔.png")){
            //随机在区域内画线
            Random r=new Random();
            for(int i=0;i<60;i++){
                if(t<=15&&last){
                    int a=r.nextInt(20-t);//ab就当成墨汁了
                    int b=r.nextInt(20-t);
                    s=new Shape(x1+a, y1+b,x2+a, y2+b,color,"直线",stroke);
                    v.addElement(s);
                    g.drawLine(x1+a,y1+b,x2+a,y2+b);
                    x1=x2;
                    y1=y2;
                    time++;//计时器++
                }else; //啥也不画 没墨汁了 再次press重画获得墨汁
            }
            //刷新t 墨汁变少
            t = time/1000;
        }

        myFrame.setV(v);
    }

    public MyFrame getMyFrame() {
        return myFrame;
    }

    public void setMyFrame(MyFrame myFrame) {
        this.myFrame = myFrame;
    }

    public Graphics2D getG() {
        return g;
    }

    public void setG(Graphics2D g) {
        this.g = g;
    }

}

5.MyFrame 类

package com.zzu;

import javax.swing.*;
import java.awt.*;
import java.util.*;

public class MyFrame extends JFrame {
    //所有数据存放至此 进行repaint
    private Vector<Shape> v = new Vector<>(); //设置v和v1的目的 v和v1都有存储图形的功能 用于遍历repaint
    private Vector<Shape> v1 = new Vector<>(); //另外我可以当刷新时 将v的所有数据送给v1 回退时 我可以遍历v1 不然会什么也不画
    private boolean back = false; //是否满足回退且v1不为空的条件
    private Image image;//文件中图片
    private boolean ig;//保证图片也能被删除

    public MyFrame(){
    }

    public MyFrame(String title){
        //窗体名称
        super(title);
        this.getContentPane().setBackground(new Color(204,255,204));
        //TODO 设置窗体图标
        try {
            ImageIcon icon = new ImageIcon("画图.png");
            Image image = icon.getImage();
            this.setIconImage(image);
        } catch (Exception e) {//跳出对话框提示
            JOptionPane.showMessageDialog(null, "图标异常");
        }
    }

    /**
     *
     * @param g the specified Graphics window
     *          重写repaint方法
     */
    @Override
    public void paint(Graphics g) {
        //父类中的方法
        super.paint(g);
        //如果此时v1中有Shape 则说明已经刷新了
        //判断是否回退 回退则将这俩换一下 并且判定是否有图片回退打印
        if(v1.size()>0) {
            ig = false;
            if(back){
                v.addAll(v1);
                v1.removeAllElements();
                //ig = true;
            }
        }
        Graphics2D g1 = (Graphics2D) g;
        //遍历画出内容
        for (Shape type: v) {
            g1.setStroke(type.getStroke());//当前图形粗细
            g1.setColor(type.getColor());//当前颜色
            int x1 = type.getX1();
            int y1 = type.getY1();
            int x2 = type.getX2();
            int y2 = type.getY2();
            //根据image选择draw
            if(type.getImage().equals("空心圆")){//圆
                g1.drawOval(x1,y1,x2,y2);//这里x2=y2=r
            }
            else if(type.getImage().equals("实心圆")){//实心圆
                g1.fillOval(x1,y1,x2,y2);//这里x2=y2=r
            }
            else if(type.getImage().equals("空心椭圆")){//椭圆
                g1.drawOval(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
            }
            else if(type.getImage().equals("实心椭圆")){//实心椭圆
                g1.fillOval(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
            }
            else if (type.getImage().equals("空心矩形")) {//矩形
                //左上角坐标 长宽
                g1.drawRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
            }
            else if (type.getImage().equals("实心矩形")){//实心矩形
                //左上角坐标 长宽
                g1.fillRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
            }
            else{//线(其他多边形 曲线都是由若干条线组成的)
                g1.drawLine(x1,y1,x2,y2); //连接两端点
            }
        }
        if(ig) g1.drawImage(image,this.getX()+200,this.getY()+200,this);
    }

    public Vector<Shape> getV() {
        return v;
    }

    public void setV(Vector<Shape> v) {
        this.v = v;
    }

    public Vector<Shape> getV1() {
        return v1;
    }
    public void setV1(Vector<Shape> v1) {
        this.v1 = v1;
    }

    public boolean isBack() {
        return back;
    }

    public void setBack(boolean back) {
        this.back = back;
    }

    public Image getImage() {
        return image;
    }

    public void setImage(Image image) {
        this.image = image;
    }

    public boolean isIg() {
        return ig;
    }

    public void setIg(boolean ig) {
        this.ig = ig;
    }
}

6.Shape 类

package com.zzu;

import java.awt.*;

//创建一个Shape类 存储每一次paint图形的数据
//窗体重画时 不会丢失原来图形数据
//矩形:Graphics类中有特定的draw方法 但是需要两顶点坐标确定大小和位置
//直线、曲线、三角形、多边形:没有特定方法 需要直线拼凑
//圆: 可以根据圆心以及圆上一点 确定位置以及大小
//综合: 需要两个Point 这里直接存坐标更方便
//      画笔颜色 color
//      画笔粗细 Stroke


public class Shape {
    //存储当前Point1 Point2
    private int x1,y1,x2,y2;
    //存储当前颜色
    private Color color;
    //确定类型(其他(直线)/矩形/圆)
    private String image;
    //线粗细
    private Stroke stroke;

    public Shape() {
    }

    public Shape(int x1, int y1, int x2, int y2, Color color, String image, Stroke stroke) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
        this.color = color;
        this.image = image;
        this.stroke = stroke;
    }

    public int getX1() {
        return x1;
    }

    public void setX1(int x1) {
        this.x1 = x1;
    }

    public int getY1() {
        return y1;
    }

    public void setY1(int y1) {
        this.y1 = y1;
    }

    public int getX2() {
        return x2;
    }

    public void setX2(int x2) {
        this.x2 = x2;
    }

    public int getY2() {
        return y2;
    }

    public void setY2(int y2) {
        this.y2 = y2;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public Stroke getStroke() {
        return stroke;
    }

    public void setStroke(Stroke stroke) {
        this.stroke = stroke;
    }
}

这里要实现拉伸功能,大家可以去学一下GUI中的异或操作。

4.面向对象

1.设计

在问题领域中根据需求识别对象
将识别出的对象抽象为类
找出对象与对象之间的联系
进行类的设计,属性、方法、继承等,建立类层次结构
创建各类对象,传递参数,调用类中方法,根据对象间的联系,在主函数中展示组装。
优秀的面向对象编程,合理的进行类的设计,各种抽象的类、接口,那是必不可少的。

2.优势

在此次程序,通过面向对象编程,对于窗口的处理,我可以抽象出类来解决。我可以独立的分成几个类,分解若干个对象,描述事物在整个解决问题的步骤中的行为。我根据程序的目的,抽象出了菜单、工具栏、监听器、图形、顶级容器类,通过创建他们的对象,关联组装,就可以完成这个程序设计,并且层次较为清晰。

我目前没有用面向过程的编程进行过此类图形化界面程序的实现,但是也有写过一次千行的大作业,其中全是逻辑算法问题,单纯各种函数的书写,解决某一步的问题,与此程序书写风格大相径庭。

因此通过此程序,也可以感受到面向对象的一些优势。也多少能体会到两种编程的一些差别。用面向过程的语言书写代码,更偏向于顺序完成,调用函数。面向对象就与此有大的差别,思路不同、解决方法的实现可能现在对我而言是差不多,但是解决方法的路径与过程差距很大。

面向过程中的解决问题的方法主要是函数,而面向对象主要是类(这是面向过程编程所不具备的),抽象成类,构造类属性、方法,创建对象,解决问题,且带有针对性。

另外面向过程是一种以过程为中心的编程思想,缺点就是重用率低,扩展能力差。而面向对象编程则更容易设计出清晰、耦合度低的系统,并且便于程序修改更新。对我这个程序而言最关键的是易复用,可继承,能更好的联系,这同时也是面向对象编程的一些优势。

5.程序最终效果

在这里插入图片描述

6.程序所需图片如下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

评论 51
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值