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

Posted 天皓Oo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用JAVA写一个画图程序(课程设计)相关的知识,希望对你有一定的参考价值。

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(
    参考技术A
            package s;//包名
  import java.awt.*;
  import java.awt.event.*;
  import javax.swing.*;
  public class Test extends JFrame
  int x1,y1,x2,y2;public Test()
  setVisible(true);
  setSize(300,300) ;
  addWindowListener(new WindowAdapter()
  public void windowClosing(WindowEvent e)
  System.exit(0) ; );
  addMouseListener(
  new MouseAdapter()
  public void mousePressed(MouseEvent e)
  x1=e.getX();
  y1=e.getY(); );
  addMouseMotionListener(new MouseMotionAdapter()
  public void mouseDragged(MouseEvent e)
  x2=e.getX() ;
  y2=e.getY() ;
  repaint(); );
  
  public void paint(Graphics g)
  
  g.drawLine(x1,y1,x2,y2);
  x1=x2;
  y1=y2;
  
  public static void main(String args[])
  
  new Test();
  
  
  

以上是关于用JAVA写一个画图程序(课程设计)的主要内容,如果未能解决你的问题,请参考以下文章

用java编写一个简单的画图程序。不用复杂

JAVA实现简单的画图板

JAVA怎么定时自动画图

20165306 实验二 Java面向对象程序设计

用java软件里的eclipse编ATM取款机(课程设计)

java课程设计:设计一个计算器模拟程序。