Java小程序——模仿Win系统画板

好久之前的一个小作业,用Java实现画板。毕竟当时花费不少功夫调试,在这里分享给大家,希望能够对需要的小伙伴有所帮助!声明一下,以下代码为参考网上相关代码修改,绝非完全原创。

运行效果图如下:


话不多说,直接上代码:

DrawBegin类:设置画板的框架,配置画布,进行监听。

package drawTable;
import java.awt.*;
import javax.swing.JFrame;  
import drawTable.ColorChoose;
import drawTable.DrawPannel;
import drawTable.MouseListener;
import drawTable.ToolPannel;
/** 
 * 主函数类 
 *  
 * @author GZ
 *  
 */  
public class DrawBegin extends JFrame {  
    /** 
     * 主函数 
     *  
     * @param args 
     */  
    public static int Panel_width;
    public static int Panel_height;
    public static void main(String args[]) {  
    DrawBegin dp = new DrawBegin();  
        dp.showFrame();  
    }  
  
    private void showFrame() {  
        this.setTitle("GZ的画板");  
        this.setSize(800, 600);  
        this.setDefaultCloseOperation(3);  
        this.setLocationRelativeTo(null);  
  
        // 创建工具面板对象  
        ToolPannel tpl = new ToolPannel();
        this.add(tpl, BorderLayout.WEST);  
  
        ColorChoose cpl = new ColorChoose();  
        this.add(cpl, BorderLayout.SOUTH);
  
        DrawPannel dpl = new DrawPannel(tpl);//原发者  
        this.add(dpl, BorderLayout.CENTER);  
        
        // 将菜单栏的对象设置为窗体的菜单栏  
        this.setVisible(true);  
        
        //实例化鼠标事件处理类的对象
        MouseListener M=new MouseListener(tpl,cpl,dpl);
      
        //给事件源添加鼠标监听器方法,然后绑定事件处理类的对象
        dpl.addMouseListener(M);
        dpl.addMouseMotionListener(M);
        
        Panel_width=dpl.panel.getWidth(); 
        Panel_height=dpl.panel.getHeight();
    } 
}  
      

DrawPannel类:设置画布。主要是在画布上呈现不同的形状,比如:矩形、椭圆等。

这里注意一点:画布在呈现过程中,由于不断的涮新页面,会导致“闪烁”现象。解决方法是使用缓存技术。

package drawTable;
import java.awt.Color; 
import java.awt.Image; 
import java.awt.Dimension;  
import java.awt.FlowLayout;  
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawPannel extends JPanel{  
    private Color backColor = Color.WHITE;  //画布背景色  
    public JPanel panel = new JPanel();  //创建一个画布对象  
    public ToolPannel tp;  
   //图像缓存空间
    private Image image;
    private Graphics mg;
    /** 
     * 构造方法 
     */  
    public DrawPannel(ToolPannel tp) {   
        this.tp=tp;  
        init();  //调用初始化面板的方法  
    }  
  
    private void init() {  
        this.setLayout(new FlowLayout(FlowLayout.LEFT));  //设置Draw_panel的布局为流式布局布局  
        this.setBackground(Color.gray);  //设置画板背景颜色
        System.out.println("it is adding");
        panel.setBackground(backColor);  //画布的背景色
        panel.setPreferredSize(new Dimension(500,400));  //设置画布大小
        this.add(panel);  //将panel添加到Draw_panel上  
        //this.panel.setVisible(true);  ///
    }  
   
    public Color getBackgroundColor(){  
        return this.backColor;  //返回画布背景色
    }  
    
     
    /**
     * 使用图形缓冲,防止重绘时画面闪烁
     */
    public void display(int index,Shape shapeArr[],Shape shape_dragged) {
   
        image = this.createImage(this.getWidth(), this.getHeight());
        if (image != null) {
            mg = image.getGraphics();
        }
        if (mg != null) {
            super.paint(mg);
            System.out.println("index is " + index);
            //绘制所有缓存的形状
            for (int i = 0; i < index; i++) {
                Shape shape = shapeArr[i];
                if (null != shape) {
                    shape.draw(mg);
                }
            }
            if (shape_dragged != null) {//绘制拖拽的形状
                shape_dragged.draw(mg);
            }
        }
        this.repaint();
        
    }


    public void paint(Graphics g) {
    super.paint(g);  
        g.drawImage(image, 0, 0, this.panel);
    }
}  

ToolPannel类:主要就是工具栏的实现。

package drawTable;
import java.awt.Dimension;  
import java.awt.FlowLayout;    
import java.awt.GridLayout;  
import java.awt.event.ActionEvent;  
import java.awt.event.ActionListener;  
import javax.swing.Icon;  
import javax.swing.ImageIcon;  
import javax.swing.JButton;  
import javax.swing.JPanel;  
  
/** 
 * 工具类 
 *  
 * @author GZ
 *  
 */  
public class ToolPannel  extends JPanel {  
    //声明一个存储用户选择的图形属性  
    public String shape_command = "line";  
    //private Graphics g;  
  
    // 构造方法  
    public ToolPannel() {  
        show();// 调用方法  
    }  
  
    // 制作工具栏的方法  
    public void show() {  
        // 实例化一个JPanel对象,充当容器来添加工具。  
        JPanel panel = new JPanel();  
        // 设置面板的布局为网格布局  
        panel.setLayout(new GridLayout(5, 2, 4, 4));  
        // 定义一个数组。  
        String[] array = { "brush.jpg", "easer.jpg",  
                "line.jpg", "oval.jpg",  
                "pencil.jpg", "rect.jpg",  
                "roundrect.jpg", "spray.jpg" };  
        // 循环创建按钮对象  
        for (int i = 0; i < array.length; i++) {  
            // 实例化一个ImageIcon的对象  
        //  ImageIcon image = new ImageIcon(array[i]);  
            Icon image = new ImageIcon(this.getClass().getResource(  
                    array[i]));  
            // 实例化按钮对象,并设置按钮的图标  
            JButton btn = new JButton(image);  
            // 设置按钮的大小  
            btn.setPreferredSize(new Dimension(28, 28));  
            //获取到唯一的动作命令(截取图片的名字)  
            String fileName = array[i].substring(array[i].indexOf("/")+1, array[i].lastIndexOf(".jpg"));  
            //设置按钮的动作命令值  
            btn.setActionCommand(fileName);  
            //设置按钮的动作命令监听器方法,绑定事件处理类的对象tool_listener  
            btn.addActionListener(toollistener);  
            // 将按钮添加到面板上  
            panel.add(btn);  
            // 设置Tool_panel的布局为流式布局布局  
            this.setLayout(new FlowLayout());  
        }  
        // 将panel添加到Tool_panel上  
        this.add(panel);  
        // 设置工具栏颜色  
        this.setBackground(null);  
    }  
    /** 
     * 使用匿名内部类来实现动作事件处理接口add 
     */  
    private ActionListener toollistener = new ActionListener() {  
        /** 
         * 事件处理方法 
         */  
        public void actionPerformed(ActionEvent e) {  
            //将按钮上的动作命令值获取到,存储到属性shape_command中  
            shape_command =e.getActionCommand();  
            //System.out.println(shape_command);
            
        }  
    };  
}  

ColorChoose类:颜料板的实现。

package drawTable;
/** 
 * 颜色类 
 */  
import java.awt.Color;  
import java.awt.Dimension;  
import java.awt.FlowLayout;  
import java.awt.GridLayout;  
import java.awt.event.MouseAdapter;  
import java.awt.event.MouseEvent;  
import javax.swing.JButton;  
import javax.swing.JPanel;   
public class ColorChoose extends JPanel {  
    //定义存储前景色和背景色的颜色属性  
    public Color bcolor = Color.WHITE,fcolor = Color.BLACK;  
    /** 
     * 构造方法(构造方法里面不能实例化对象) 
     */  
    public ColorChoose() {  
        init();// 调用显示的方法  
    }  
  
    // 将颜色栏显示的方法  
    private void init() {  
        // 实例化一个panelFB对象  
        JPanel panelFB = new JPanel();  
        // 设置面板大小  
        panelFB.setPreferredSize(new Dimension(30, 30));  
        // 设置面板布局为空布局  
        panelFB.setLayout(null);  
  
        // 创建两个按钮(这里必须要定义为final类型,要控制其不能改变)  
        final JButton btnF = new JButton();  
        final JButton btnB = new JButton();  
  
        // 设置颜色按钮的位置和大小。setBounds,记住,去查询下。  
        btnF.setBounds(5, 5, 15, 15);  
        btnB.setBounds(10, 10, 15, 15);  
        // 设置颜色按钮的颜色  
        btnF.setBackground(Color.black);  
        btnB.setBackground(Color.red);  
        // 将颜色按钮添加到面板上  
        panelFB.add(btnF);  
        panelFB.add(btnB);  
        // 将可换颜色面板添加到总的颜色面板上  
        this.add(panelFB);  
  
        /** 
         * 实例化一个MouseAdapter抽象类的对象(匿名内部类) 
         */  
        MouseAdapter ma = new MouseAdapter(){  
            /** 
             * 鼠标按下时执行的方法 
             */  
            public void mousePressed(MouseEvent e) {  
                //获取到事件源对象 按钮
                JButton btn = (JButton)e.getSource();  
                //判断当前点击的是否是左键,如果是则改变背景色,条件是e.getButton()返回的值是否为1  
                if(e.getButton() == 1){  
                    //获取到按钮上的颜色了  
                    fcolor = btn.getBackground();  
                    //改变背景色按钮上的颜色  
                    btnF.setBackground(fcolor);  
                }else if(e.getButton() == 3){//表示点击了右键  
                    //获取到按钮上的颜色了  
                    bcolor = btn.getBackground();  
                    //改变背景色按钮上的颜色  
                    btnB.setBackground(bcolor);  
                }  
                  
            }  
        };  
          
        // 创建一个 可选颜色面板的对象  
        JPanel panel1 = new JPanel();  
  
        Color[] array = {Color.BLACK,Color.BLUE,Color.CYAN,Color.DARK_GRAY,  
                Color.GRAY,Color.GREEN,Color.LIGHT_GRAY,Color.MAGENTA,Color.ORANGE,  
                Color.PINK,Color.RED,Color.YELLOW,Color.WHITE,new Color(150,200,130),  
                new Color(100,120,130),new Color(150,125,130),new Color(150,125,130),new Color(150,125,130),  
                new Color(150,125,130),new Color(150,90,130),new Color(150,160,130),new Color(150,175,130),  
                new Color(150,190,130),new Color(150,125,120),new Color(160,125,130),  
                new Color(180,100,130),new Color(150,125,160),new Color(150,125,160) };  
  
        for (int i = 0; i < array.length; i++) {  
            // 创建颜色按钮对象  
            JButton jbn = new JButton();  
            // 设置颜色按钮大小,颜色  
            jbn.setPreferredSize(new Dimension(20, 20));  
            jbn.setBackground(array[i]);  
            //给按钮添加鼠标监听器方法,绑定事件处理类的对象  
            jbn.addMouseListener(ma);  
            // 将按钮添加到可选颜色面板对象上  
            panel1.add(jbn);  
  
        }  
  
        // 设置可选颜色面板上的布局为网格布局  
        panel1.setLayout(new GridLayout(2, 14));  
        // 设置为从左至右的流式布局  
        this.setLayout(new FlowLayout(FlowLayout.LEFT));  
        // 设置背景颜色  
        this.setBackground(null);  
        // 将可选颜色面板添加到颜色面板上  
        this.add(panel1);  
  
    }  

}  


Shape类:基本形状类。

package drawTable;
import java.awt.*;
/**
 * Created by GZ on 2017/11/4 9:23.
 * Description:定义形状,实现形状的显示
 */
public class Shape {
    private int x_start, y_start, x_end, y_end;
    private Color current_color;
    private String shape_command;


    protected int getXstart() {
        return x_start;
    }


    void setXstart(int x1) {
        this.x_start = x1;
    }


    protected int getYstart() {
        return y_start;
    }


    void setYstart(int y1) {
        this.y_start = y1;
    }


    protected int getXend() {
        return x_end;
    }


    void setXend(int x2) {
        this.x_end = x2;
    }


    protected int getYend() {
        return y_end;
    }


    void setYend(int y2) {
        this.y_end = y2;
    }


    protected Color getColor() {
        return current_color;
    }


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


    protected String getShapeCommand() {
        return shape_command;
    }


    public void setShapeCommand(String shape_command) {
        this.shape_command = shape_command;
    }


    public Shape(int x1, int y1, int x2, int y2, Color color, String shapeCommand) {
        this.x_start = x1;
        this.y_start = y1;
        this.x_end = x2;
        this.y_end = y2;
        this.current_color = color;
        this.shape_command = shapeCommand;
    }


    public String toString() {
        return this.getXstart()+","+this.getYstart()+","+this.getXend()+","+this.getYend()+","+this.getColor()+","+this.getShapeCommand();
    }


    public void draw(Graphics g){
        Graphics2D g2d=(Graphics2D)g;
        g2d.setStroke(new BasicStroke(1));
        //抗锯齿处理
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        g.setColor(this.getColor());
        String shape_command=getShapeCommand();
        System.out.println(this);
        
        //命令判别
        if(shape_command.equals("line")){  
            g.drawLine(x_start, y_start, x_end, y_end);  
            
        }else if(shape_command.equals("oval")){  
       
            if(x_start<x_end&&y_start<y_end){  
                g.drawOval(x_start, y_start,Math.abs(x_start-x_end), Math.abs(y_start-y_end));  
            }else if(x_start>x_end&&y_start>y_end){  
                g.drawOval(x_end, y_end, Math.abs(x_start-x_end), Math.abs(y_start-y_end));  
            }else if (x_start>x_end&&y_start<y_end){  
                g.drawOval(x_end,y_start, Math.abs(x_start-x_end), Math.abs(y_start-y_end));  
            }else if(x_start<x_end&&y_start>y_end){  
                g.drawOval(x_start, y_end,Math.abs(x_start-x_end) , Math.abs(y_start-y_end));  
            }  
            
        }else if(shape_command.equals("rect")) {  
       
            if(x_start<x_end&&y_start<y_end){  
        g.drawRect(x_start, y_start,Math.abs(x_start-x_end), Math.abs(y_start-y_end));  
            }else if(x_start>x_end&&y_start>y_end){  
                g.drawRect(x_end, y_end, Math.abs(x_start-x_end), Math.abs(y_start-y_end));     
            }else if(x_start>x_end&&y_start<y_end){  
                g.drawRect(x_end, y_start, Math.abs(x_start-x_end), Math.abs(y_start-y_end));  
            }else if(x_start<x_end&&y_start>y_end){  
                g.drawRect(x_start, y_end, Math.abs(x_start-x_end), Math.abs(y_start-y_end));  
            }     
        }else if(shape_command.equals("roundrect")){  
       
            if(x_start<x_end&&y_start<y_end){  
                g.drawRoundRect(x_start, y_start,Math.abs( x_end-x_start), Math.abs(y_end-y_start),10,10);  
                    }else if(x_start>x_end&&y_start>y_end){  
                        g.drawRoundRect(x_end, y_end, Math.abs(x_start-x_end), Math.abs(y_start-y_end),10,10);      
                    }else if(x_start>x_end&&y_start<y_end){  
                        g.drawRoundRect(x_end, y_start, Math.abs(x_start-x_end), Math.abs(y_start-y_end),10,10);  
                    }else if(x_start<x_end&&y_start>y_end){  
                        g.drawRoundRect(x_start, y_end, Math.abs(x_start-x_end), Math.abs(y_start-y_end),10,10);  
                    }     
        }else if(shape_command.equals("pencil")){  
        g.drawLine(x_start, y_start, x_end, y_end);  
            //将直线的结束点的坐标作为下一条直线的开始点  
            //x_start=x_end;  
            //y_start=y_end;  
        }else if(shape_command.equals("brush")) {
        g2d.setStroke(new BasicStroke(8));  
        g2d.drawLine(x_start, y_start, x_end, y_end);  
        g2d.setStroke(new BasicStroke(1));  
        }else if(shape_command.equals("easer")) {
        g2d.setStroke(new BasicStroke(8));  
        g2d.drawLine(x_start, y_start, x_end, y_end);  
        g2d.setStroke(new BasicStroke(1));  
        } else if(shape_command.equals("spray")) {
        g2d.drawLine(x_start+x_end, y_start+y_end, x_start+x_end+1, y_start+y_end+1);  
        } 
    }  
}

MouseListener类:MVC中的controller,主要是业务逻辑。重点讲解一下相关工具的实现,具体图形是拖拽呈现但不保存,鼠标抬起的那一刻图形定格并保存到Shape数组中。喷枪依靠随机的生成点营造效果,生成点多了就变成了刷子。铅笔就是点动成线的原理,诸多的小线段进行首尾连接。橡皮可以类比颜色为白的刷子。

package drawTable;
/** 
 * 鼠标监听器类 
 */  


import java.awt.Color;  
import java.awt.Graphics;  
import java.awt.event.MouseAdapter;  
import java.awt.event.MouseEvent;
import java.util.Random;
public class MouseListener extends MouseAdapter{  
  
    // 定义一些基本属性  
    // 画笔颜色  
    private Color penColor = Color.black;  
    // 画笔
    private Graphics g;  
    // 坐标参数
    private int x_start, y_start, x_end, y_end;  
    // 画板上的工具栏
    private ToolPannel tp ;  
    // 颜料板
    private ColorChoose cp;  
    // 画板上的画布
    // 标识
    public static boolean flag;  
    private DrawPannel dp;
    private final static int MAX_CACHED_PAINTED_SHAPE = 100000;
    //一个数组,用于缓存已经绘制的所有形状
    private Shape[] shapeArr = new Shape[MAX_CACHED_PAINTED_SHAPE];
    //当前已经绘制的形状的数目
    private int index;
    //绘制的每一个形状(除去拖动)
    private Shape shape;
    //保存拖动过程中的每一个形状
    private Shape shape_dragged;


    //图像缓存空间
    
    String shapeCommand = "line";//形状
    /** 
     * 构造方法 
     */  
    public MouseListener(ToolPannel tp ,ColorChoose cp,DrawPannel dp){  
        this.tp = tp;  
        this.cp = cp;  
        this.dp = dp;
        //this.jp = dp.panel;//画板上的画布
        this.g = dp.panel.getGraphics();  //获得画笔
    }  
    
    @Override
    public void mousePressed(MouseEvent e) {  
        // 获得x_start,y_start的坐标  
        x_start = e.getX();  
        y_start = e.getY();  
        if(e.getButton() == 1){  
            penColor = cp.fcolor;  
        }else if(e.getButton() == 3){  
            penColor = cp.bcolor;  
        }  
        System.out.println("x1->" + x_start + ",y1->" + y_start);
    }  
    /**
     * 事件监听类。包括按钮点击事件和鼠标事件
     */
 
    //鼠标释放监听事件
    @Override
    public void mouseReleased(MouseEvent e) {  
        x_end = e.getX();  
        y_end = e.getY();           
        System.out.println("x2->" + x_end + ",y2->" + y_end);
        //判别区域
        if (x_start<0||x_start >= DrawBegin.Panel_width||y_start<0||y_start>DrawBegin.Panel_height) {
            System.out.println("Can't draw out of Panel!");
            return;
        }
        if (x_end<0){
            x_end=0;
        }
        if(y_end<0) {
        y_end=0;
        }
        if (x_end>DrawBegin.Panel_width){
            x_end=DrawBegin.Panel_width;
        }
        if(y_end>DrawBegin.Panel_height) {
        y_end=DrawBegin.Panel_height;
        }
        g.setColor(penColor);  //画笔颜色默认为黑色
        /**
         * 松开鼠标时,将已经绘制的形状加入缓存
         */ 
        if(tp.shape_command.equals("easer")) {
        shape = new Shape(x_start, y_start, x_end, y_end, Color.white,tp.shape_command);
            shapeArr[index++] = shape;
            dp.display(index, shapeArr, shape);
        }else {
        shape = new Shape(x_start, y_start, x_end, y_end, penColor,tp.shape_command);
            shapeArr[index++] = shape;
            dp.display(index, shapeArr, shape);
        }
    }  
  
    //鼠标拖拽监听事件
    /**
     * 鼠标拖拽预览。
     * 预览的实现:拖拽之后,立即重绘,但是不把绘制的形状加入缓存。
     */
    @Override
    public void mouseDragged(MouseEvent e){  
    //判别画图区域是否在画板范围内
    g.setColor(penColor);  //画笔颜色默认为黑色
    int x_end = e.getX();
        int y_end = e.getY();
        System.out.println("Dragged:x->" + x_end + ",y->" + y_end);
        if (x_start<0||x_start >= DrawBegin.Panel_width||y_start<0||y_start>DrawBegin.Panel_height) {
            System.out.println("Can't draw out of Panel!");
            return;
        }
        if (x_end<0){
            x_end=0;
        }
        if(y_end<0) {
        y_end=0;
        }
        if (x_end>DrawBegin.Panel_width){
            x_end=DrawBegin.Panel_width;
        }
        if(y_end>DrawBegin.Panel_height) {
        y_end=DrawBegin.Panel_height;
        }
        
        //shape_dragged = new Shape(x_start, y_start, x_end, y_end, penColor, tp.shape_command);
        //display();//根据不同命令开始画画
                if(tp.shape_command.equals("brush")){  
                shape = new Shape(x_start, y_start, x_end, y_end, penColor,tp.shape_command);
                x_start=x_end;
                y_start=y_end;
                    shapeArr[index++] = shape;
                    dp.display(index, shapeArr, shape);
                }else if(tp.shape_command.equals("easer")){  
                //g.setColor(Color.WHITE);  
                shape = new Shape(x_start, y_start, x_end, y_end, Color.white,tp.shape_command);
                x_start=x_end;
                y_start=y_end;
                    shapeArr[index++] = shape;
                    dp.display(index, shapeArr, shape);
                   // g.setColor(penColor);  
                }else if(tp.shape_command.equals("spray")){//如果是喷枪  
                    //获取坐标值  
                    x_end=e.getX();  
                    y_end=e.getY();  
                    //实例化一个随机数对象  
                    Random rand = new Random();  
                    //循环画多个点  
                    for(int i=0;i<20;i++){  
                        //随机生成新的x和y点,用来绘制不同的点  
                        int x = rand.nextInt(8);  
                        int y = rand.nextInt(8);  
                        //开始绘制点  
                        shape = new Shape(x_end, y_end, x, y, penColor,tp.shape_command);
                        shapeArr[index++] = shape;
                        dp.display(index, shapeArr, shape);
                    }  
                }else if(tp.shape_command.equals("pencil")){
                shape = new Shape(x_start, y_start, x_end, y_end, penColor,tp.shape_command);
                x_start=x_end;
                y_start=y_end;
                    shapeArr[index++] = shape;
                    dp.display(index, shapeArr, shape);
                }else{
               
                shape_dragged = new Shape(x_start, y_start, x_end, y_end, penColor, tp.shape_command);
                dp.display(index,shapeArr,shape_dragged);
               
               
                }
             
    }
    
}  

上述就是相关代码的说明,总体上的效果还是比较理想的。但在实现过程中,每一次在画布上增添新的笔墨,其实都要整体重绘,感觉在实现方法和效率上不是很合理!不知道Windows的画板是如何实现的?!应该有更为优化的方法吧!上述代码改了很长时间,又由于是作业的缘故,所以当时特别希望能够有完善的代码直接拿来用,但之后想想,感觉还是通读代码后,加之自己的理解,在此基础上完善代码的经历更有意义!所以也期望阅读博文的你有用心去研读!

完整代码资源可在此链接下载:https://download.csdn.net/download/gzharryanonymous/10425695


  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值