JavaGUI编程——及贪吃蛇游戏实战

GUI编程

GUI:Graphical User Interface 又称图形用户接口

  • Java不适合做界面设计
  • 不过 Java自己都放弃GUI了,所以了解篇,你懂的
  • GUI怎么玩?

组件:

  • 窗体
  • 弹窗
  • 面板
  • 文本框
  • 列表框
  • 按钮
  • 菜单栏
  • 表格等

事件监听

  • 鼠标事件
  • 键盘事件
  • 窗口事件

1.简介

GUI核心 : Swing , AWT

  • 问什么学?
  • GUI是MVC架构的基础
  • 可以用来开发一些小工具

2.1AWT

JavaGUI编程——及贪吃蛇游戏实战_第1张图片

2.2.认识第一个窗体

package com.gui.demo;
import java.awt.*;
public class GuiDemo1 {
    public static void main(String[] args) {
        Frame frame = new Frame("我的第一个窗体");  // 创建一个窗体
        frame.setSize(300,300);// 设置窗体大小
        frame.setBackground(new Color(214, 123, 56)); // 设置窗体背景颜色
        frame.setResizable(false);//设置窗体不可缩放
        frame.setVisible(true);//设置窗体可视化[如果不设置为true则无法显示]
    }
}

JavaGUI编程——及贪吃蛇游戏实战_第2张图片

2.3.面板

package com.gui.demo;

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class Demo2 {
    public static void main(String[] args) {

        Frame frame = new Frame("这是窗体");

        frame.setBackground(new Color(116, 237, 10));
        frame.setSize(800,550);
        frame.setLayout(null); // 设置取消默认布局
        frame.setLocationRelativeTo(null); // 设置自动居中
        frame.setVisible(true);
        frame.addWindowListener(new WindowAdapter() {
//            给窗体添加一个窗口监听器,解决窗体关闭问题
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        Panel panel = new Panel(); // 这是面板
        panel.setBounds(30,50,150,450); // 设置面板大小及相对于窗体位置
        panel.setBackground(new Color(221, 69, 59)); //设置面板的背景颜色
        frame.add(panel); // 将面板添加到窗体中
    }
}

JavaGUI编程——及贪吃蛇游戏实战_第3张图片

解决乱码问题

Run As Run Configuration,在Arguments中增加下面这句:
-Dfile.encoding=gbk

2.4.三种布局管理器

  • 流式布局
package com.gui.demo;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class Demo3 {
    public static void main(String[] args) {

        Frame frame = new Frame();

        frame.setSize(300,300);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
               System.exit(0);
            }
        });

//        创建按钮
        Button button1 = new Button("按钮1");
        Button button2 = new Button("按钮2");
        Button button3 = new Button("按钮3");
        Button button4 = new Button("按钮4");

//        设置窗体为流式布局
        frame.setLayout(new FlowLayout()); //默认居中对齐
//        frame.setLayout(new FlowLayout(FlowLayout.LEADING)); // 头[左上角]对齐
//        frame.setLayout(new FlowLayout(FlowLayout.LEFT));// 左对齐
//        frame.setLayout(new FlowLayout(FlowLayout.RIGHT));//右对齐
//        frame.setLayout(new FlowLayout(FlowLayout.TRAILING)); //尾部[右上角]对齐
        frame.add(button1);
        frame.add(button2);
        frame.add(button3);
        frame.add(button4);

        frame.setVisible(true);
    }
}

JavaGUI编程——及贪吃蛇游戏实战_第4张图片

  • 东南西北中(边界布局)
package com.gui.demo;

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class Demo4 {
    public static void main(String[] args) {
        Frame frame = new Frame();

        Button buttonE = new Button("东");
        Button buttonS = new Button("南");
        Button buttonW = new Button("西");
        Button buttonN = new Button("北");
        Button buttonC = new Button("中");
//        设置为边界布局
        frame.setLayout(new BorderLayout());
        frame.add(buttonE,BorderLayout.EAST);
        frame.add(buttonW,BorderLayout.WEST);
        frame.add(buttonS,BorderLayout.SOUTH);
        frame.add(buttonN,BorderLayout.NORTH);
        frame.add(buttonC,BorderLayout.CENTER);

        frame.setSize(500,500);
        frame.setVisible(true);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }
}

JavaGUI编程——及贪吃蛇游戏实战_第5张图片

  • 网格布局

    package com.gui.demo;
    
    import java.awt.*;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    
    public class Demo5 {
        public static void main(String[] args) {
    
            Frame frame = new Frame();
    
            Button button1 = new Button("button1");
            Button button2 = new Button("button2");
            Button button3 = new Button("button3");
            Button button4 = new Button("button4");
            Button button5 = new Button("button5");
            Button button6 = new Button("button6");
            Button button7 = new Button("button7");
            Button button8 = new Button("button8");
            Button button9 = new Button("button9");
    
            frame.add(button1);
            frame.add(button2);
            frame.add(button3);
            frame.add(button4);
            frame.add(button5);
            frame.add(button6);
            frame.add(button7);
            frame.add(button8);
            frame.add(button9);
            frame.setLayout(new GridLayout(3,3)); //三行三列的网格布局
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            });
            frame.setSize(500,500);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    }
    

    JavaGUI编程——及贪吃蛇游戏实战_第6张图片

  • 综合应用

    JavaGUI编程——及贪吃蛇游戏实战_第7张图片

    package com.gui.demo;
    
    import java.awt.*;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    
    public class Demo6 {
        public static void main(String[] args) {
            Frame frame = new Frame("面板&布局综合应用");
            frame.setSize(800,500);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            });
    
    
            Panel panelT = new Panel(); //顶部面板
            Panel panelB = new Panel();// 底部面板
            Panel panelTC = new Panel();//顶部中间面板
            Panel panelBC = new Panel();//底部中间
    
            Button button1 = new Button("1号按钮");
            Button button2 = new Button("2号按钮"); // 顶部中间上
            Button button3 = new Button("3号按钮"); //顶部中间下
            Button button4 = new Button("4号按钮");
    
            panelTC.setLayout(new GridLayout(2,1)); // 2行1列
            panelT.setLayout(new BorderLayout());
            panelTC.add(button2); //顶部中间上
            panelTC.add(button3);//顶部中间下
            panelT.add(panelTC,BorderLayout.CENTER);//顶部中间
            panelT.add(button1,BorderLayout.WEST);//顶部西边
            panelT.add(button4,BorderLayout.EAST);//顶部东边
    
            Button button5 = new Button("按钮5");
            Button button6 = new Button("按钮6");
            Button button7 = new Button("按钮7");
            Button button8 = new Button("按钮8");
            Button button9 = new Button("按钮9");
            Button button10 = new Button("按钮10");
    
            panelB.setLayout(new GridLayout(1,3)); // 1行3列网格布局
            panelBC.setLayout(new GridLayout(2,2)); // 两行两列网格布局
            panelB.add(button5);
            panelB.add(panelBC);
            panelB.add(button10);
    
            panelBC.add(button6);
            panelBC.add(button7);
            panelBC.add(button8);
            panelBC.add(button9);
    
            frame.setLayout(new GridLayout(2,1));
            frame.add(panelT);
            frame.add(panelB);
    
        }
    }
    

    JavaGUI编程——及贪吃蛇游戏实战_第8张图片

2.5.事件监听

package com.gui.demo;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class Demo7 {
    public static void main(String[] args) {

        Frame frame = new Frame();
        frame.setVisible(true);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        Button button1 = new Button("点我一下");
        Button button2 = new Button("也点我一下");

        button1.addActionListener(new Click());//添加事件监听
        button2.addActionListener(new Click());//添加事件监听

        frame.setLayout(new GridLayout(1,2));
        frame.add(button1);
        frame.add(button2);
        frame.pack();
    }
}

class Click implements ActionListener{ /// 创建一个点击事件,实现ActionListener接口

    @Override
    public void actionPerformed(ActionEvent e) {
        String actionCommand = e.getActionCommand();
        if (actionCommand.equals("点我一下")){
            System.out.println("讨厌,你点我了");
        }else {
            System.out.println("叫你点,你就点!!");
        }
    }
}
  • 文本框事件监听
package com.gui.demo;


import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class Demo8 {
    public static void main(String[] args) {
        Frame frame = new Frame();
        frame.setSize(300,300);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        frame.setVisible(true);

        TextField textField = new TextField();
        textField.setEchoChar('*');  // 设置密文编码
        textField.addActionListener(new MyActionListener());//按下回车触发
        frame.add(textField);
    }
}

class MyActionListener implements ActionListener{

    @Override
    public void actionPerformed(ActionEvent e) {
        TextField textField = (TextField) e.getSource();// 获取一个Object对象
        System.out.println(textField.getText());//获取输入的数值
        textField.setText("");//清空文本框
    }
}
  • 画笔+鼠标监听+集合实现画图工具

    JavaGUI编程——及贪吃蛇游戏实战_第9张图片

package com.gui.demo;


import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Iterator;

public class Demo9 {
    public static void main(String[] args) {
        new MyFrame("画图").loding(300, 300, 800, 550);
    }
}

// 画图窗体
class MyFrame extends Frame {
    private MyMouseListener listener = null;
    private ArrayList<Point> list = null;

    public MyFrame(String title) throws HeadlessException {
        super(title);
    }
    public void loding( int x, int y, int width, int height){
//        窗体初始化配置
        this.list = new ArrayList<Point>();// 集合初始化,用来存储点
        setBounds(x, y, width, height);
        setVisible(true);
        this.addMouseListener(new MyMouseListener()); // 增加鼠标监听
        this.addWindowListener(new Close()); // 增加窗体关闭监听
    }

    @Override
    public void paint(Graphics g) {
//        设置画笔颜色
        g.setColor(Color.black);
        Iterator<Point> iterator = this.list.iterator(); // 创建一个迭代器
        while (iterator.hasNext()) {
            Point point = iterator.next();
            g.fillOval(point.x, point.y, 10, 10); // 画点
        }
    }

    // 将点添加到集合中
    public void addPoint(Point point) {
        this.list.add(point);
    }

    class MyMouseListener extends MouseAdapter { // 监听鼠标事件
        @Override
        public void mouseClicked(MouseEvent e) {
//        点击
            MyFrame frame = (MyFrame) e.getSource(); // 获取窗体
            frame.addPoint(new Point(e.getX(), e.getY()));//添加点
            frame.repaint();//重新执行画笔
        }
    }

    class Close extends WindowAdapter { // 监听窗体关闭
        @Override
        public void windowClosing(WindowEvent e) {
            System.exit(0);
        }
    }
}

JavaGUI编程——及贪吃蛇游戏实战_第10张图片

  • 键盘监听

    package com.gui.demo;
    
    import java.awt.*;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyEvent;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    
    public class Demo10 {
        public static void main(String[] args) {
            new MyFrame10().loading();
        }
        static class MyFrame10 extends Frame{
            public MyFrame10() throws HeadlessException {
                super();
            }
            public void  loading(){
                this.addKeyListener(new KeyListener());
                this.setVisible(true);
                this.addWindowListener(new WindowClose());
            }
        }
    
        static class WindowClose extends WindowAdapter{
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        }
    
        static class KeyListener extends KeyAdapter{
            @Override
            public void keyPressed(KeyEvent e) {
                System.out.println(e.getKeyCode());
                if (e.getKeyCode()==e.VK_UP){// 通过e.getKeyCode可以获取按键的编码,也可以用e.VK_xx 来替代
                    System.out.println("你按下了上键");
                }
                System.out.println("你按下了按键");
            }
    
            @Override
            public void keyReleased(KeyEvent e) {
                System.out.println("你松开了按键");
            }
        }
    }
    
    

3.1.Swing

- Swing是AWT的再次封装
package com.gui.demo;
import javax.swing.*;
import java.awt.*;

public class Demo11 {
    public static void main(String[] args) {

        Demo11 demo11 = new Demo11();
        demo11.new MyJFrame().init();

    }
    class MyJFrame extends JFrame{

        public MyJFrame() throws HeadlessException {
            super();
            init();
        }

        public void init(){
        setVisible(true);
        setBounds(400,300,800,550);
        JLabel label = new JLabel("我是JFrame");
        label.setHorizontalAlignment(SwingConstants.CENTER);//设置标签文字居中
        add(label);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); //设置默认关闭
        }
    }

}

3.2.弹窗

package com.gui.demo;

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

public class Demo12 {
    public static void main(String[] args) {
        JFrame jFrame = new JFrame();
        jFrame.setSize(300,200);
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JButton button = new JButton("点击弹窗");
        jFrame.setVisible(true);
        jFrame.add(button);
        button.addActionListener(new MyActionListenerDemo12());

    }
}
class MyActionListenerDemo12 implements ActionListener{

    @Override
    public void actionPerformed(ActionEvent e) {
        MyDialog myDialog = new MyDialog();
        myDialog.setSize(150,100);
        myDialog.setVisible(true);
    }
}

class MyDialog extends JDialog{

    public MyDialog() {
        super();
        JLabel label = new JLabel("你好,我是弹窗!");
        add(label);
    }
}

3.3其他组件

  • 单选框,复选框
  • 菜单栏
  • 表格
  • 文本域等

更多请自行查阅API

4.GUI案例(贪吃蛇)

JavaGUI编程——及贪吃蛇游戏实战_第11张图片

  • 定时器

    定时器是一个可以实现在规定时间间隔内循环执行代码块的一种机制

  • 蛇身应该如何移动?

    JavaGUI编程——及贪吃蛇游戏实战_第12张图片

  • 只要在极短的时间内更新画面,人眼无法分辨看起来动画就像是连贯的,这样就实现了让蛇动起来

  • 下边我们看具体实现

  1. 首先我们需要一个窗体用来装载游戏面板
package com.snake.snake;

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

public class SnakeJFrame extends JFrame {
    public SnakeJFrame(String title) throws HeadlessException {
        super(title);
    }

    public void init(){
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1100,700); // 设置窗体大小
        setLocationRelativeTo(null);//初始化默认居中
        setResizable(false);  // 设置大小不可改变
        add(new GamePanel());
        setVisible(true);  // 必须放在最后不然会捕捉不到面板上的事件!!!
    }
}
  1. 定义必须的一些变量
int length; // 记录蛇的长度
int[] snakeX = new int[960]; // 记录蛇的x坐标
int[] snakeY = new int[960]; // 记录蛇的y坐标
String fx;  // 记录方向,默认向右
boolean isStart; // 暂停标志位
boolean isFail;  // 游戏结束标志位
int scores; //得分
Timer timer = new Timer(100, this); // 定时器

3.面板初始化

public GamePanel() {
    init();
    this.setFocusable(true); //获取焦点事件
    this.addKeyListener(this); //键盘监听事件
}

public void init() {
    snakeX[0] = 200;snakeY[0] = 100;
    snakeX[1] = 175;snakeY[1] = 100;
    snakeX[2] = 150;snakeY[2] = 100;
    snakeX[3] = 125;snakeY[3] = 100;

    Foods.makeFoods();

    fx = "R";
    isStart = false;
    isFail = false;
    length = 3;
    scores = 0;
}
  1. 画出画面
 @Override
    public void paint(Graphics g) {
        super.paint(g);
        paintInterface(g); // 游戏界面绘制
        paintSnake(g);  // 画蛇
        paintFoods(g); // 画食物

    }

    private void paintFoods(Graphics g) {
        //        画出食物
        if (snakeX[0] == Foods.getFoodX() && snakeY[0] == Foods.getFoodY()) // 判断是否吃到食物
        {

            length++;
            if (length==960)// 判断是否胜利
            {
                timer.stop();
                JOptionPane.showMessageDialog(getRootPane(),"你赢了!");
            }
            Foods.makeFoods();
            again:
            for (int i = 1; i <length ; i++) {//判断是位置是否可以生成食物
                if (snakeX[i]==Foods.getFoodX()&&snakeY[i]==Foods.getFoodY()){
                    Foods.makeFoods();
                    break again;
                }
            }
        }// 画出食物
        Data.FOOD.paintIcon(this, g, Foods.getFoodX(), Foods.getFoodY());
    }

    private void paintSnake(Graphics g) {
        //      判断蛇头方向
        if (fx.equals("R")) {
            Data.RIGHT.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("L")) {
            Data.LEFT.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("U")) {
            Data.UP.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("D")) {
            Data.DOWN.paintIcon(this, g, snakeX[0], snakeY[0]);
        }

//        循环画出蛇身
        for (int i = 1; i <= length; i++) {
            Data.BODY.paintIcon(this, g, snakeX[i], snakeY[i]);
        }
    }

    private void paintInterface(Graphics g) {
        setBackground(new Color(166, 200, 81)); // 设置背景颜色
        g.fillRect(50, 50, 1000, 600); // 绘制游戏区域 , 左右间隔50,上下间隔50
        g.setColor(Color.white); // 设置字体大小为白色
        g.setFont(new Font("微软雅黑", Font.BOLD, 40)); //字体微软雅黑,加粗,字号40
        g.drawString("分数:" + scores, 200, 40);
        g.drawString("长度:" + length, 450, 40);

        if (isFail) { // 判断游戏是否结束;
            g.setColor(Color.red); // 设置字体大小为白色
            g.drawString("游戏结束", 350, 250);
            timer.stop();
        }

        if (!isStart) { //判断游戏是否开始
            g.drawString("按下空格开始游戏", 350, 250);
        }
    }

5.定时器事件

  @Override
    public void actionPerformed(ActionEvent e) {
        moveBody();//移动身体
        // 更新头部
        updateHeader();
        //判断是否装到自己
        isDeathed();
//     更新画布
        repaint();
    }

    private void isDeathed() {
        //        判断是否碰到自己
        for (int i = 1; i < length; i++) {
            if (snakeX[i] == snakeX[0] && snakeY[i] == snakeY[0]) {
                isFail = true;
            }
        }
    }

    private void moveBody() {
        for (int i = length; i > 0; i--) { //除了脑袋都往前移:身体移动
            snakeY[i] = snakeY[i - 1]; //即第i节(后一节)的位置变为(i-1:前一节)节的位置!
            snakeX[i] = snakeX[i - 1];
        }
    }

    private void updateHeader() {
        // 更新头部位置
        if (fx.equals("R")) {
            snakeX[0] = snakeX[0] + 25;
            if (snakeX[0] > 1025) {
                snakeX[0] = 50;
            }
        } else if (fx.equals("L")) {
            snakeX[0] = snakeX[0] - 25;
            if (snakeX[0] < 50) {
                snakeX[0] = 1025;
            }
        } else if (fx.equals("U")) {
            snakeY[0] = snakeY[0] - 25;
            if (snakeY[0] < 50) snakeY[0] = 625;
        } else if (fx.equals("D")) {
            snakeY[0] = snakeY[0] + 25;
            if (snakeY[0] > 625) snakeY[0] = 50;
        }
    }
  1. 键盘监听
  @Override
    public void keyPressed(KeyEvent e) {
//        捕捉按键
        int keyCode = e.getKeyCode();
        performCommand(e, keyCode);
        repaint();
    }

    private void performCommand(KeyEvent e, int keyCode) {
        if (keyCode == e.VK_SPACE) { // 如果按的按键是空格
            if (isFail) {
                init(); // 重开
            } else {
                if (isStart) {
                    timer.stop(); // 暂停
                } else {
                    timer.start(); // 继续
                }
                isStart = !isStart;
            }
        } else {
            if (keyCode == e.VK_UP) {
                fx = "U";
            } else if (keyCode == e.VK_DOWN) {
                fx = "D";
            } else if (keyCode == e.VK_RIGHT) {
                fx = "R";
            } else if (keyCode == e.VK_LEFT) {
                fx = "L";
            }
        }
    }

JavaGUI编程——及贪吃蛇游戏实战_第13张图片

  • 游戏源码

你可能感兴趣的:(JavaSE部分,gui,swing,游戏)