画图板基本功能实现

画图板基本功能实现

显现了基本图形绘制,画笔效果切换,绘图存储恢复等功能

1,界面UI

1.1 效果展示

在这里插入图片描述

基本方法认识使用JFrame类,进行分块并添加组件:

1.2 注意事项

(1)JFrame默认BorderLayout边界布局,JPanel默认FlowLayout流式布局,JFrame中加JPanel,JPanel中加JPanel。

(2)BorderLayout的效果
在这里插入图片描述

(3)单独给JPanel添加监听器,有别于前边给整个JFrame对象加上监听器,可以让画的图只在面板之内

(4)重中之重:一定要在所有按钮添加上上后再显示窗口,一定在显示窗口之后再调取Graphics对象

(5)用配置数组+循环语句对按钮进行批量添加

package Drawer.MyDrawer;

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

public class MyDrawerUI {
    public MyDrawerUI(){
        initUI();
    }
    public void initUI(){
        //JFrame对象的默认布局为边界布局
        JFrame jf=new JFrame("MyDrawer");
        jf.setSize(900,800);
        jf.setLocation(200,200);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //不可调整大小
        jf.setResizable(false);
        //位置依赖为空
        jf.setLocationRelativeTo(null);
        //给JFrame面板加上两个JPanel,JPanel对象的默认布局方式是流式布局
        JPanel[] jps=addJPanelToJFrame(jf);
        //给第一个JPanel再加上三个JPanel对象,即再分成三块
        JPanel[] jpsInJps=addJPanelToJPanel(jps[0]);

        //添加按钮并附加监听器
        JButton[] btns1=addGraphicsBTN(jpsInJps[0]);
        JButton[] btns2=addColorBTN(jpsInJps[1]);
        JButton[] btns3=addLineWidthBTN(jpsInJps[1]);
        JButton[] btns4=addFunctionBTN(jpsInJps[2]);
        //重中之重:一定要在所有按钮添加上上后再显示窗口,一定在显示窗口之后再调取Graphics对象
        jf.setVisible(true);

        //获取jps[1]的画板
        Graphics g=jps[1].getGraphics();
        //创建监听器对象并用画板初始化
        MyDrawerListener listener=new MyDrawerListener(g);
        //给jps[1],即画板,加上监听器,有别于前边给整个JFrame对象加上监听器,可以让画的图只在面板之内
        jps[1].addMouseListener(listener);
        jps[1].addMouseMotionListener(listener);
        //给按钮数组加上监听器,可以用for循环
        addBTNListener(btns1,listener);
        addBTNListener(btns2,listener);
        addBTNListener(btns3,listener);
        addBTNListener(btns4,listener);
    }
    public void setFlowLayoutOfJPanel(JPanel[] jps){
        for (int i = 0; i < jps.length; i++) {
            jps[i].setLayout(new FlowLayout());
        }
    }
    //给按钮数组加上监听器的方法
    public void addBTNListener(JButton[] btns, ActionListener al){
        for (int i = 0; i < btns.length; i++) {
            btns[i].addActionListener(al);
        }
    }
    //给JPanel对象批量加上按钮的方法
    public JButton[] addGraphicsBTN(JPanel jp){
        String[] GRAPHICS_BTN = {"直线","矩形","圆","签字笔","实时直线","实时矩形","多边形","自动多边形"};
        //这里创建的仅仅是一系列指针数组,每个指针指向的值还是要具体new出来
        JButton[] btns=new JButton[GRAPHICS_BTN.length];
        for (int i = 0; i < GRAPHICS_BTN.length; i++) {
            JButton btn=new JButton(GRAPHICS_BTN[i]);
            jp.add(btn);
            //给每个指针指向对应对象
            btns[i]=btn;
        }
        return btns;
    }
    public JButton[] addColorBTN(JPanel jp){
        Color[] COLORS={Color.BLACK,Color.white,Color.RED,Color.green,Color.blue};
        JButton[] btns=new JButton[COLORS.length];
        String[] colorNames={"黑","白","红","绿","蓝"};
        for (int i = 0; i < COLORS.length; i++) {
            JButton btn=new JButton(colorNames[i]);
            btn.setPreferredSize(new Dimension(50,30));
            btn.setBackground(COLORS[i]);
            jp.add(btn);
            btns[i]=btn;
        }
        return btns;
    }
    public JButton[] addLineWidthBTN(JPanel jp){
        String[] lineWidths={"细 ","中 ","粗 "};
        //String[] lineWidths={"s","m","l"};
        JButton[] btns=new JButton[lineWidths.length];
        for (int i = 0; i < lineWidths.length; i++) {
            JButton btn=new JButton(lineWidths[i]);
            btn.setPreferredSize(new Dimension(50,50));
            jp.add(btn);
            btns[i]=btn;
        }
        return btns;
    }
    public JButton[] addFunctionBTN(JPanel jp){
        String[] func={"橡皮擦","清空屏幕"};
        JButton[] btns=new JButton[func.length];
        for (int i = 0; i < func.length; i++) {
            JButton btn=new JButton(func[i]);
            btn.setPreferredSize(new Dimension(80,80));
            jp.add(btn);
            btns[i]=btn;
        }
        return btns;
    }
    //给JFame窗口对象加上面板对象的方法
    public JPanel[] addJPanelToJFrame(JFrame jf) {
        Color[] colors = {Color.GRAY, Color.WHITE, Color.RED, Color.GREEN, Color.BLUE};
        String[] location = {BorderLayout.NORTH, BorderLayout.CENTER};
        JPanel[] jps = new JPanel[location.length];
        for (int i = 0; i < location.length; i++) {
            JPanel jp=new JPanel();
            jp.setLayout(new BorderLayout());
            jp.setPreferredSize(new Dimension(100,100));
            jp.setBackground(colors[i]);
            jf.add(jp, location[i]);
            jps[i]=jp;
        }
        return jps;
    }
    //给JPanel对象加上面板对象的方法
    public JPanel[] addJPanelToJPanel(JPanel jp){
        String[] JPANEL_LOCATION_OF_JPANEL={
                BorderLayout.WEST,BorderLayout.CENTER,BorderLayout.EAST
        };
        Color[] colors = {Color.GRAY, Color.WHITE, Color.RED, Color.GREEN, Color.BLUE};
        JPanel[] jps=new JPanel[JPANEL_LOCATION_OF_JPANEL.length];
        for (int i = 0; i < JPANEL_LOCATION_OF_JPANEL.length; i++) {
            JPanel jPanel=new JPanel();
            //不要用setSize()!!!!!!!!!!!!!!!!!!!!!!
            jPanel.setPreferredSize(new Dimension(300,100));
            jPanel.setBackground(colors[i]);
            jp.add(jPanel,JPANEL_LOCATION_OF_JPANEL[i]);
            jps[i]=jPanel;
        }
        return jps;
    }

    public static void main(String[] args) {
        new MyDrawerUI();
    }

}

2,监听器与画图方法设计

2.1 监听器

(1)使用了静态数组用以配置 监听按钮 与 效果;

(2)设置了多个公共变量用于在监听器中全局使用;例如,标识当前图形种类,画笔颜色,画笔粗细,临时存储需要多个坐标绘制的图形;

(3)使用switch语句分别调取对应的方法;

(4)重写构造方法,必须传入Graphics类

2.2 画图方法

为了能调整画笔的粗细,将Graphics类强转为Graphics2D

(1)直线

mousePressed()获取第一个点的坐标,mouseReleased()获取第二个点的坐标,并绘制

(2)实时直线

mousePressed()获取第一个点的坐标,mouseDragged()实时获取移动过程中的坐标,并先后做有颜色直线和白色直线的绘制,效果显示为闪烁,该方法会存在擦除现有图形的问题。

(3)矩形

基本方法同直线,但要解决只能画右下方向矩形的问题,解决方法:获取按下和释放是的两个坐标,取min(x1,x2),min(y1,y2),为矩形的初始点,差值绝对值为长宽g.drawRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));

(4)实时矩形

同上

(5)多边形

事实上每次连线只需要前一个点的坐标和当前位置的坐标,以及为了使得图形封闭需要第一个点的坐标,因此,使用两组坐标即可达到目的。使用全局的freeFlag来判断多边形的绘制状态。使用鼠标右键来封闭多边形e.getButten()==3

(6)自动多边形

上边的多边形其实只是简单的点连线,可能出现线交叉。这里是画下一组点会自动练成一个多边形。实现方法:在一组点坐标中,找到最右边的一个点(如果相同,取上边的点),连接此点与其他的点,以此作为比较,对其余点进行排序,按顺序连接这些点,即可得到。

在这里插入图片描述

(7)橡皮擦

即白色的粗的签字笔

(8)清屏

画一个大的白色矩形

package Drawer.MyDrawer;

import Drawer.Drawer2.Pointe;
import MyGraphics.MyCircle;
import MyGraphics.MyGraphic;
import MyGraphics.MyLine;
import MyGraphics.MyRect;

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

public class MyDrawerListener implements ActionListener, MouseListener, MouseMotionListener {
    Graphics2D g;
    static String[] GRAPHICS_NAMES={"直线","矩形","圆","签字笔","实时矩形","实时直线","多边形","自动多边形","橡皮擦","清空屏幕"};
    static String[] COLORS_NAMES={"黑","白","红","绿","蓝"};
    static Color[]  COLORS={Color.BLACK,Color.WHITE,Color.RED,Color.GREEN,Color.BLUE};
    static String[] LINE_WIDTH_NAMES={"细 ","中 ","粗 "};
    static int[] LINE_WIDTH={1,3,9};
    //画多边形时的标识
    int freeFlag=0;
    //闲置坐标
    int x1,x2,y1,y2;
    //自动多边形中的最右点
    Pointe theRightest;
    //自动多边形中除去最右点的所有点数组
    ArrayList<Pointe> list=new ArrayList<Pointe>();
    //储存图形数据
    ArrayList<MyGraphic> myGraphicsList=new ArrayList<>();
    String graphicText="直线";
    String colorText="黑";
    //目前画笔的颜色
    Color nowColor=Color.BLACK;
    //画笔的粗细
    int lineWidth=1;
    //临时字符串
    String tempText="";

    public MyDrawerListener(Graphics g){
        this.g=(Graphics2D) g;//有一个强转的过程,为了使画笔粗细能被调整
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        freeFlag=0;
        tempText=e.getActionCommand();
        int i=0;
        //取出按钮的标识并给相应的标识赋值,执行相应功能
        if(findElem(GRAPHICS_NAMES,tempText)>=0){
            if(tempText.equals("清空屏幕")){
                clearAll();
            }
            else
                graphicText=tempText;
        }
        else if((i=findElem(COLORS_NAMES,tempText))>=0) {
            colorText = tempText;
            nowColor=COLORS[i];
            g.setColor(COLORS[i]);
        }
        else if((i=findElem(LINE_WIDTH_NAMES,tempText))>=0){
            g.setStroke(new BasicStroke(LINE_WIDTH[i]));
            lineWidth=LINE_WIDTH[i];
        }
        System.out.println(tempText);
    }
    //清屏:通过画一个大的白色填充矩形来清屏
    public void clearAll(){
        g.setColor(new Color(255,255,255));
        g.fillRect(0,0,100000,100000);
        g.setColor(new Color(0,0,0));
        System.out.println("down");
    }
    //查找:返回字符串数组的目标值的下标
    public int findElem(String[] strs,String str){
        for (int i=0;i< strs.length;i++){
            if (strs[i].equals(str))
                return i;
        }
        return -1;
    }
    @Override
    public void mouseClicked(MouseEvent e) {
        if(e.getButton()==2){
            for (MyGraphic myGraphic:myGraphicsList) {
                myGraphic.draw(g);
            }
        }
        switch (graphicText){
            case "多边形":
                drawPolygon(e);
                break;
            case "自动多边形":
                drawAutoPolygon(e);
                break;
            default:
                x1=e.getX();
                y1=e.getY();
                break;
        }
    }
    @Override
    public void mousePressed(MouseEvent e) {
        //按下
        switch(graphicText){
            case "多边形":
                break;
            case "自动多边形":
                break;
            default:
                x1=e.getX();
                y1=e.getY();
                break;
        }

    }
    @Override
    public void mouseReleased(MouseEvent e) {
        //释放
        switch (graphicText){
            case "直线":
                x2=e.getX();y2=e.getY();
                g.drawLine(x1,y1,x2,y2);
                myGraphicsList.add(new MyLine(lineWidth,nowColor,x1,y1,x2,y2));
                break;
            case "矩形":
                x2=e.getX();y2=e.getY();
                g.drawRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
                myGraphicsList.add(new MyRect(lineWidth,nowColor,Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2)));
                break;
            case "实时直线":
                x2=e.getX();y2=e.getY();
                g.drawLine(x1,y1,x2,y2);
                myGraphicsList.add(new MyLine(lineWidth,nowColor,x1,y1,x2,y2));
                break;
            case "实时矩形":
                x2=e.getX();y2=e.getY();
                g.drawRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
                myGraphicsList.add(new MyRect(lineWidth,nowColor,Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2)));
                break;
            case "圆":
                x2=e.getX();y2=e.getY();
                g.drawOval(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
                myGraphicsList.add(new MyCircle(lineWidth,nowColor,Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2)));
                break;
            default:
                break;
        }
    }



    @Override
    public void mouseDragged(MouseEvent e) {
        //拖动
        switch (graphicText){
            //实现方法:通过不断在直线上再画一条白色的线来实现闪烁效果
            case "实时直线":
                x2=e.getX();
                y2=e.getY();
                g.drawLine(x1,y1,x2,y2);
                g.setColor(Color.WHITE);
                g.drawLine(x1,y1,x2,y2);
                g.setColor(nowColor);
                break;
            case "实时矩形":
                x2=e.getX();y2=e.getY();
                g.drawRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
                g.setColor(Color.WHITE);
                g.drawRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
                g.setColor(nowColor);
                break;
            case "签字笔":
                pen(e);
                break;
            case"橡皮擦":
                rubber(e);
                break;
            default:
                break;
        }
    }
    //签字笔:通过画直线的方法
    public void pen(MouseEvent e){
        x2=e.getX();
        y2=e.getY();
        g.drawLine(x1,y1,x2,y2);
        x1=x2;y1=y2;
    }
    //橡皮擦:通过画白线的方法,画完把画笔颜色和粗细都还原
    public void rubber(MouseEvent e){
        g.setStroke(new BasicStroke(20));
        x2=e.getX();
        y2=e.getY();
        g.setColor(Color.WHITE);
        g.drawLine(x1,y1,x2,y2);
        x1=x2;y1=y2;
        g.setColor(nowColor);
        g.setStroke(new BasicStroke(lineWidth));
    }
    @Override
    public void mouseMoved(MouseEvent e) {
    }
    @Override
    public void mouseEntered(MouseEvent e) {
    }
    @Override
    public void mouseExited(MouseEvent e) {
    }
    //画多边形
    public void drawPolygon(MouseEvent e){
        if(freeFlag==0){
            x1=x2=e.getX();
            y1=y2=e.getY();
            freeFlag++;
        }
        else if(freeFlag>=1){
            if(e.getButton()==1&&freeFlag==1){
                g.drawLine(x2,y2,e.getX(),e.getY());
                x2=e.getX();
                y2=e.getY();
                freeFlag++;
            }
            else if(e.getButton()==3){
                g.drawLine(x1,y1,x2,y2);
                freeFlag=0;
            }
            else {
                g.drawLine(x2,y2,e.getX(),e.getY());
                x2=e.getX();
                y2=e.getY();
                freeFlag++;
            }
        }
    }
    //画自动多边形:找取最右点,与其余点算正切值,以此对点排序,按次序给各个点连线,即可将各点连线且不相交,得到多边形
    public void drawAutoPolygon(MouseEvent e){
        if(e.getButton()==3){
//            list.sort(new Comparator<Pointe>() {
//                @Override
//                public int compare(Pointe o1, Pointe o2) {
//                    return getLineTan(o1)>getLineTan(o2)?1:0;
//                }
//            });
            //用上边的比较器方法不行,所以自己重写了个冒泡排序
            for(int i=0;i<list.size()-1;i++){
                for(int j=0;j<list.size()-1-i;j++){
                    double a=getLineTan(list.get(j));
                    double b= getLineTan(list.get(j+1));
                    if(a<b){
                        Collections.swap(list,j,j+1);
                    }
                }
            }
            lineAutoPolygon();
            list.clear();
            freeFlag=0;
            return;
        }
        Pointe newPointe=new Pointe(e.getX(),e.getY());
        if(freeFlag==0){
            g.drawOval(e.getX()-2,e.getY()-2,4,4);
            theRightest =newPointe;
            freeFlag++;
            return;
        }
        if(e.getButton()==1){
            g.drawOval(e.getX()-2,e.getY()-2,4,4);
            if(newPointe.x<theRightest.x) {
                list.add(newPointe);
            }
            else{
                list.add(theRightest);
                theRightest=newPointe;
            }
            freeFlag++;
            return;
        }
    }
    //把点连接为多边形
    public void lineAutoPolygon(){
        g.drawLine(list.get(0).x, list.get(0).y,theRightest.x,theRightest.y);
        for (int i=0;i<list.size()-1;i++) {
            g.drawLine(list.get(i).x,list.get(i).y,list.get(i+1).x,list.get(i+1).y);
        }
        int a=list.size()-1;
        g.drawLine(list.get(a).x, list.get(a).y,theRightest.x,theRightest.y);
    }
    //算正切值
    public double getLineTan(Pointe o1){
        double a=o1.y-theRightest.y;
        double b=o1.x-theRightest.x;
        double c=a/b;
        return c;
    }
}

3,图形储存

建立一个新的类,用多态实现,以ArrayList储存
在这里插入图片描述

存储机制:左键松开存储,中键点击恢复

接口

package MyGraphics;

import java.awt.*;

public interface MyGraphicsInterface {
    public void draw(Graphics2D g);
}

超类

package MyGraphics;
import java.awt.*;

public class MyGraphic implements MyGraphicsInterface{
    public int lineWidth;
    public Color myGraphicColor;

    public MyGraphic(int lineWidth, Color myGraphicColor) {
        this.lineWidth = lineWidth;
        this.myGraphicColor = myGraphicColor;
    }

    @Override
    public void draw(Graphics2D g) {
    }
}

子类

package MyGraphics;
import java.awt.*;
//直线类
public class MyLine extends MyGraphic{
    public int x1;
    public int y1;
    public int x2;
    public int y2;

    public MyLine(int lineWidth, Color myGraphicColor, int x1, int y1, int x2, int y2) {
        super(lineWidth, myGraphicColor);
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
    }

    @Override
    public void draw(Graphics2D g) {
        super.draw( g);
        g.setStroke(new BasicStroke(super.lineWidth));
        g.setColor(super.myGraphicColor);
        g.drawLine(x1,y1,x2,y2);
    }
}

package MyGraphics;
import java.awt.*;
//矩形类
public class MyRect extends MyGraphic {
    public int x1;
    public int y1;
    public int width;
    public int heigth;


    public MyRect(int lineWidth, Color myGraphicColor, int x1, int y1, int width, int heigth) {
        super(lineWidth, myGraphicColor);
        this.x1 = x1;
        this.y1 = y1;
        this.width = width;
        this.heigth = heigth;
    }

    @Override
    public void draw(Graphics2D g) {
        super.draw( g);
        g.setStroke(new BasicStroke(super.lineWidth));
        g.setColor(super.myGraphicColor);
        g.drawRect(x1,y1,width,heigth);
    }
}

package MyGraphics;

import java.awt.*;
//圆类
public class MyCircle extends MyGraphic{
    public int x1;
    public int y1;
    public int width;
    public int heigth;

    public MyCircle(int lineWidth, Color myGraphicColor, int x1, int y1, int width, int heigth) {
        super(lineWidth, myGraphicColor);
        this.x1 = x1;
        this.y1 = y1;
        this.width = width;
        this.heigth = heigth;
    }

    @Override
    public void draw(Graphics2D g) {
        super.draw(g);
        g.setStroke(new BasicStroke(lineWidth));
        g.setColor(myGraphicColor);
        g.drawOval(x1,y1,width,heigth);

    }
}

```java

phics;

import java.awt.*;
//圆类
public class MyCircle extends MyGraphic{
    public int x1;
    public int y1;
    public int width;
    public int heigth;

    public MyCircle(int lineWidth, Color myGraphicColor, int x1, int y1, int width, int heigth) {
        super(lineWidth, myGraphicColor);
        this.x1 = x1;
        this.y1 = y1;
        this.width = width;
        this.heigth = heigth;
    }

    @Override
    public void draw(Graphics2D g) {
        super.draw(g);
        g.setStroke(new BasicStroke(lineWidth));
        g.setColor(myGraphicColor);
        g.drawOval(x1,y1,width,heigth);

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值