• 画图工具之优化篇


    import java.awt.BasicStroke;
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    /**
     * 1.新建一个LoginListener事件处理类,
     * 该类实现MouseListener鼠标事件接口,实现接口中的抽象方法。
     * 2.定义四个变量,在按下和释放方法中获取按下和释放的坐标值。
        3.定义Graphics画笔画布类的对象,调用绘制图形的方法来画图。
            我们的组件是画出来的,那么你要在哪一个组件上画图形,那你的画笔画布对象就从这个组件上获取。
        4.实例化DrawListener事件处理类的对象,对象名dl
        5.给事件源窗体对象添加addMouseListener()鼠标监听方法,指定事件处理类对象dl.
    
     */
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.event.MouseMotionListener;
    import java.util.Random;
    
    import javax.swing.JButton;
    
    //F3键可以看到代码
    public class LoginListener implements MouseListener, ActionListener, MouseMotionListener {
        // private int c;
        int x, y;
        private int x1, y1, x2, y2, x3, y3;// x4, y4;
        int a1, a2, a3, a4, b1, b2, b3, b4;
        double X1, X2, Y1, Y2;
        double a, b, c, d, k, f;
        public int sx, sy, ex, ey;// 存储任意多边形的起始点坐标和结束点的坐标
        public int count = 0;// 记录画的是任意多边形的第几条线
        private Color color = Color.BLACK;
        private Random rand = new Random();/*
                                             * 实例化一个随机数类的对象
                                             * 之前是在for循环中定义实例化的rand,增加了时间复杂度和空间复杂度,
                                             * 每次循环都会实例化一个rand变量,所以不要再循环中定义变量;
                                             */
        public String s = "";
    
        public Shape[] Sh;
        public int i = 0;
    
        public void setSh(Shape[] sh) {
            Sh = sh;
        }
    
        Graphics g;// 声明一个画笔画布类的对象名
    
        private Graphics2D g1;// 声明一个画布类的对象;Graphics2D是Graphics的一个子类。
        BasicStroke S = new BasicStroke(10);
        BasicStroke C = new BasicStroke(1);// 方法一:实例化画笔粗细。设置画笔粗细为1.
        /*
         * 没有用到对象的属性和方法就不用传过去;
         */
    
        public void SetG(Graphics gra) {
            g = gra;// 把gra给g;
            g1 = (Graphics2D) gra;// 强制转型
    
            g1.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            // 设置设置画笔抗锯齿,使线条更加平滑。
        }
    
        /**
         * 当你在事件源上发生鼠标按下动作时执行的方法。
         */
    
        public void mousePressed(MouseEvent e) {
            // 取得鼠标按下时取得的坐标;
            x1 = e.getX();
            y1 = e.getY();
    
        }
    
        /**
         * 当你在事件源上发生鼠标释放动作时执行的方法。
         */
        public void mouseReleased(MouseEvent e) {
    
            x3 = e.getX();
            y3 = e.getY();
    
            if (s.equals("直线")) {
                g1.setColor(color);
                g1.setStroke(C);
                g1.drawLine(x1, y1, x3, y3);
                Shape shape = new Shape(x1, y1, x3, y3, Color.black, new BasicStroke(1), "直线");
                Sh[i++] = shape;
                if (i == 10000) {
                    i = 0;
                }
    
            } else if (s.equals("圆")) {
                g1.setColor(color);
                g1.setStroke(C);
                g1.drawOval(x1, y1, x3 - x1, y3 - y1);
                Shape shape = new Shape(x1, y1, x3 - x1, y3 - y1, Color.black, new BasicStroke(1), "圆");
                Sh[i++] = shape;
                if (i == 10000) {
                    i = 0;
                }
    
            } else if (s.equals("立体球")) {
                g1.setColor(color);
                g1.setStroke(C);
    
                // g1.drawOval(x3, y3, 50, 50);
                for (int c = 50; c > 0; c--) {
    
                    g.fillOval(x3++, y3++, 2 * c, 2 * c); // 使用当前颜色填充外接指定矩形框的椭圆。
    
                    Color col = g.getColor();
                    int red = col.getRed();
                    int blue = col.getBlue();
                    int green = col.getGreen();
                    red += 5;
                    if (red > 255)
                        red = 255;
                    blue += 5;
                    if (blue > 255)
                        blue = 255;
                    green += 5;
                    if (green > 255)
                        green = 255;
                    col = new Color(red, green, blue);
                    g.setColor(col);
    
                } // g.setColor(color);
            } else if (s.equals("矩形")) {
                System.out.println("小:" + x1 + "    " + y1);
                g1.setColor(color);
                g1.setStroke(C);
                g1.drawRect(x1, y1, x3 - x1, y3 - y1);
                Shape shape = new Shape(x1, y1, x3 - x1, y3 - y1, Color.black, new BasicStroke(1), "矩形");
                Sh[i++] = shape;
                if (i == 10000) {
                    i = 0;
                }
    
            } else if (s.equals("任意多边形") && count == 0) {// 判断是否画任意多边形的第一条线
    
                g1.setColor(color);
                g1.setStroke(C);
                g1.drawLine(x1, y1, x3, y3);
                // System.out.println(" x1 "+x1 +" y1 "+y1 +" x3 "+x3 +" y3 "+y3);
                Shape shape = new Shape(x1, y1, x3, y3, Color.black, new BasicStroke(1), "任意多边形");
                Sh[i++] = shape;
                if (i == 10000) {
                    i = 0;
                }
    
                // 存储第一条线的起始点
                sx = x1;
                sy = y1;
                // 存储第一条线的结束点
                ex = x3;
                ey = y3;
    
                count++;// 表示第一条已经画完了
            }
    
        }
    
        /**
         * 当你的鼠标进入到事件源是行时执行的方法。
         */
        public void mouseEntered(MouseEvent e) {
    
        }
    
        /**
         * .当你的鼠标离开到事件源是行时执行的方法。
         */
        public void mouseExited(MouseEvent e) {
    
        }
    
        /**
         * 当你在事件源上发生鼠标点击动作时执行的方法。(在同一个位置上按下并释放才会执行点击)
         */
    
        public void mouseClicked(MouseEvent e) {
    
            x = e.getX();
            y = e.getY();
            // System.out.println(s);
            // System.out.println(color);
            if (s.equals("任意多边形") && count != 0) {// 判断是否已经画完任意多边形的第一条线了
                // 获取点击的坐标值
    
                g1.setColor(color);
                g1.setStroke(C);
                if (e.getClickCount() == 2) {// 判断是双击,图形要闭合
                    // 使用x,y和ex,ey画闭合的第一条线
                    // System.out.println(" ex " +ex+" ey "+ ey+" x " +x+" y "+ y);
                    g1.drawLine(x, y, ex, ey);
    
                    Shape shape = new Shape(x, y, ex, ey, Color.black, new BasicStroke(1), "任意多边形");
                    Sh[i++] = shape;
                    if (i == 10000) {
                        i = 0;
                    }
    
                    // 使用x,y和sx,sy画闭合图形的最后 一条线
    
                    g1.drawLine(sx, sy, x, y);
                    // System.
                    // System.out.println("sx"+" "+sx +"sy " +sy +" " + x+" "+ y);
                    Shape shapes = new Shape(sx, sy, x, y, Color.black, new BasicStroke(1), "任意多边形");
                    Sh[i++] = shapes;
                    if (i == 10000) {
                        i = 0;
                    }
                    // 改变count的值,好让下一次又是重新开始新的多边形
                    count = 0;
                } else {// 判断不是双击,要接下来的线
    
                    // 根据上一条线的结束点和当前点击的坐标,来绘制直线
                    g1.drawLine(ex, ey, x, y);
                    // System.out.println(" ex "+ex +" ey "+ ey +" x "+x +" y "+y);
                    Shape shape = new Shape(ex, ey, x, y, Color.black, new BasicStroke(1), "任意多边形");
                    Sh[i++] = shape;
                    if (i == 10000) {
                        i = 0;
                    }
                    // 将当前这条线的结束赋给ex,ey,作为下一条线的起始点
                    ex = x;
                    ey = y;
    
                }
    
            } else if (s.equals("三角金字塔形")) {
    
                g1.setColor(color);
                drawsanjiaojinzita();
            }
    
            else if (s.equals("角")) {
    
                g1.setColor(color);
                drawjiao();
    
            } else if (s.equals("手环")) {
    
                g1.setColor(color);
                drawShouhuang();
            } else if (s.equals("外星飞船形")) {
    
                g1.setColor(color);
                drawwaixingfeichuang();
    
            } else if (s.equals("菱形星空")) {
    
                g1.setColor(color);
                drawlingxingxingkong();
    
            } else if (s.equals("树形")) {
    
                g1.setColor(color);
                drawshuxing();
    
            } else if (s.equals("递归正方形")) {
    
                g1.setColor(color);
                a1 = 90;
                a2 = 0;
                drawdigui(x1, y1, a1, a2);
    
            } else if (s.equals("递归三角形")) {
    
                g1.setColor(color);
                if (count < 3) { // 用变量控制存储四个值;
                    g1.drawLine(x, y, x, y);
                    if (count == 0) {
                        a1 = x;
                        b1 = y;
                        // System.out.println(a1 + " 1 " + a1);
                    } else if (count == 1) {// 存储第二个值B
                        a2 = x;
                        b2 = y;
    
                    } else if (count == 2) {// 存储第三个值C
                        a3 = x;
                        b3 = y;
                        // System.out.println(x3+" 3 "+y3);
                    }
    
                    count++;
                } else {
                    /*
                     * 先是得到三个点的坐标;然后调用方法;
                     * 在方法中,先画出这个三角形,然后求得三边的三个中点值,然后画出新的三角形,
                     * 这时,要记得转换坐标,因为我们是要在这个三角形外边画三个三角形,而不是接着在它的里面画,
                     * 转换之后又会得到新的三个坐标,然后进行第一递归;
                     * 然后在第一递归回归是,画上旁边的另一个三角形;进行递归;第三次也是如此;
                     * 要在三边都画上所以转换三次坐标就可以了;
                     * 要注意的是:应该注意函数回归时带回来的值;
                     *
                     */
                    a4=0;
                    
                    diguisanjiaoxing( a1,  b1,  a2,  b2, a3, b3, a4);
                    count=0;
                }
            }
        }
    
        @Override // 当鼠标拖动时,在事件源上按下鼠标按键然后拖动鼠标时执行的方法。
        public void mouseDragged(MouseEvent e) {
            x2 = e.getX();
            y2 = e.getY();
            if (s.equals("画笔")) {
                /**
                 * 因为在拖动过程当中会不断取点,如果起点固定则画出来的都是在一个点开始的。
                 * 以上一个拖动取到的坐标作为下一段直线的起点,从而画出曲线。
                 */
    
                g1.setColor(color);
                g1.setStroke(C);
    
                g1.drawLine(x1, y1, x2, y2);
                Shape shape = new Shape(x1, y1, x2, y2, Color.black, new BasicStroke(1), "任意多边形");
                Sh[i++] = shape;
                if (i == 10000) {
                    i = 0;
                }
    
                x1 = x2;// 转换坐标。
                y1 = y2;
    
            }
            if (s.equals("刷子")) {
    
                g1.setColor(color);
                g1.setStroke(S);// 要进行转换画笔,再画;设置线条的粗细。
    
                g1.drawLine(x1, y1, x2, y2);
                Shape shape = new Shape(x1, y1, x2, y2, Color.black, new BasicStroke(10), "刷子");
                Sh[i++] = shape;
                if (i == 10000) {
                    i = 0;
                }
    
                x1 = x2;// 转换坐标。
                y1 = y2;
    
            }
            if (s.equals("橡皮擦")) {
                g1.setStroke(S);
                g1.setColor(Color.WHITE); // 设置线条的颜色为白色来绘制橡皮擦。
                g1.drawLine(x1, y1, x2, y2);
                Shape shape = new Shape(x1, y1, x2, y2, Color.WHITE, new BasicStroke(10), "橡皮擦");
                Sh[i++] = shape;
                if (i == 10000) {
                    i = 0;
                }
                x1 = x2;// 转换坐标。
                y1 = y2;
                // g1.setColor(Color.black);// 在画完之后转换回一般的格式就可以不用在每个都设置。粗细也是。
                // g1.setStroke(new BasicStroke(1));// 设置粗细法二。
    
            }
            if (s.equals("喷枪")) {
                g1.setStroke(C);
    
                g1.setColor(color);
                int size = rand.nextInt(50) + 20;// 随机决定要画的点数,size的范围在20到69之间。没有“+20”时,只有0到49之间
                for (int i = 0; i < size; i++) {
                    int x = rand.nextInt(8);// 在0到7之间随机取点。
                    int y = rand.nextInt(8);
                    g1.drawLine(x2 + x, y2 + y, x2 + x, y2 + y);// 有随机数来改变坐标,在X2,Y2附件画点。
    
                    Shape shape = new Shape(x2 + x, y2 + y, x2 + x, y2 + y, Color.black, new BasicStroke(1), "喷枪");
                    Sh[this.i++] = shape;
                    if (this.i == 10000) {
                        this.i = 0;// 注意区分变量;
                    }
                }
    
                // g1.setColor(Color.black);
                // g1.setStroke(C);
    
            }
    
        }
    
        public void drawsanjiaojinzita() {
            g1.setColor(Color.BLUE);
            g1.setStroke(C);
    
            if (count < 4) { // 用变量控制存储四个值;
                g1.drawLine(x, y, x, y);
    
                /*
                 * 之前是写的四个并列的if语句,所以每执行一次都会调用所有的if语句,同样的增加了程序运行的时间,增加了时间复杂度;
                 * 所有要加上else if;来减少程序运行的时间。所有学会减少不必要的语句;
                 */
                if (count == 0) {// 存储第一个值A
                    a1 = x;// 之前是写的x1=x;这样增加了空间复杂度,时间复杂度;
                    b1 = y;// 改成x1=e.getY();可以少定义一个变量;减少占用的空间;
                    // System.out.println(a1 + " 1 " + a1);
                } else if (count == 1) {// 存储第二个值B
                    a2 = x;
                    b2 = y;
                    // System.out.println(a2 + " 2 " + a2);
                } else if (count == 2) {// 存储第三个值C
                    a3 = x;
                    b3 = y;
                    // System.out.println(x3+" 3 "+y3);
                } else if (count == 3) {// 存储第四个值P;
                    a4 = x;
                    b4 = y;
                }
    
                count++;
            }
    
            if (count >= 4) {
                for (int c = 0; c <= 10000; c++) {
                    int s = rand.nextInt(3);// 这个不能放在for循环外边;随机数的大小;0到3;取值取0,1,2;
                    if (s == 0) {// 当随机数取0时,色子面为A;
                        a4 = (a1 + a4) / 2;
                        b4 = (b1 + b4) / 2;
                    } else if (s == 1) {// 当随机数取1时,色子面为B;
                        a4 = (a2 + a4) / 2;
                        b4 = (b2 + b4) / 2;
                    } else {// 当随机数取2时,色子面为C。
                        a4 = (a3 + a4) / 2;
                        b4 = (b3 + b4) / 2;
                    }
    
                    g1.drawLine(a4, b4, a4, b4);
    
                }
                count = 0;// count值变为0,然后开始下一个图形。不然只能画一个图形;
    
            }
    
        }
    
        public void drawjiao() {
            double a = -2, b = -2, c = -1.2, d = 2;
            for (int n = 0; n <= 50000; n++) {
                g1.setColor(new Color(0, 128, 255));
                g1.setStroke(C);
    
                /*
                 * 先算出值,然后再来画图; 画图时要注意,因为求出的值很小,所以需要扩大。 而强制转型时应该是求出的值整体转也就是应该加上括号(x2
                 * * 100 + 350), int m = (int)x2 * 100 + 350
                 * ,不加括号时是,X2转型之后,再乘以100,加上350,
                 */
                X2 = (Math.sin(a * Y1) - Math.cos(b * X1));
                Y2 = (Math.sin(c * X1) - Math.cos(d * Y1));
                // int m = (int) (x2 * 100 + 350);(x2 * 100 + 350)整体强制转型;
                // int s = (int) (y2 * 100 + 350);这时是X2乘以100加上350得到的数再进行转型;
                // g.drawLine(m, s, m, s);
                g1.drawLine((int) (X2 * 100 + 300), (int) (Y2 * 100 + 300), (int) (X2 * 100 + 300), (int) (Y2 * 100 + 300));
                // 强制转型时,要注意加上括号,整体转型
                X1 = X2;
                Y1 = Y2;
    
            }
        }
    
        public void drawShouhuang() {
    
            g1.setColor(new Color(0, 255, 64));
            g1.setStroke(C);
    
            // double x1 = 0, y1 = 0, x2 = 0, y2 = 0;
            a = 1.40;
            b = 1.56;
            c = 1.40;
            d = -6.56;
            for (int n = 0; n <= 60000; n++) {
                X2 = d * Math.sin(a * X1) - Math.sin(b * Y1);
                Y2 = c * Math.cos(a * X1) + Math.cos(b * Y1);
                g1.drawLine((int) (X2 * 50 + 500), (int) (Y2 * 50 + 200), (int) (X2 * 50 + 500), (int) (Y2 * 50 + 200));
                // 乘以的数,控制大小,整体相加改变位置;
                X1 = X2;
                Y1 = Y2;
    
            }
    
        }
    
        public void drawwaixingfeichuang() {
            g1.setColor(new Color(41, 225, 102));
            g1.setStroke(C);
    
            a = 0.4;
            b = 1;
            c = 0;
    
            /**
             * signum(double d):返回参数的符号函数;如果参数为 0,则返回 0;如果参数大于 0,则返回 1.0;如果参数小于
             * 0,则返回 -1.0。 abs(double a):返回 double 值的绝对值。 sqrt(double a):返回正确舍入的
             * double 值的正平方根。
             */
    
            for (int n = 0; n <= 100000; n++) {
                X2 = Y1 - Math.signum(X1) * Math.sqrt(Math.abs(b * X1 - c));
                Y2 = a - X1;
                g1.drawLine((int) (X2 * 150 + 500), (int) (Y2 * 150 + 200), (int) (X2 * 150 + 500), (int) (Y2 * 150 + 200));
                // 乘以的数,控制大小,整体相加改变位置;
                X1 = X2;
                Y1 = Y2;
            }
        }
    
        public void drawshuxing() {
    
            // 1.建立一个for循环,在For循环中用随机数来实现概率;
    
            g1.setColor(new Color(58, 235, 116));
            g1.setStroke(C);
            for (int i = 0; i < 77000; i++) {
    
                // 用随机数来实现概率: 能够满足条件的的随机数的点数 除以 所有的随机数 = 本次事件的概率
    
                int u = rand.nextInt(100);
    
                if (u < 10) {
                    a = 0.0;
                    b = 0.0;
                    c = 0.0;
                    d = 0.16;
                    k = 0.0;
                    f = 0.0;
    
                } // 当随机数为0到9时,执行,这时的概率为0.1;
                else if (u < 18) {
                    a = 0.2;
                    b = -0.26;
                    c = 0.23;
                    d = 0.22;
                    k = 0.0;
                    f = 1.6;
                    // 当随机数为10到17时,执行,这时的概率为0.08;
                } else if (u < 25) {
                    a = -0.15;
                    b = 0.28;
                    c = 0.26;
                    d = 0.24;
                    k = 0.0;
                    f = 0.44;
                    // 当随机数为18到24时,执行,这时的概率为0.08;
                } else {
                    a = 0.75;
                    b = 0.04;
                    c = -0.04;
                    d = 0.85;
                    k = 0.0;
                    f = 1.6;
                    // 当随机数为25到99时,执行,这时的概率为0.74;
                }
                X2 = a * X1 + b * Y1 + k;
                Y2 = c * X1 + d * Y1 + f;
    
                // System.out.println((int)(x2*100+200));
                // System.out.println((int)(y2*100+200));
    
                g1.drawLine((int) (X2 * 100 + 500), (int) (Y2 * (-50) + 510), (int) (X2 * 100 + 500),
                        (int) (Y2 * (-50) + 510));// 空指针异常指的是g;
                // (int)(y2*(-50)+600);乘以的负数可以改变图形的方向;
                X1 = X2;
                Y1 = Y2;
    
            }
    
        }
    
        public void drawlingxingxingkong() {
            g1.setColor(Color.BLUE);
            g1.setStroke(C);
            int a = 1, b = 4, c = 60;
            // double x1 = 0, y1 = 0, x2 = 0, y2 = 0;
    
            for (int n = 0; n <= 60000; n++) {
                X2 = Y1 - Math.signum(X1) * Math.sqrt(Math.abs(b * X1 - c));
                Y2 = a - X1;
                g1.drawLine((int) (X2 * 3 + 600), (int) (Y2 * 3 + 400), (int) (X2 * 3 + 600), (int) (Y2 * 3 + 400));// 注意画线的值;
                // 乘以的数,控制大小,整体相加改变位置;该图形的乘数不能太大,最好控制在0-5之间
                X1 = X2;
                Y1 = Y2;
            }
    
        }
    
        public void drawdigui(int x1, int y1, int a1, int a2) {
            /*
             * 画一个正方形,改变他的坐标以及大小,来进行递归;现递推画出一个小三角形,在回归的时候再来画其他的(此时只要改变坐标就好);
             */
    
            g1.drawRect(x1, y1, a1, a1);
            x1 = x1 - a1;// 改变画的位置,改变大小由当前的图形的大小来进行调整。
            y1 = y1 - a1;
            a1 = a1 / 3;// 改变正方形的大小;长和高
            a2++;
            if (a2 > 5)
                return;// 只要一个就好;
            drawdigui(x1, y1, a1, a2);// 第一次的递归;画的是左上角的第一个正方形;
            x1 = x1 + 4 * a1;// 改变x轴的坐标,大小不变,画一个向右移动的图形;
            drawdigui(x1, y1, a1, a2);
            x1 = x1 + 4 * a1;
            drawdigui(x1, y1, a1, a2);
            y1 = y1 + 4 * a1;// 改变y轴的坐标,大小不变,画一个向下移动的图形;
            drawdigui(x1, y1, a1, a2);
            x1 = x1 - 8 * a1;
            drawdigui(x1, y1, a1, a2);
            y1 = y1 + 4 * a1;
            drawdigui(x1, y1, a1, a2);
            x1 = x1 + 4 * a1;
            drawdigui(x1, y1, a1, a2);
            x1 = x1 + 4 * a1;
            drawdigui(x1, y1, a1, a2);
    
        }
    
        public void diguisanjiaoxing(int a1, int b1, int a2, int b2, int a3, int b3,int a4) {
            int c1,d1,c2,d2,c3,d3;
            g1.drawLine(a1, b1, a2, b2);
            g1.drawLine(a2, b2, a3, b3);
            g1.drawLine(a1, b1, a3, b3);
            //求出中点坐标;来画三角形;
            c1=(a2+a3)/2;
            d1=(b2+b3)/2;
            c2=(a1+a3)/2;
            d2=(b1+b3)/2;
            c3=(a2+a1)/2;
            d3=(b2+b1)/2;
            System.out.println(c1 + "    " + d1 + "    " + c2 + "    " + d2 + "    " + c3 + "    " + d3);
            g1.drawLine(c1, d1, c2, d2);
            g1.drawLine(c2, d2, c3, d3);
            g1.drawLine(c1, d1, c3, d3); 
            //转换坐标求得新三个值来画;
            a3=c3;
            b3=d3;
            a1=c1;
            b1=d1;
            a4++;
            if(a4>6)return;
            diguisanjiaoxing( a1,  b1,  a2,  b2, a3, b3,a4);
            a3=a1*2-a2;
            b3=b1*2-b2;//在回归的基础上求得新的坐标;注意带回来的值;
            a2=c2;
            b2=d2;
            diguisanjiaoxing( a1,  b1,  a2,  b2, a3, b3,a4);
            a1=a2*2-a3;
            b1=b2*2-b3;
            a3=c3;
            b3=d3;
            diguisanjiaoxing( a1,  b1,  a2,  b2, a3, b3,a4);
            
        }
    
        public void actionPerformed(ActionEvent e) {
            // 得到按钮上的文字;
            if (e.getActionCommand().equals("")) {
                JButton but = (JButton) e.getSource();// getSource():最初发生 Event 的对象。
                color = but.getBackground();
            } else {
                s = e.getActionCommand();
            }
            // System.out.println(s);
            // System.out.println(color);
            // getActionCommand()的方法是ActionEvent的,也就是e的。
    
        }
    
        @Override
        /*
         * 当在事件源上移动鼠标时执行的方法。
         */
        public void mouseMoved(MouseEvent e) {
    
        }
    
    }
    LoginListener.java
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    
    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    /**
     * 定义一个画图界面类,该类继承自JFrame窗体类.
     */
    public class DrawFrame extends JFrame {
        /**
         * 程序入口主函数
         */
        public Shape[] Sh = new Shape[10000];// 两个方法都要用到这个属性时,属性不能定义在一个方法中;应该定义在一个类里面;
        // (刚刚是定义在了public void initUN(){}方法中;但是在paint方法中用的时候就不能用了;)
    
        public static void main(String[] args) {
            // 实例化窗体类的对象,调用初始化界面的方法
            DrawFrame dl = new DrawFrame();
            dl.initUN();
            // dl.setBackground(Color.WHITE);这个是错误的不能改变窗体的颜色,只能改变组件的颜色。
        }
    
        public void initUN() {
            setTitle("简单画图");
            setSize(1300, 700);
            setDefaultCloseOperation(3);
            setLocationRelativeTo(null);
            setLayout(new BorderLayout());//设置窗体为的布局方式边框布局(边框布局是把容器分为上北下南左西右东中间五部分。)
    
    
            /*
             * //实例化一个流失布局类的对象,布局类是针对容器的,容器上要填多个组件,那么必须要设置排列对齐方式;
             * java.awt.FlowLayout fl=new java.awt.FlowLayout();
             * jf.setLayout(fl);//设置窗体的布局方式为流式布局 //定义一个ImageIcon类,该类用来读取一个磁盘的图片文文件。
             */
    
            LoginListener dn = new LoginListener();
            //getContentPane().setBackground(Color.WHITE);// getContenPane为 改变窗口的颜色。
        //*******************设置窗体北边的部分***********************************/
            JPanel northPanel = new JPanel();//创建具有双缓冲和流布局的新 JPanel。 
            //利用数组存储值,再添加JButton,简化了代码
            String[] jbu = { "直线", "矩形", "圆", "任意多边形", "画笔", "刷子", "橡皮擦", "喷枪", "三角金字塔形", "角", "手环", "外星飞船形", "菱形星空",
                    "树形" ,"立体球","递归正方形","递归三角形"};
            for (int i = 0; i < jbu.length; i++) {
                ImageIcon ima = new ImageIcon("E:\hesi\LoginDemo\bin\HuaTu\" + jbu[i] + ".jpg");
              //  ImageIcon ima = new ImageIcon(this.getClass().getResource(jbu[i] + ".png"));//这个命令是把java文件和图片放在一起。避免图片消失。
                JButton but1 = new JButton(ima);// 这个是加载图片;
                but1.setPreferredSize(new Dimension(80, 80));// 设置按钮大小;
                but1.setActionCommand(jbu[i]);// 设置按钮所触发的动作命令字符串。
    
            //    JButton but1 = new JButton(jbu[i]);
                //but1.setPreferredSize(new Dimension(70,50));
                but1.setBackground(Color.pink);
                //this.add(but1);//错误,不应该加到窗体上;
                but1.addActionListener(dn);
                northPanel.add(but1);
            }
    
            this.add(northPanel, BorderLayout.NORTH);
            northPanel.setPreferredSize(new Dimension(160,160));//设置边框的大小;
               //*******************设置窗体中间的部分***********************************/
            JPanel centerPanel = new JPanel() {
                
                public void paint(Graphics g) {
                    super.paint(g);// super表示调用父类中的paint方法。
                    
                    /*
                     * 输出数组中的值;然后画出图形;
                     */
            
                    for (int i = 0; i < 10000; i++) {
                        Shape shape = Sh[i];
    
                        if (null != shape) {
                            
                            ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                    RenderingHints.VALUE_ANTIALIAS_ON);
                            // 这个变量不用存,直接设置就可以了;
                            // 设置设置画笔抗锯齿,使线条更加平滑。
    
                            g.setColor(shape.color);
                            ((Graphics2D) g).setStroke(shape.stroke);// 如果之前画的时候没有设置这个粗细,那么在调用这里的这个就是空的;
                        //    System.out.println(shape.type);
                            //System.out.println("  x1   "+shape.x1 +"  y1   "+shape.y1   +"   x2   "+shape.x2   +"   y2   "+shape.y2);
                            if (shape.type.equals("直线") || shape.type.equals("任意多边形") || shape.type.equals("画笔")
                                    || shape.type.equals("刷子") || shape.type.equals("喷枪") || shape.type.equals("橡皮擦")) {
                                g.drawLine(shape.x1, shape.y1, shape.x2, shape.y2);
                            } else if (shape.type.equals("圆")) {
                                g.drawOval(shape.x1, shape.y1, shape.x2, shape.y2);
                            } else if (shape.type.equals("矩形")) {
                                g.drawRect(shape.x1, shape.y1, shape.x2, shape.y2);
                            }
    
                        } else {
                            break;
                        }
    
                    }
    
                }
            };
              
            centerPanel.setBackground(Color.WHITE);
            this.add(centerPanel, BorderLayout.CENTER);//添加到CENTER布局中去;
             //*******************设置窗体南边的部分***********************************/
            JPanel southPanel = new JPanel();
            //利用数组存储值,再添加JButton,简化了代码
            Color[] Col = { Color.blue, Color.GREEN, Color.PINK, Color.ORANGE, Color.RED, Color.YELLOW, Color.WHITE,
                    new Color(148, 65, 154), new Color(29, 136, 167), new Color(0, 255, 64) };
    
            for (int i = 0; i < Col.length; i++) {
                JButton but2 = new JButton();
                but2.setBackground(Col[i]);
                but2.setPreferredSize(new Dimension(40, 50));
                but2.addActionListener(dn);
                southPanel.add(but2);
            }
            
            this.add(southPanel, BorderLayout.SOUTH);
    
            setVisible(true);
            dn.setSh(Sh);// 对象.方法名(参数);
            centerPanel.addMouseListener(dn);// 给事件源窗体对象添加addMouseListener()鼠标监听方法,指定事件处理类对象.
            centerPanel.addMouseMotionListener(dn);//给centerPanel加上监听方法,是在centerPanel上面画画;
      
            // 获取窗体上画笔画布对象(注意:必须要在窗体可见之后才能获取画笔画布对象,否则获取的是null)
            //Graphics  g=getGraphics();
            dn.SetG(centerPanel.getGraphics());
            //dn.SetG(g);
    
        }
    }
    DrawFrame.java
    package HuaTu;
    
    import java.awt.Color;
    import java.awt.Stroke;
    
    public class Shape {
        public int x1, x2, y1, y2;
        public Color color;
        public String type;
        public Stroke stroke;
    
        public Shape() {
    
        }
    
        public Shape(int x1, int y1, int x2, int y2, Color color, Stroke stroke, String type) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.color = color;
            this.stroke = stroke;// 之前少了这一个,造成了变量为空的情况;
            this.type = type;
    
        }
    
    }
    Shape.java

                                          画图工具之优化篇

    对于之前的画图窗体,做了初步的修改,简化了程序,优化了代码,并且加上了颜色的选项;一个自己的画图小工具正在生成中;

    通过这次的学习,对于优化程序,在程序中查找错误,都有进一步的认识和理解;

    同时也增加了几个小图形,接着我们一个一个的来进行分析;

    首先是,优化代码。 

    我把之前的代码,在Clicked中画角的,画手环的,等画图形的几个方法,单独定义了函数也就是方法,只是在public void mouseClicked(MouseEvent e){}这个方法中调用它;

    这样也就看起来更加的方便,而且对于查找错误也是很方便的,这个真的是深有体会;如下:


    else if (s.equals("角")) {
    
    g1.setColor(color);
    drawjiao();
    
    } else if (s.equals("手环")) {
    
    g1.setColor(color);
    drawShouhuang();
    }

    这样代码看起来也比较方便;

    对于查找错误的方法,我们可以通过输出语句来,输出值来查看,这个对于画图形的时候相当有帮助。

    其次,新学了,一个布局。

    setLayout(new BorderLayout());//设置窗体为的布局方式边框布局(边框布局是把容器分为上北下南左西右东中间五部分。)

    把布局分为了窗体北边,中间,和南边的部分,在北边添加图片实现功能按钮,在中间放上画布,在南边也就是最下边放上颜色按钮;

    这里要注意的就是:

    北边(JPanel northPanel = new JPanel();):

    因为是在按钮上添加图片所以我们无法获取图片上的文字,所以我们要注意设置按钮所触发的动作命令字符串。

    but1.setActionCommand(jbu[i]);

     ImageIcon ima = new ImageIcon(this.getClass().getResource(jbu[i] + ".png"));//这个命令是把java文件和图片放在一起。避免图片消失。

    加载图片时最好用这个命令;

    中间:JPanel centerPanel = new JPanel();

    实现重绘的方法;

    南边:JPanel centerPanel = new JPanel();

    增加了颜色按钮;

    在此过程中,用数组存储颜色和加载的功能按钮的名字,在用循环添加按钮,这样就减少了代码,以及提高了效率;之前重复的写了很多代码,每增加一个JButton就重写;现在还觉得累;

    还有要注意的是,给事件源窗体对象添加addMouseListener()鼠标监听方法,指定事件处理类对象时,我们的事件源以及改变了,是在窗体中间画;所以应该给centerPanel加上监听方法;

     此次加上了新的图形:“树形”,"立体球","递归正方形","递归三角形"。

    先来看“树形”:树形是由四组数据,四个概率表示的;

    在这里我们运用了随机数来表示概率;

    for (int i = 0; i < 77000; i++) {

    // 用随机数来实现概率: 能够满足条件的的随

    机数的点数 除以 所有的随机数 = 本次事件的概率


    int u = rand.nextInt(100);
    
    if (u < 10) {
    a = 0.0;
    b = 0.0;
    c = 0.0;
    d = 0.16;
    k = 0.0;
    f = 0.0;
    
    } // 当随机数为0到9时,执行,这时的概率为0.1;
    else if (u < 18) {
    a = 0.2;
    b = -0.26;
    c = 0.23;
    d = 0.22;
    k = 0.0;
    f = 1.6;
    // 当随机数为10到17时,执行,这时的概率为0.08;
    } else if (u < 25) {
    a = -0.15;
    b = 0.28;
    c = 0.26;
    d = 0.24;
    k = 0.0;
    f = 0.44;
    // 当随机数为18到24时,执行,这时的概率为0.08;
    } else {
    a = 0.75;
    b = 0.04;
    c = -0.04;
    d = 0.85;
    k = 0.0;
    f = 1.6;
    // 当随机数为25到99时,执行,这时的概率为0.74;
    }
    
     
    
    "立体球":球的画法如同我们美术画的素描;用颜色的深浅来显示立体感;
    
    不同的是这里的颜色是通过改变构成它三原色来实现的:
    
     
    
    for (int c = 50; c > 0; c--) {
    
    g.fillOval(x3++, y3++, 2 * c, 2 * c); // 使用当前颜色填充外接指定矩形框的椭圆。
    
    Color col = g.getColor();//先得到他的颜色的值;
    int red = col.getRed();
    int blue = col.getBlue();
    int green = col.getGreen();
    red += 5;//逐渐改变大小;
    if (red > 255)
    red = 255;//值在0到255之间;
    blue += 5;
    if (blue > 255)
    blue = 255;
    green += 5;
    if (green > 255)
    green = 255;
    
    //三个值为255时,是黑色,三个值是0时,是白色;
    col = new Color(red, green, blue);//用得到的新的值,来画圆;
    g.setColor(col);

    "递归正方形","递归三角形":

    这两个都是用递归来实现的,我认为可以把递归简单地理解为循环,但是和for循环等又有不一样的地方,递归还会带回来值;递归要有return语句;

    使用递归是要注意得到和输出的值;个人认为递归要比循环好用;

    "递归正方形"


     
    
    public void drawdigui(int x1, int y1, int a1, int a2) {
    /*
    * 画一个正方形,改变他的坐标以及大小,来进行递归;现递推画出一个小三角形,在回归的时候再来画其他的(此时只要改变坐标就好);
    */
    
    g1.drawRect(x1, y1, a1, a1);
    x1 = x1 - a1;// 改变画的位置,改变大小由当前的图形的大小来进行调整。
    y1 = y1 - a1;
    a1 = a1 / 3;// 改变正方形的大小;长和高
    a2++;
    if (a2 > 5)
    return;// 只要一个就好;
    drawdigui(x1, y1, a1, a2);// 第一次的递归;画的是左上角的第一个正方形;
    x1 = x1 + 4 * a1;// 改变x轴的坐标,大小不变,画一个向右移动的图形;
    drawdigui(x1, y1, a1, a2);
    x1 = x1 + 4 * a1;
    drawdigui(x1, y1, a1, a2);
    y1 = y1 + 4 * a1;// 改变y轴的坐标,大小不变,画一个向下移动的图形;
    drawdigui(x1, y1, a1, a2);
    x1 = x1 - 8 * a1;
    drawdigui(x1, y1, a1, a2);
    y1 = y1 + 4 * a1;
    drawdigui(x1, y1, a1, a2);
    x1 = x1 + 4 * a1;
    drawdigui(x1, y1, a1, a2);
    x1 = x1 + 4 * a1;
    drawdigui(x1, y1, a1, a2);
    
    }

    "递归三角形":

     先是得到三个点的坐标;然后调用方法;
     在方法中,先画出这个三角形,然后求得三边的三个中点值,然后画出新的三角形,
     这时,要记得转换坐标,因为我们是要在这个三角形外边画三个三角形,而不是接着在它的里面画,
     转换之后又会得到新的三个坐标,然后进行第一递归;
     然后在第一递归回归是,画上旁边的另一个三角形;进行递归;第三次也是如此;
     要在三边都画上所以转换三次坐标就可以了;
    要注意的是:应该注意函数回归时带回来的值;


    public void diguisanjiaoxing(int a1, int b1, int a2, int b2, int a3, int b3,int a4) {
    int c1,d1,c2,d2,c3,d3;
    g1.drawLine(a1, b1, a2, b2);
    g1.drawLine(a2, b2, a3, b3);
    g1.drawLine(a1, b1, a3, b3);
    //求出中点坐标;来画三角形;
    c1=(a2+a3)/2;
    d1=(b2+b3)/2;
    c2=(a1+a3)/2;
    d2=(b1+b3)/2;
    c3=(a2+a1)/2;
    d3=(b2+b1)/2;
    System.out.println(c1 + " " + d1 + " " + c2 + " " + d2 + " " + c3 + " " + d3);
    g1.drawLine(c1, d1, c2, d2);
    g1.drawLine(c2, d2, c3, d3);
    g1.drawLine(c1, d1, c3, d3); 
    //转换坐标求得新三个值来画;
    a3=c3;
    b3=d3;
    a1=c1;
    b1=d1;
    a4++;
    if(a4>6)return;
    diguisanjiaoxing( a1, b1, a2, b2, a3, b3,a4);
    a3=a1*2-a2;
    b3=b1*2-b2;//在回归的基础上求得新的坐标;注意带回来的值;
    a2=c2;
    b2=d2;
    diguisanjiaoxing( a1, b1, a2, b2, a3, b3,a4);
    a1=a2*2-a3;
    b1=b2*2-b3;
    a3=c3;
    b3=d3;
    diguisanjiaoxing( a1, b1, a2, b2, a3, b3,a4);
    
    }

    本次的图形的结果:

  • 相关阅读:
    kafka数据可靠性深度解读【转】
    漫游Kafka实战篇之搭建Kafka运行环境
    redis 数据持久化
    redis学习笔记之pipeline
    为redis分配一个新的端口
    redis配置实例及redis.conf详细说明
    Redis内存存储结构分析
    windows下安装redis
    show engine innodb status 详解
    Redis常用命令手册:服务器相关命令
  • 原文地址:https://www.cnblogs.com/hesi/p/5624995.html
Copyright © 2020-2023  润新知