Java--GUI图形用户界面编程(计算器,贪吃蛇)

Java--GUI图形用户界面编程(计算器,贪吃蛇)

@ TOC

GUI图形用户界面编程

1. GUI简介

图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)是指采用图形方式显示的计算机操作用户界面。(百度百科)

核心技术:

  • AWT
  • Swing

缺点:

  • 界面不美观
  • 需要jre环境才能使用

2. AWT(Abstract Window Toolkit)

AWT(Abstract Window Toolkit)抽象窗口工具包,该包提供了一套与本地图形界面进行交互的接口,是Java提供的用来建立和设置Java的图形用户界面的基本工具。 AWT是Java基础类 (JFC)的一部分,为Java程序提供图形用户界面(GUI)的标准API。

2.1 常用组件

AWT中包含窗口(Frame),画板(Panel),标签(Label),按钮(Button)等组件。

2.1.1 窗口组件

2.1.1.1 Frame

通过静态变量设置窗口长windowHeight和宽windowWidth以及窗口弹出的位置(startX,starty),方便整体的编程和修改。

//创建图像界面窗口并设置标题
Frame frame=new Frame("贪吃蛇");
//设置窗口可见性
frame.setVisible(true);
//设置窗口大小
frame.setSize(windowWidth,windowHeight);
//设置窗口背景颜色
frame.setBackground(new Color(68,150, 131));
//设置窗口弹出的初始位置
frame.setLocation(startX,starty);
//设置窗口大小固定
frame.setResizable(false);
//监听关闭窗口事件--如果不添加该事件,无法通过点击窗口的叉号去关闭窗口
frame.addWindowListener(new WindowAdapter() {
    @Override
    public void windowClosing(WindowEvent e) {
        System.exit(0);
});

效果如下:

在这里插入图片描述

2.1.1.2 自定义窗口

通过继承Frame类,自定义窗口

public class TestFrame2 {
    public static void main(String[] args) {
        //展示多个窗口
        for (int i = 0; i < 4; i++) {
            if(i%2==0){
                MyFrame frame=new MyFrame(200,i*100+200,200,200,new Color(i*10,i*30,i*50));
            }else {
                MyFrame frame=new MyFrame(400,i*100+100,200,200,new Color(i*10,i*30,i*50));
class MyFrame extends Frame{
    static int id=0;
    public MyFrame(int x,int y,int w,int h,Color color){
        super("MyFrame"+(++id));
        setVisible(true);
        setBounds(x,y,w,h);
        setBackground(color);
}

效果如下:

在这里插入图片描述

2.1.1.3 窗口监听

设置窗口监听事件,如窗口激活(windowActivated),窗口关闭(windowClosing),窗口停用(windowDeactivated)等。

public class TestWindow {
    public static void main(String[] args) {
        new WindowFrame();
class WindowFrame extends Frame{
    public WindowFrame(){
        setBackground(Color.blue);
        setBounds(100,100,200,200);
        setVisible(true);
//        addWindowListener(new MyWindowListener());
        this.addWindowListener(new WindowAdapter() {
            //关闭窗口
            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("windowClosing");
                System.exit(0);
            //激活窗口
            @Override
            public void windowActivated(WindowEvent e) {
                WindowFrame frame = (WindowFrame) e.getSource();
                frame.setTitle("窗口被激活");
                System.out.println("windowActivated");
}

效果如下: 鼠标未点击窗口外的位置时,窗口处于激活状态, 当鼠标点击窗口外位置时,窗口处于待激活的状态, 再次点击窗口,窗口重新被激活并设置标题为 “窗口被激活”

在这里插入图片描述
在这里插入图片描述

2.1.2 Panel画板

画板是位于窗口内的一个组件,窗口内一般包含一个或多个画板。然后将其他组件添加到画板上,到达最终效果。

Frame frame=new Frame();
//创建面板
Panel panel=new Panel();
//设置布局
frame.setLayout(null);
frame.setBounds(frameX,frameY,frameW,frameH);
frame.setBackground(new Color(0x00281F));
//panel设置坐标,相对于frame
panel.setBounds(panelX,panelY,panelW,panelH);
panel.setBackground(new Color(0x480050));
//窗口添加画板
frame.add(panel);
frame.setVisible(true);
//监听事件,实现关闭窗口 System.exit(0)
//适配器模式:
frame.addWindowListener(new WindowAdapter() {
    //窗口点击关闭时需要做的事
    @Override
    public void windowClosing(WindowEvent e) {
        //结束程序
        System.exit(0);
});

效果如下:

在这里插入图片描述

2.2 布局

2.2.1 流式布局FlowLayout

流式布局:从左到右依次排列组件

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");
        //设置流式布局
        frame.setLayout(new FlowLayout());
//        frame.setLayout(new FlowLayout(FlowLayout.LEFT));
//        frame.setLayout(new FlowLayout(FlowLayout.RIGHT));
        frame.setBounds(100,100,200,200);
        frame.setVisible(true);
        frame.add(button1);
        frame.add(button2);
        frame.add(button3);
    }

效果如下:

在这里插入图片描述

2.2.2 东西南北中布局BorderLayout

东西南北中布局:见名知意,分为东西南北中五个位置,其中中间的位置最大,东西南北都只有很小的空间。

public class TestBorderLayout {
    public static void main(String[] args) {
        Frame frame=new Frame("TestBorderLayout");
        Button east=new Button("east");
        Button west=new Button("west");
        Button south=new Button("south");
        Button north=new Button("north");
        Button center=new Button("center");
        frame.add(east,BorderLayout.EAST);
        frame.add(west,BorderLayout.WEST);
        frame.add(south,BorderLayout.SOUTH);
        frame.add(north,BorderLayout.NORTH);
        frame.add(center,BorderLayout.CENTER);
        frame.setBounds(100,100,500,500);
        frame.setVisible(true);
}

效果如下:

在这里插入图片描述

2.2.3 网格布局GridLayout

网格布局:设置行和列的数量划分网格

public class TestGridLayout {
    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");
        frame.setLayout(new GridLayout(3,2));
        frame.setBounds(100,100,500,500);
        frame.setVisible(true);
        frame.add(button1);
        frame.add(button2);
        frame.add(button3);
        frame.add(button4);
        frame.add(button5);
        frame.add(button6);
}

效果如下:

在这里插入图片描述

2.2.4 布局案例

利用上述3种布局方法,实现如下效果

在这里插入图片描述
public class LayoutDemo {
    public static void main(String[] args) {
        Frame frame=new Frame("测试布局");
        frame.setBounds(300,300,400,300);
        frame.setLayout(new GridLayout(2,1));
        frame.setVisible(true);
        Panel panel1=new Panel(new BorderLayout());
        panel1.add(new Button("button1"),BorderLayout.WEST);
        panel1.add(new Button("button2"),BorderLayout.EAST);
        Panel panel3=new Panel(new GridLayout(2,1));
        panel1.add(panel3,BorderLayout.CENTER);
        panel3.add(new Button("button3"));
        panel3.add(new Button("button4"));
        panel1.add(panel3);
        Panel panel2=new Panel(new BorderLayout());
        panel2.add(new Button("button5"),BorderLayout.WEST);
        panel2.add(new Button("button6"),BorderLayout.EAST);
        Panel panel4=new Panel(new GridLayout(2,2));
        for (int i = 0; i < 4; i++) {
            panel4.add(new Button("button"+(i+7)));
        panel2.add(panel4);
        frame.add(panel1);
        frame.add(panel2);
        //监听关闭窗口事件
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
}

效果如下:

在这里插入图片描述

2.3 事件监听

2.3.1 窗口监听

如2.1.1.3所示,窗口监听包括窗口关闭,激活等。

2.3.2 按钮事件监听

2.3.2.1 一个按钮一个监听事件

实现目标:点击按钮在控制台输出aaa

public class TestActionEvent {
    public static void main(String[] args) {
        Frame frame=new Frame();
        frame.setBounds(100,100,200,300);
        Button button=new Button();
        frame.add(button);
        //构造一个ActionListener,去满足addActionListener()监听事件的需求
        MyActionListener listener=new MyActionListener();
        button.addActionListener(listener);
        frame.pack();
        frame.setVisible(true);
        //监听关闭窗口事件
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
class MyActionListener implements ActionListener{
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("aaa");
}

2.3.2.2 多个按钮共享一个监听事件

实现目标:运行程序,窗口中间使用xx年xx月xx日 HH:mm:ss格式显示日期时间。点击change按钮修改日期时间显示格式xx-xx-xx HH:mm:ss,点击refresh按钮再次将日期时间显示格式修改为xx年xx月xx日 HH:mm:ss。

public class TestActionEvent2 {
    public static void main(String[] args) {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        Frame frame=new Frame();
        frame.setBounds(100,100,300,500);
        //标签:显示时间
        Label label=new Label();
        label.setPreferredSize(new Dimension(400,300));
        label.setAlignment(Label.CENTER);
        label.setFont(new Font("宋体",Font.PLAIN,20));
        label.setBackground(new Color(192,192,192));
        label.setText(sdf.format(new Date()));
//        System.out.println(String.valueOf(new Date(System.currentTimeMillis())));
        //刷新按钮:用来刷新标签显示的时间
        MyMonitor monitor=new MyMonitor(label);
        Button button1=new Button("refresh");
        button1.setPreferredSize(new Dimension(200,300));
        button1.setFont(new Font("宋体",Font.PLAIN,24));
        button1.setActionCommand("refresh");
        button1.addActionListener(monitor);
        //格式转换按钮:用来转换标签时间显示的格式
        Button button2=new Button("change");
        button2.setPreferredSize(new Dimension(200,300));
        button2.setFont(new Font("宋体",Font.PLAIN,24));
        button2.setActionCommand("change");
        button2.addActionListener(monitor);
        frame.add(button1,BorderLayout.EAST);
        frame.add(button2,BorderLayout.WEST);
        frame.add(label,BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
class MyMonitor implements ActionListener{
    private Label label;
    public MyMonitor(Label label) {
        this.label = label;
    @Override
    public void actionPerformed(ActionEvent e) {
        try {
            if(e.getActionCommand().equals("refresh")){
                SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                label.setText(sdf.format(new Date()));
            }else if(e.getActionCommand().equals("change")){
                SimpleDateFormat sdf1=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                Date date=sdf1.parse(label.getText());
                label.setText(date.toLocaleString());
        } catch (ParseException parseException) {
            parseException.printStackTrace();
}

效果如下:

在这里插入图片描述
在这里插入图片描述

2.3.3 文本域事件监听

实现目标:在文本域中输入文字,点击回车键,将输入的文字打印到控制台并清空文本域。

public class TestInputText {
    public static void main(String[] args) {
        new MyFrame1();
class MyFrame1 extends Frame {
    public MyFrame1(){
        setBounds(300,300,800,300);
        TextField textField=new TextField();
        add(textField);
        //监听文本框输入的数字
        MyActionListener2 listener2=new MyActionListener2();
        //按下enter就会出发事件
        textField.addActionListener(listener2);
        //设置替换编码
//        textField.setEchoChar('*');
        setVisible(true);
        //监听关闭窗口事件
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
class MyActionListener2 implements ActionListener{
    @Override
    public void actionPerformed(ActionEvent e) {
        TextField field=(TextField) e.getSource();//获取一些二资源,返回一个对象
        System.out.println(field.getText());//获得输入框的文本
        field.setText("");  //清空输入框
}

2.3.4 键盘事件监听

实现目标:识别键盘上按下的是不是方向键中的上键,如果是在控制台中打印出”你按的是上键“。

public class TestKeyListener {
    public static void main(String[] args) {
        new KeyFrame();
class KeyFrame extends Frame{
    public KeyFrame(){
        setBounds(1,2,300,400);
        setVisible(true);
        this.addKeyListener(new KeyAdapter() {
            //键盘按下
            @Override
            public void keyPressed(KeyEvent e) {
                //获取当前按下的是那个键
                int keyCode=e.getKeyCode();
                if(keyCode==KeyEvent.VK_UP){
                    System.out.println("你按的是上键");
}

2.3.5 鼠标监听事件

实现目标:识别鼠标在窗口的位置,点击鼠标时在窗口的该位置留下一个点。

public class TestMouseListener {
    public static void main(String[] args) {
        new MyFrame3("画图");
class MyFrame3 extends Frame{
    ArrayList points;
    public MyFrame3(String title){
        super(title);
        setBounds(200,200,400,300);
        //创建一个list存放鼠标点击的点
        points=new ArrayList<>();
        //鼠标监听器,
        this.addMouseListener(new MyMouseListener());
        setVisible(true);
        //点击关闭按钮结束程序
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
    @Override
    public void paint(Graphics g) {
        //画画,监听鼠标事件
        Iterator iterator=points.iterator();
        while (iterator.hasNext()){
            Point point= (Point) iterator.next();
            g.setColor(Color.blue);
            g.fillOval(point.x,point.y,5,5);
    //添加一个点到窗口
    public void addPaint(Point point){
        points.add(point);
    //适配器模式
    private class MyMouseListener extends MouseAdapter{
        //鼠标模式:按下,弹起,按住不放
        @Override
        public void mousePressed(MouseEvent e) {
            MyFrame3 myFrame=(MyFrame3) e.getSource();
            myFrame.addPaint(new Point(e.getX(),e.getY()));
            //每次点击鼠标都需要重画一遍
            myFrame.repaint();
}

2.4 小结案例--计算器

package com.yang.learning.GUILearning.AWT;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
 * 模拟计算器
 * @Author yang97
 * @Date 2022/9/29 16:36
public class TestCalc {
    public static void main(String[] args) {
        new Calculator().loadFrame();
//计算器类
class Calculator extends Frame{
    TextField textField;
    Panel panel,panel1,panel2,panel3;
    MyButton button1;
    public void loadFrame(){
        setTitle("计算器");
        setBounds(500,500,600,400);
        //文本框
        textField=new TextField();
        textField.setPreferredSize(new Dimension(600,80));
        textField.setBackground(new Color(0x30C1D2F0, true));
        textField.setFont(new Font("宋体",Font.PLAIN,24));
        //按钮0~9,+,-,*,/,=共15个按钮
        //画板,放所有按钮
        panel=new Panel(new GridLayout(1,2));
        panel.setBounds(0,200,600,600);
        //放1-9
        panel1=new Panel(new GridLayout(3,3));
        for (int i = 9; i > 0; i--) {
            panel1.add(new MyButton(String.valueOf(i),this));
        //放+,-,*,/,0,=,清空键C
        panel2=new Panel(new GridLayout(3,2));
        panel2.add(new MyButton("+",this));
        panel2.add(new MyButton("-",this));
        panel2.add(new MyButton("*",this));
        panel2.add(new MyButton("/",this));
        panel2.add(new MyButton("0",this));
        panel2.add(new MyButton("=",this));
        //放panel2和清空键C
        panel3=new Panel(new BorderLayout());
        button1=new MyButton("C",this);
        button1.setPreferredSize(new Dimension(240,60));
        panel3.add(button1,BorderLayout.NORTH);
        panel3.add(panel2);
        panel.add(panel1);
        panel.add(panel3);
        add(textField,BorderLayout.NORTH);
        add(panel);
        setVisible(true);
        //点击关闭按钮结束程序
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
//按钮类,修改按钮的字体和背景,添加不同的监听器
class MyButton extends Button{
    public MyButton(String label,Calculator calculator){
        super(label);
        setFont(new Font("宋体",Font.PLAIN,24));
        setBackground(new Color(192,192,192));
        setActionCommand(label);
        if(label.equals("=")){
            addActionListener(new MyCalcListener(calculator));
        }else {
            addActionListener(new InputListener(calculator));
//监听器类--监听输入
class InputListener implements ActionListener{
    private Calculator calculator;
    public InputListener(Calculator calculator){
        this.calculator=calculator;
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getActionCommand().equals("C")){
            calculator.textField.setText("");
        }else {
            calculator.textField.setText(calculator.textField.getText()+e.getActionCommand());
//监听器类--监听计算
class MyCalcListener implements ActionListener{
    private Calculator calculator;
    public MyCalcListener(Calculator calculator) {
        this.calculator = calculator;
    @Override
    public void actionPerformed(ActionEvent e) {
        String str=calculator.textField.getText();
        //获取两个操作数
        String[] array=str.split("\\+|\\/|\\*|\\-");
        //获取操作符
        String op= str.split(array[0])[1].split(array[1])[0];
        //类型转换
        int n1=Integer.parseInt(array[0]);
        int n2=Integer.parseInt(array[1]);
        if(op.equals("+")){
            calculator.textField.setText(""+(n1+n2));
        }else if(op.equals("-")){
            calculator.textField.setText(""+(n1-n2));
        }else if(op.equals("*")){
            calculator.textField.setText(""+(n1*n2));
        }else if(op.equals("/")){
            if(n2==0){
                calculator.textField.setText("除0错误,一秒后清空输入框!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                calculator.textField.setText("");
            }else {
                calculator.textField.setText(""+(n1/n2));
}

效果如下:

在这里插入图片描述

3. Swing

Swing是一个用于开发Java应用程序用户界面的开发工具包。Swing具有丰富、灵活的功能和模块化组件可用来创建更优美的用户界面。

3.1 JFrame窗口

相比于Frame,JFrame不需要监听窗口关闭事件,只需要设置默认关闭i操作即可。 Frame一般将组件放置于Panel中,JFrame一般将组件放置于container中

//JFrame
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//Frame
//监听关闭窗口事件
frame.addWindowListener(new WindowAdapter() {
    @Override
    public void windowClosing(WindowEvent e) {
        System.exit(0);
public class TestJFrame2 {
    public static void main(String[] args) {
        new MyJFrame().init();
class MyJFrame extends JFrame{
    public void init(){
        setBounds(100,200,300,400);
        setVisible(true);
        setBackground(Color.gray);
        //设置默认关闭操作
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        JLabel label=new JLabel("欢迎使用Swing");
        //水平对齐,居中
        label.setHorizontalAlignment(SwingConstants.CENTER);
        //获得一个容器
        Container container=this.getContentPane();
        container.setBackground(Color.ORANGE);
        this.add(label);
}

3.2 JPanel

public class JPanelDemo extends JFrame {
    public JPanelDemo() {
        Container container=getContentPane();
        container.setLayout(new GridLayout(2,1,10,10));
        JPanel panel1=new JPanel(new GridLayout(1,3));
        JPanel panel2=new JPanel(new GridLayout(3,1));
        JPanel panel3=new JPanel(new GridLayout(2,3));
        JPanel panel4=new JPanel(new GridLayout(1,3));
        panel1.add(new JButton("1"));
        panel1.add(new JButton("2"));
        panel1.add(new JButton("3"));
        panel2.add(new JButton("1"));
        panel2.add(new JButton("2"));
        panel2.add(new JButton("3"));
        panel3.add(new JButton("1"));
        panel3.add(new JButton("1"));
        panel3.add(new JButton("1"));
        panel3.add(new JButton("2"));
        panel3.add(new JButton("2"));
        panel3.add(new JButton("2"));
        panel4.add(new JButton("1"));
        panel4.add(new JButton("2"));
        panel4.add(new JButton("3"));
        container.add(panel1);
        container.add(panel2);
        container.add(panel3);
        container.add(panel4);
        this.setVisible(true);
        this.setBounds(100,100,400,400);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    public static void main(String[] args) {
        new JPanelDemo();
}

效果如下:

在这里插入图片描述

3.3 按钮(图片按钮,单选按钮,多选按钮)

public class JButtonDemo extends JFrame {
    public JButtonDemo(){
        Container container=getContentPane();
        URL res=JButtonDemo.class.getResource("1.jpg");
        Icon icon=new ImageIcon(res);
        //图标按钮,把图标放在按钮上
        JButton button=new JButton();
        button.setIcon(icon);
        button.setToolTipText("图片按钮");
        //单选框按钮JRadioButton
        JRadioButton button1=new JRadioButton("button1");
        JRadioButton button2=new JRadioButton("button2");
        JRadioButton button3=new JRadioButton("button3");
        //需要将多个按钮分到一个组中
        ButtonGroup group=new ButtonGroup();
        group.add(button1);
        group.add(button2);
        group.add(button3);
        //多选框
        JCheckBox checkBox1=new JCheckBox("checkBox1");
        JCheckBox checkBox2=new JCheckBox("checkBox2");
        container.setLayout(new FlowLayout());
        container.add(button);
        container.add(button1);
        container.add(button2);
        container.add(button3);
        container.add(checkBox1);
        container.add(checkBox2);
        this.setVisible(true);
        this.setBounds(100,100,400,400);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    public static void main(String[] args) {
        new JButtonDemo();
}

效果如下:

在这里插入图片描述

3.4 文本域,滚动面板

public class JScrollDemo extends JFrame {
    public JScrollDemo() {
        Container container=this.getContentPane();
        //文本域
        JTextArea textArea=new JTextArea(20,50);
        textArea.setText("欢迎学习java");
        //Scroll面板
        JScrollPane scrollPane=new JScrollPane(textArea);
        container.add(scrollPane);
        this.setVisible(true);
        this.setBounds(100,100,400,400);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    public static void main(String[] args) {
        new JScrollDemo();
}

效果如下:

在这里插入图片描述

3.5 下拉框和列表

public class ComboBoxDemo1 extends JFrame{
    public ComboBoxDemo1() {
        Container container=getContentPane();
        JComboBox comboBox=new JComboBox();
        comboBox.addItem("null");
        comboBox.addItem("过去");
        comboBox.addItem("现在");
        comboBox.addItem("未来");
        container.add(comboBox);
        this.setVisible(true);
        this.setBounds(100,100,400,70);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    public static void main(String[] args) {
        new ComboBoxDemo1();
public class ComboBoxDemo2 extends JFrame{
    public ComboBoxDemo2() {
        Container container=getContentPane();
        //生成列表内容
        String[] content={"天","生","我","材","必","有","用",",","千","金","散","去","还","复","来"};
        JList jList=new JList(content);
        container.add(jList);
        this.setVisible(true);
        this.setBounds(100,100,400,400);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    public static void main(String[] args) {
        new ComboBoxDemo2();
}

效果如下:

在这里插入图片描述

3.6 弹窗

public class DialogDemo extends JFrame {
    public DialogDemo(){
        this.setVisible(true);
        this.setBounds(100,200,300,400);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //容器,用来放组件
        Container container=this.getContentPane();
        container.setLayout(null);  //绝对布局
        JButton button=new JButton("点击弹出一个对话框");
        button.setBounds(30,30,200,50);
        //按钮监听事件,点击按钮弹出一个对话框
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new MyDialog();
        this.add(button);
    public static void main(String[] args) {
        new DialogDemo();
class MyDialog extends JDialog{
    public MyDialog() {
        this.setVisible(true);
        this.setBounds(100,100,300,300);
        this.setTitle("欢迎查看弹窗");
}

效果如下:

在这里插入图片描述

4. 小结案例--贪吃蛇

启动游戏界面

package com.yang.learning.GUILearning.SnakeGluttony;
import javax.swing.*;
 * 启动游戏界面
 * D0D0D0
 * @Author yang97
 * @Date 2022/10/20 19:34
public class StartGame {
    public static void main(String[] args) {
        JFrame frame=new JFrame();
        frame.setBounds(10,10,900,720);
        frame.setTitle("贪吃蛇");
//        frame.setIconImage();
        //游戏界面
        frame.add(new GamePanel());
        frame.setVisible(true);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}

资源界面

package com.yang.learning.GUILearning.SnakeGluttony;
import javax.swing.*;
import java.net.URL;
 * @Author yang97
 * @Date 2022/10/20 20:09
public class Data {
    public static URL upURL=Data.class.getResource("statics/up.png");
    public static URL downURL=Data.class.getResource("statics/down.png");
    public static URL leftURL=Data.class.getResource("statics/left.png");
    public static URL rightURL=Data.class.getResource("statics/right.png");
    public static ImageIcon up=new ImageIcon(upURL);
    public static ImageIcon down=new ImageIcon(downURL);
    public static ImageIcon left=new ImageIcon(leftURL);
    public static ImageIcon right=new ImageIcon(rightURL);
    public static URL headerURL=Data.class.getResource("statics/header.png");
    public static URL bodyURL=Data.class.getResource("statics/body.png");
    public static URL foodURL=Data.class.getResource("statics/food.png");
    public static ImageIcon header=new ImageIcon(headerURL);
    public static ImageIcon body=new ImageIcon(bodyURL);
    public static ImageIcon food=new ImageIcon(foodURL);
}

游戏面板

package com.yang.learning.GUILearning.SnakeGluttony;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
 * @Author yang97
 * @Date 2022/10/20 19:38
public class GamePanel extends JPanel implements KeyListener, ActionListener {
    //蛇的属性
    int length; //蛇的长度
    int[] snakeX=new int[600];  //蛇的X坐标
    int[] snakeY=new int[600];  //蛇的Y坐标
    String fx;  //初始时蛇头朝向的方向
    //食物的坐标
    int foodX;
    int foodY;
    Random random=new Random();     //随机种子
    //游戏当前状态属性
    boolean isStart=false;  //默认是不开始
    //定义游戏状态
    boolean isFail=false;
    int score;
    //定时器,以毫秒为单位
    Timer timer=new Timer(100,this);    //100毫秒一次
    public GamePanel() {
        init();
        //获得焦点和键盘事件
        this.setFocusable(true);    //获得焦点事件
        this.addKeyListener(this);  //获得键盘监听事件
        timer.start();  //游戏一开始就启动定时器
    public void init(){
        //初始化小蛇
        length=3;   //初始长度为3
        snakeX[0]=100;  snakeY[0]=100;  //脑袋的坐标
        snakeX[1]=75;  snakeY[1]=100;  //第一个身体的坐标
        snakeX[2]=50;  snakeY[2]=100;  //第二个身体的坐标
        fx="R";
        //初始化食物,随机分布在画布上
        foodX=25+25*random.nextInt(850/25);
        foodY=75+25*random.nextInt(650/25);
        //初始成绩
        score=0;
    //绘制面板,绘制游戏界面
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);    //清屏
        //绘制静态面板
        this.setBackground(new Color(73, 72, 72));
        //画头部标题栏
        Data.header.paintIcon(this,g,25,11);
        //画成绩
        g.setColor(Color.BLACK);
        g.setFont(new Font("楷体",Font.BOLD,30));
        g.drawString("长度:"+length,550,50);
        g.drawString("分数:"+score,700,50);
        //画默认游戏界面
        g.setColor(Color.gray);
        g.fillRect(25,75,850,600);
        //画初始小蛇,初始蛇头向右
        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]);
        //绘制食物
        Data.food.paintIcon(this,g,foodX,foodY);
        //游戏状态
        if(isStart==false){
            g.setColor(Color.WHITE);
            g.setFont(new Font("楷体",Font.BOLD,40));
            g.drawString("按下空格开始游戏",300,300);
        if(isFail){
            g.setColor(Color.RED);
            g.setFont(new Font("楷体",Font.BOLD,40));
            g.drawString("游戏失败,按下空格重新开始游戏",150,300);
    //键盘监听事件===通过键盘事件刷新
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode=e.getKeyCode();
        //开始暂停游戏
        if(keyCode==KeyEvent.VK_SPACE){
            if(isFail){
                isFail=false;
                init();
            }else {
                isStart=!isStart;
            repaint();
        //小蛇移动
        if(keyCode==KeyEvent.VK_UP){
            fx="U";
        }else if(keyCode==KeyEvent.VK_DOWN){
            fx="D";
        }else if(keyCode==KeyEvent.VK_LEFT){
            fx="L";
        }else if(keyCode==KeyEvent.VK_RIGHT){
            fx="R";
    //事件监听===通过固定事件刷新
    @Override
    public void actionPerformed(ActionEvent e) {
        if(isStart && isFail==false){    //如果游戏是开始状态,小蛇移动
            //吃食物
            if(snakeX[0]==foodX&&snakeY[0]==foodY){
                length++;   //长度加一
                score+=10;    //分数加10
                //再次随机刷新食物
                foodX=25+25*random.nextInt(34);
                foodY=75+25*random.nextInt(24);
            //小蛇移动
            for(int i =length-1;i>0;i--){
                snakeX[i]=snakeX[i-1];  //向前移动一节
                snakeY[i]=snakeY[i-1];  //向前移动一节
            if(fx.equals("R")){
                snakeX[0]=snakeX[0]+25;
                //边界判断,超过边界后从另一边回来
                if(snakeX[0]>850){ snakeX[0]=25; }
            }else if(fx.equals("L")){
                snakeX[0]=snakeX[0]-25;
                //边界判断,超过边界后从另一边回来
                if(snakeX[0]<25){ snakeX[0]=850; }
            }else if(fx.equals("U")){
                snakeY[0]=snakeY[0]-25;
                //边界判断,超过边界后从另一边回来
                if(snakeY[0]<75){ snakeY[0]=650; }
            }else if(fx.equals("D")){
                snakeY[0]=snakeY[0]+25;
                //边界判断,超过边界后从另一边回来
                if(snakeY[0]>650){ snakeY[0]=75; }
            //失败判定,撞到自己
            for (int i = 1; i < length; i++) {
                if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
                    isFail=true;
            repaint();  //重画页面
        timer.start();
    @Override